Skip to content
This repository
Browse code

First import from Subversion

  • Loading branch information...
commit b5788a43b0d9714ed2e53dfa138d41c22ea4649c 0 parents
Geoffrey Grosenbach authored

Showing 103 changed files with 5,282 additions and 0 deletions. Show diff stats Hide diff stats

  1. +2 0  .gitignore
  2. +89 0 CHANGELOG
  3. +21 0 MIT-LICENSE
  4. +72 0 Manifest.txt
  5. +15 0 README.txt
  6. +52 0 Rakefile
  7. BIN  artwork/city_scene.psd
  8. 0  artwork/graphs/Backup of Untitled.key/.typeAttributes.dict
  9. +1 0  artwork/graphs/Backup of Untitled.key/Contents/PkgInfo
  10. BIN  artwork/graphs/Backup of Untitled.key/index.apxl.gz
  11. BIN  artwork/graphs/Backup of Untitled.key/thumbs/st0.tiff
  12. BIN  artwork/graphs/Backup of Untitled.key/thumbs/st1.tiff
  13. BIN  artwork/graphs/Backup of Untitled.key/thumbs/st2.tiff
  14. BIN  artwork/graphs/Backup of Untitled.key/thumbs/st3.tiff
  15. 0  artwork/graphs/Untitled.key/.typeAttributes.dict
  16. +1 0  artwork/graphs/Untitled.key/Contents/PkgInfo
  17. BIN  artwork/graphs/Untitled.key/index.apxl.gz
  18. BIN  artwork/graphs/Untitled.key/thumbs/st0.tiff
  19. BIN  artwork/graphs/Untitled.key/thumbs/st1.tiff
  20. BIN  artwork/graphs/Untitled.key/thumbs/st2.tiff
  21. BIN  artwork/graphs/Untitled.key/thumbs/st3.tiff
  22. BIN  artwork/graphs/samples.001.png
  23. BIN  artwork/graphs/samples.002.png
  24. BIN  artwork/graphs/samples.003.png
  25. BIN  artwork/graphs/samples.004.png
  26. +36 0 artwork/gruff_controller.rb
  27. +32 0 artwork/gruffs_helper.rb
  28. +15 0 artwork/install_rmagick.sh
  29. BIN  artwork/mrplot-0.0.1.tar.gz
  30. BIN  artwork/plastik-blue.psd
  31. BIN  artwork/plastik-green.psd
  32. BIN  artwork/plastik-red.psd
  33. BIN  artwork/plastik-template.psd
  34. BIN  artwork/plastik.png
  35. BIN  assets/bubble.png
  36. BIN  assets/city_scene/background/0000.png
  37. BIN  assets/city_scene/background/0600.png
  38. BIN  assets/city_scene/background/2000.png
  39. BIN  assets/city_scene/clouds/cloudy.png
  40. BIN  assets/city_scene/clouds/partly_cloudy.png
  41. BIN  assets/city_scene/clouds/stormy.png
  42. BIN  assets/city_scene/grass/default.png
  43. BIN  assets/city_scene/haze/true.png
  44. BIN  assets/city_scene/number_sample/1.png
  45. BIN  assets/city_scene/number_sample/2.png
  46. BIN  assets/city_scene/number_sample/default.png
  47. BIN  assets/city_scene/sky/0000.png
  48. BIN  assets/city_scene/sky/0200.png
  49. BIN  assets/city_scene/sky/0400.png
  50. BIN  assets/city_scene/sky/0600.png
  51. BIN  assets/city_scene/sky/0800.png
  52. BIN  assets/city_scene/sky/1000.png
  53. BIN  assets/city_scene/sky/1200.png
  54. BIN  assets/city_scene/sky/1400.png
  55. BIN  assets/city_scene/sky/1500.png
  56. BIN  assets/city_scene/sky/1700.png
  57. BIN  assets/city_scene/sky/2000.png
  58. BIN  assets/pc306715.jpg
  59. BIN  assets/plastik/blue.png
  60. BIN  assets/plastik/green.png
  61. BIN  assets/plastik/red.png
  62. +26 0 lib/gruff.rb
  63. +27 0 lib/gruff/accumulator_bar.rb
  64. +58 0 lib/gruff/area.rb
  65. +84 0 lib/gruff/bar.rb
  66. +46 0 lib/gruff/bar_conversion.rb
  67. +1,070 0 lib/gruff/base.rb
  68. +109 0 lib/gruff/bullet.rb
  69. +39 0 lib/gruff/deprecated.rb
  70. +105 0 lib/gruff/line.rb
  71. +32 0 lib/gruff/mini/bar.rb
  72. +77 0 lib/gruff/mini/legend.rb
  73. +36 0 lib/gruff/mini/pie.rb
  74. +35 0 lib/gruff/mini/side_bar.rb
  75. +142 0 lib/gruff/net.rb
  76. +100 0 lib/gruff/photo_bar.rb
  77. +124 0 lib/gruff/pie.rb
  78. +209 0 lib/gruff/scene.rb
  79. +114 0 lib/gruff/side_bar.rb
  80. +73 0 lib/gruff/side_stacked_bar.rb
  81. +130 0 lib/gruff/spider.rb
  82. +66 0 lib/gruff/stacked_area.rb
  83. +53 0 lib/gruff/stacked_bar.rb
  84. +23 0 lib/gruff/stacked_mixin.rb
  85. +119 0 test/gruff_test_case.rb
  86. +50 0 test/test_accumulator_bar.rb
  87. +134 0 test/test_area.rb
  88. +284 0 test/test_bar.rb
  89. +8 0 test/test_base.rb
  90. +26 0 test/test_bullet.rb
  91. +71 0 test/test_legend.rb
  92. +493 0 test/test_line.rb
  93. +32 0 test/test_mini_bar.rb
  94. +20 0 test/test_mini_pie.rb
  95. +37 0 test/test_mini_side_bar.rb
  96. +230 0 test/test_net.rb
  97. +41 0 test/test_photo.rb
  98. +154 0 test/test_pie.rb
  99. +100 0 test/test_scene.rb
  100. +12 0 test/test_side_bar.rb
  101. +89 0 test/test_sidestacked_bar.rb
  102. +216 0 test/test_spider.rb
  103. +52 0 test/test_stacked_bar.rb
2  .gitignore
... ... @@ -0,0 +1,2 @@
  1 +.DS_Store
  2 +test/output/*
89 CHANGELOG
... ... @@ -0,0 +1,89 @@
  1 +== 0.3.0
  2 +
  3 +* ???
  4 +
  5 +== 0.2.9
  6 +
  7 +* Patch to make SideBar accurate instead of stacked [Marik]
  8 +* Will be extracting net, pie, stacked, and side-stacked to separate gem
  9 + in next release.
  10 +
  11 +== 0.2.8
  12 +
  13 +* New accumulator bar graph (experimental)
  14 +* Better mini graphs
  15 +* Bug fixes
  16 +
  17 +== 0.2.7
  18 +
  19 +* Regenerated Manifest.txt
  20 +* Added scene sample to package
  21 +* Added mini side_bar (EXPERIMENTAL)
  22 +* Added @zero_degree option to Gruff::Pie so first slice can start somewhere other than 3 o'clock
  23 +* Increased size of numbers in Gruff::Mini::Pie
  24 +* Added legend_box_size accessor
  25 +
  26 +== 0.2.6
  27 +
  28 +* Fixed missing side_bar.rb in Manifest.txt
  29 +
  30 +== 0.2.5
  31 +
  32 +* New mini graph types (Experimental)
  33 +* Marker lines can be different color than text labels
  34 +* Theme definition cleanup
  35 +
  36 +== 0.2.4
  37 +
  38 +* Added option to hide line numbers
  39 +* Fixed code that was causing warnings
  40 +
  41 +== 0.2.3
  42 +
  43 +* Cleaned up measurements so the graph expands to fill the available space
  44 +* Added x-axis and y-axis label options
  45 +
  46 +== 0.1.2
  47 +
  48 +* minimum_value and maximum_value can be set after data() to manually scale the graph
  49 +* Fixed infinite loop bug when values are all equal
  50 +* Added experimental net and spider graphs
  51 +* Added non-linear scene graph for a simple interface to complex layered graphs
  52 +* Initial refactoring of tests
  53 +* A host of other bug fixes
  54 +
  55 +== 0.0.8
  56 +
  57 +* NEW Sidestacked Bar Graphs. [Alun Eyre]
  58 +* baseline_value larger than data will now show correctly. [Mike Perham]
  59 +* hide_dots and hide_lines are now options for line graphs.
  60 +
  61 +== 0.0.6
  62 +
  63 +* Fixed hang when no data is passed.
  64 +
  65 +== 0.0.4
  66 +
  67 +* Added bar graphs
  68 +* Added area graphs
  69 +* Added pie graphs
  70 +* Added render_image_background for using images as background on a theme
  71 +* Fixed small size legend centering issue
  72 +* Added initial line marker rounding to significant digits (Christian Winkler)
  73 +* Line graphs line width is scaled with number of points being drawn (Christian Winkler)
  74 +
  75 +== 0.0.3
  76 +
  77 +* Added option to draw line graphs without the lines (points only), thanks to Eric Hodel
  78 +* Removed font-minimum check so graphs look better at 300px width
  79 +
  80 +== 0.0.2
  81 +
  82 +* Fixed to_blob (thanks to Carlos Villela)
  83 +* Added bar graphs (initial functionality...will be enhanced)
  84 +* Removed rendered test output from gem
  85 +
  86 +== 0.0.1
  87 +
  88 +* Initial release.
  89 +* Line graphs only. Other graph styles coming soon.
21 MIT-LICENSE
... ... @@ -0,0 +1,21 @@
  1 +Copyright (c) 2005 Geoffrey Grosenbach boss@topfunky.com
  2 +
  3 +Permission is hereby granted, free of charge, to any person obtaining
  4 +a copy of this software and associated documentation files (the
  5 +"Software"), to deal in the Software without restriction, including
  6 +without limitation the rights to use, copy, modify, merge, publish,
  7 +distribute, sublicense, and/or sell copies of the Software, and to
  8 +permit persons to whom the Software is furnished to do so, subject to
  9 +the following conditions:
  10 +
  11 +The above copyright notice and this permission notice shall be
  12 +included in all copies or substantial portions of the Software.
  13 +
  14 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  17 +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  18 +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  19 +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  20 +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21 +
72 Manifest.txt
... ... @@ -0,0 +1,72 @@
  1 +CHANGELOG
  2 +MIT-LICENSE
  3 +Manifest.txt
  4 +README.txt
  5 +Rakefile
  6 +assets/bubble.png
  7 +assets/city_scene/background/0000.png
  8 +assets/city_scene/background/0600.png
  9 +assets/city_scene/background/2000.png
  10 +assets/city_scene/clouds/cloudy.png
  11 +assets/city_scene/clouds/partly_cloudy.png
  12 +assets/city_scene/clouds/stormy.png
  13 +assets/city_scene/grass/default.png
  14 +assets/city_scene/haze/true.png
  15 +assets/city_scene/number_sample/1.png
  16 +assets/city_scene/number_sample/2.png
  17 +assets/city_scene/number_sample/default.png
  18 +assets/city_scene/sky/0000.png
  19 +assets/city_scene/sky/0200.png
  20 +assets/city_scene/sky/0400.png
  21 +assets/city_scene/sky/0600.png
  22 +assets/city_scene/sky/0800.png
  23 +assets/city_scene/sky/1000.png
  24 +assets/city_scene/sky/1200.png
  25 +assets/city_scene/sky/1400.png
  26 +assets/city_scene/sky/1500.png
  27 +assets/city_scene/sky/1700.png
  28 +assets/city_scene/sky/2000.png
  29 +assets/pc306715.jpg
  30 +assets/plastik/blue.png
  31 +assets/plastik/green.png
  32 +assets/plastik/red.png
  33 +lib/gruff.rb
  34 +lib/gruff/accumulator_bar.rb
  35 +lib/gruff/area.rb
  36 +lib/gruff/bar.rb
  37 +lib/gruff/bar_conversion.rb
  38 +lib/gruff/base.rb
  39 +lib/gruff/deprecated.rb
  40 +lib/gruff/line.rb
  41 +lib/gruff/mini/bar.rb
  42 +lib/gruff/mini/legend.rb
  43 +lib/gruff/mini/pie.rb
  44 +lib/gruff/mini/side_bar.rb
  45 +lib/gruff/net.rb
  46 +lib/gruff/photo_bar.rb
  47 +lib/gruff/pie.rb
  48 +lib/gruff/scene.rb
  49 +lib/gruff/side_bar.rb
  50 +lib/gruff/side_stacked_bar.rb
  51 +lib/gruff/spider.rb
  52 +lib/gruff/stacked_area.rb
  53 +lib/gruff/stacked_bar.rb
  54 +lib/gruff/stacked_mixin.rb
  55 +test/gruff_test_case.rb
  56 +test/test_accumulator_bar.rb
  57 +test/test_area.rb
  58 +test/test_bar.rb
  59 +test/test_base.rb
  60 +test/test_legend.rb
  61 +test/test_line.rb
  62 +test/test_mini_bar.rb
  63 +test/test_mini_pie.rb
  64 +test/test_mini_side_bar.rb
  65 +test/test_net.rb
  66 +test/test_photo.rb
  67 +test/test_pie.rb
  68 +test/test_scene.rb
  69 +test/test_side_bar.rb
  70 +test/test_sidestacked_bar.rb
  71 +test/test_spider.rb
  72 +test/test_stacked_bar.rb
15 README.txt
... ... @@ -0,0 +1,15 @@
  1 +== Gruff Graphs
  2 +
  3 +A library for making beautiful graphs.
  4 +
  5 +See samples at http://nubyonrails.com/pages/gruff
  6 +
  7 +See the test suite in test/line_test.rb for examples.
  8 +
  9 +== Documentation
  10 +
  11 +Most of the documentation is in the Gruff::Base class.
  12 +
  13 +== WARNING
  14 +
  15 +This is beta-quality software. It works well according to my tests, but the API may change and other features will be added.
52 Rakefile
... ... @@ -0,0 +1,52 @@
  1 +require 'rubygems'
  2 +require 'hoe'
  3 +$:.unshift(File.dirname(__FILE__) + "/lib")
  4 +require 'gruff'
  5 +
  6 +Hoe.new('Gruff', Gruff::VERSION) do |p|
  7 + p.name = "gruff"
  8 + p.author = "Geoffrey Grosenbach"
  9 + p.description = "Beautiful graphs for one or multiple datasets. Can be used on websites or in documents."
  10 + p.email = 'boss@topfunky.com'
  11 + p.summary = "Beautiful graphs for one or multiple datasets."
  12 + p.url = "http://nubyonrails.com/pages/gruff"
  13 + p.clean_globs = ['test/output/*.png']
  14 + p.changes = p.paragraphs_of('CHANGELOG', 0..1).join("\n\n")
  15 + p.remote_rdoc_dir = '' # Release to root
  16 +end
  17 +
  18 +desc "Simple test on packaged files to make sure they are all there"
  19 +task :verify => :package do
  20 + # An error message will be displayed if files are missing
  21 + if system %(ruby -e "require 'pkg/gruff-#{Gruff::VERSION}/lib/gruff'")
  22 + puts "\nThe library files are present"
  23 + end
  24 +end
  25 +
  26 +namespace :test do
  27 +
  28 + desc "Run mini tests"
  29 + task :mini => :clean do
  30 + Dir['test/test_mini*'].each do |file|
  31 + system "ruby #{file}"
  32 + end
  33 +
  34 + end
  35 +
  36 +end
  37 +
  38 +##
  39 +# Catch unmatched tasks and run them as a unit test.
  40 +#
  41 +# Makes it possible to do
  42 +#
  43 +# rake pie
  44 +#
  45 +# To run the +test/test_pie+ and +test/test_mini_pie+ files.
  46 +
  47 +rule '' do |t|
  48 + # Rake::Task["clean"].invoke
  49 + Dir["test/test_*#{t.name}*.rb"].each do |filename|
  50 + system "ruby #{filename}"
  51 + end
  52 +end
BIN  artwork/city_scene.psd
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
0  artwork/graphs/Backup of Untitled.key/.typeAttributes.dict
No changes.
1  artwork/graphs/Backup of Untitled.key/Contents/PkgInfo
... ... @@ -0,0 +1 @@
  1 +????????
BIN  artwork/graphs/Backup of Untitled.key/index.apxl.gz
Binary file not shown
BIN  artwork/graphs/Backup of Untitled.key/thumbs/st0.tiff
Binary file not shown
BIN  artwork/graphs/Backup of Untitled.key/thumbs/st1.tiff
Binary file not shown
BIN  artwork/graphs/Backup of Untitled.key/thumbs/st2.tiff
Binary file not shown
BIN  artwork/graphs/Backup of Untitled.key/thumbs/st3.tiff
Binary file not shown
0  artwork/graphs/Untitled.key/.typeAttributes.dict
No changes.
1  artwork/graphs/Untitled.key/Contents/PkgInfo
... ... @@ -0,0 +1 @@
  1 +????????
BIN  artwork/graphs/Untitled.key/index.apxl.gz
Binary file not shown
BIN  artwork/graphs/Untitled.key/thumbs/st0.tiff
Binary file not shown
BIN  artwork/graphs/Untitled.key/thumbs/st1.tiff
Binary file not shown
BIN  artwork/graphs/Untitled.key/thumbs/st2.tiff
Binary file not shown
BIN  artwork/graphs/Untitled.key/thumbs/st3.tiff
Binary file not shown
BIN  artwork/graphs/samples.001.png
BIN  artwork/graphs/samples.002.png
BIN  artwork/graphs/samples.003.png
BIN  artwork/graphs/samples.004.png
36 artwork/gruff_controller.rb
... ... @@ -0,0 +1,36 @@
  1 +
  2 +# Handles requests for gruff graphs.
  3 +#
  4 +# You shouldn't need to edit or extend this, but you can read
  5 +# the documentation for GruffHelper to see how to call it from
  6 +# another view.
  7 +#
  8 +# AUTHOR
  9 +# Carlos Villela [mailto:cv@lixo.org]
  10 +# Geoffrey Grosenbach[mailto:boss@topfunky.com]
  11 +#
  12 +# http://lixo.org
  13 +# http://topfunky.com
  14 +#
  15 +require_gem 'gruff'
  16 +
  17 +class GruffController < ApplicationController
  18 + layout nil
  19 +
  20 + def index
  21 + opts = @session['gruff_opts']
  22 + data = @session['gruff_data']
  23 +
  24 + raise "No Gruff data or options set in the session" if data.nil? or opts.nil?
  25 +
  26 + g = Gruff::Line.new(475)
  27 + g.title = opts[:title]
  28 + g.labels = opts[:labels]
  29 + g.theme_37signals
  30 +
  31 + data.each_pair {|k,v| g.data(k, v) }
  32 +
  33 + send_data(g.to_blob, :disposition => 'inline', :type => 'image/png', :filename => "gruff.png")
  34 + end
  35 +
  36 +end
32 artwork/gruffs_helper.rb
... ... @@ -0,0 +1,32 @@
  1 +
  2 +# Provides a tag for embedding gruff graphs into your Rails app.
  3 +#
  4 +# To use, load it in your controller with
  5 +#
  6 +# helper :gruff
  7 +#
  8 +# AUTHOR
  9 +#
  10 +# Carlos Villela [mailto:cv@lixo.org]
  11 +# Geoffrey Grosenbach[mailto:boss@topfunky.com]
  12 +#
  13 +# http://lixo.org
  14 +# http://topfunky.com
  15 +#
  16 +# License
  17 +#
  18 +# This code is licensed under the MIT license.
  19 +#
  20 +module GruffsHelper
  21 +
  22 + # Call with a name-values hash and an options hash (title and labels supported for now).
  23 + # You can also pass :class => 'some_css_class' ('gruff' by default).
  24 + def gruff_tag(data={}, opts={})
  25 +
  26 + @session['gruff_opts']=opts
  27 + @session['gruff_data']=data
  28 +
  29 + "<img src=\"/gruff\" class=\"#{opts[:class] || 'gruff'}\" alt=\"Gruff Graph\" />"
  30 + end
  31 +
  32 +end
15 artwork/install_rmagick.sh
... ... @@ -0,0 +1,15 @@
  1 +#!/bin/sh
  2 +
  3 +# Install libraries for rmagick, using darwinports.
  4 +#
  5 +# Geoffrey Grosenbach boss@topfunky.com
  6 +#
  7 +
  8 +sudo port install jpeg
  9 +sudo port install libpng
  10 +sudo port install libwmf
  11 +sudo port install tiff
  12 +sudo port install lcms
  13 +sudo port install freetype
  14 +sudo port install imagemagick
  15 +sudo gem install rmagick
BIN  artwork/mrplot-0.0.1.tar.gz
Binary file not shown
BIN  artwork/plastik-blue.psd
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
BIN  artwork/plastik-green.psd
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
BIN  artwork/plastik-red.psd
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
BIN  artwork/plastik-template.psd
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
BIN  artwork/plastik.png
BIN  assets/bubble.png
BIN  assets/city_scene/background/0000.png
BIN  assets/city_scene/background/0600.png
BIN  assets/city_scene/background/2000.png
BIN  assets/city_scene/clouds/cloudy.png
BIN  assets/city_scene/clouds/partly_cloudy.png
BIN  assets/city_scene/clouds/stormy.png
BIN  assets/city_scene/grass/default.png
BIN  assets/city_scene/haze/true.png
BIN  assets/city_scene/number_sample/1.png
BIN  assets/city_scene/number_sample/2.png
BIN  assets/city_scene/number_sample/default.png
BIN  assets/city_scene/sky/0000.png
BIN  assets/city_scene/sky/0200.png
BIN  assets/city_scene/sky/0400.png
BIN  assets/city_scene/sky/0600.png
BIN  assets/city_scene/sky/0800.png
BIN  assets/city_scene/sky/1000.png
BIN  assets/city_scene/sky/1200.png
BIN  assets/city_scene/sky/1400.png
BIN  assets/city_scene/sky/1500.png
BIN  assets/city_scene/sky/1700.png
BIN  assets/city_scene/sky/2000.png
BIN  assets/pc306715.jpg
BIN  assets/plastik/blue.png
BIN  assets/plastik/green.png
BIN  assets/plastik/red.png
26 lib/gruff.rb
... ... @@ -0,0 +1,26 @@
  1 +# Extra full path added to fix loading errors on some installations.
  2 +
  3 +%w(
  4 + base
  5 + area
  6 + bar
  7 + bullet
  8 + line
  9 + pie
  10 + spider
  11 + net
  12 + stacked_area
  13 + stacked_bar
  14 + side_stacked_bar
  15 + side_bar
  16 + accumulator_bar
  17 +
  18 + scene
  19 +
  20 + mini/legend
  21 + mini/bar
  22 + mini/pie
  23 + mini/side_bar
  24 +).each do |filename|
  25 + require File.dirname(__FILE__) + "/gruff/#{filename}"
  26 +end
27 lib/gruff/accumulator_bar.rb
... ... @@ -0,0 +1,27 @@
  1 +require File.dirname(__FILE__) + '/base'
  2 +
  3 +##
  4 +# A special bar graph that shows a single dataset as a set of
  5 +# stacked bars. The bottom bar shows the running total and
  6 +# the top bar shows the new value being added to the array.
  7 +
  8 +class Gruff::AccumulatorBar < Gruff::StackedBar
  9 +
  10 + def draw
  11 + raise(Gruff::IncorrectNumberOfDatasetsException) unless @data.length == 1
  12 +
  13 + accumulator_array = []
  14 + index = 0
  15 +
  16 + increment_array = @data.first[DATA_VALUES_INDEX].inject([]) {|memo, value|
  17 + memo << ((index > 0) ? (value + memo.max) : value)
  18 + accumulator_array << memo[index] - value
  19 + index += 1
  20 + memo
  21 + }
  22 + data "Accumulator", accumulator_array
  23 +
  24 + super
  25 + end
  26 +
  27 +end
58 lib/gruff/area.rb
... ... @@ -0,0 +1,58 @@
  1 +
  2 +require File.dirname(__FILE__) + '/base'
  3 +
  4 +class Gruff::Area < Gruff::Base
  5 +
  6 + def draw
  7 + super
  8 +
  9 + return unless @has_data
  10 +
  11 + @x_increment = @graph_width / (@column_count - 1).to_f
  12 + @d = @d.stroke 'transparent'
  13 +
  14 + @norm_data.each do |data_row|
  15 + poly_points = Array.new
  16 + prev_x = prev_y = 0.0
  17 + @d = @d.fill data_row[DATA_COLOR_INDEX]
  18 +
  19 + data_row[1].each_with_index do |data_point, index|
  20 + # Use incremented x and scaled y
  21 + new_x = @graph_left + (@x_increment * index)
  22 + new_y = @graph_top + (@graph_height - data_point * @graph_height)
  23 +
  24 + if prev_x > 0 and prev_y > 0 then
  25 + poly_points << new_x
  26 + poly_points << new_y
  27 +
  28 + #@d = @d.polyline(prev_x, prev_y, new_x, new_y)
  29 + else
  30 + poly_points << @graph_left
  31 + poly_points << @graph_bottom - 1
  32 + poly_points << new_x
  33 + poly_points << new_y
  34 +
  35 + #@d = @d.polyline(@graph_left, @graph_bottom, new_x, new_y)
  36 + end
  37 +
  38 + draw_label(new_x, index)
  39 +
  40 + prev_x = new_x
  41 + prev_y = new_y
  42 + end
  43 +
  44 + # Add closing points, draw polygon
  45 + poly_points << @graph_right
  46 + poly_points << @graph_bottom - 1
  47 + poly_points << @graph_left
  48 + poly_points << @graph_bottom - 1
  49 +
  50 + @d = @d.polyline(*poly_points)
  51 +
  52 + end
  53 +
  54 + @d.draw(@base_image)
  55 + end
  56 +
  57 +
  58 +end
84 lib/gruff/bar.rb
... ... @@ -0,0 +1,84 @@
  1 +
  2 +require File.dirname(__FILE__) + '/base'
  3 +require File.dirname(__FILE__) + '/bar_conversion'
  4 +
  5 +class Gruff::Bar < Gruff::Base
  6 +
  7 + def draw
  8 + # Labels will be centered over the left of the bar if
  9 + # there are more labels than columns. This is basically the same
  10 + # as where it would be for a line graph.
  11 + @center_labels_over_point = (@labels.keys.length > @column_count ? true : false)
  12 +
  13 + super
  14 + return unless @has_data
  15 +
  16 + draw_bars
  17 + end
  18 +
  19 +protected
  20 +
  21 + def draw_bars
  22 + # Setup spacing.
  23 + #
  24 + # Columns sit side-by-side.
  25 + spacing_factor = 0.9 # space between the bars
  26 + @bar_width = @graph_width / (@column_count * @data.length).to_f
  27 +
  28 + @d = @d.stroke_opacity 0.0
  29 +
  30 + # Setup the BarConversion Object
  31 + conversion = Gruff::BarConversion.new()
  32 + conversion.graph_height = @graph_height
  33 + conversion.graph_top = @graph_top
  34 +
  35 + # Set up the right mode [1,2,3] see BarConversion for further explanation
  36 + if @minimum_value >= 0 then
  37 + # all bars go from zero to positiv
  38 + conversion.mode = 1
  39 + else
  40 + # all bars go from 0 to negativ
  41 + if @maximum_value <= 0 then
  42 + conversion.mode = 2
  43 + else
  44 + # bars either go from zero to negativ or to positiv
  45 + conversion.mode = 3
  46 + conversion.spread = @spread
  47 + conversion.minimum_value = @minimum_value
  48 + conversion.zero = -@minimum_value/@spread
  49 + end
  50 + end
  51 +
  52 + # iterate over all normalised data
  53 + @norm_data.each_with_index do |data_row, row_index|
  54 +
  55 + data_row[1].each_with_index do |data_point, point_index|
  56 + # Use incremented x and scaled y
  57 + # x
  58 + left_x = @graph_left + (@bar_width * (row_index + point_index + ((@data.length - 1) * point_index)))
  59 + right_x = left_x + @bar_width * spacing_factor
  60 + # y
  61 + conv = []
  62 + conversion.getLeftYRightYscaled( data_point, conv )
  63 +
  64 + # create new bar
  65 + @d = @d.fill data_row[DATA_COLOR_INDEX]
  66 + @d = @d.rectangle(left_x, conv[0], right_x, conv[1])
  67 +
  68 + # Calculate center based on bar_width and current row
  69 + label_center = @graph_left +
  70 + (@data.length * @bar_width * point_index) +
  71 + (@data.length * @bar_width / 2.0)
  72 + # Subtract half a bar width to center left if requested
  73 + draw_label(label_center - (@center_labels_over_point ? @bar_width / 2.0 : 0.0), point_index)
  74 + end
  75 +
  76 + end
  77 +
  78 + # Draw the last label if requested
  79 + draw_label(@graph_right, @column_count) if @center_labels_over_point
  80 +
  81 + @d.draw(@base_image)
  82 + end
  83 +
  84 +end
46 lib/gruff/bar_conversion.rb
... ... @@ -0,0 +1,46 @@
  1 +##
  2 +# Original Author: David Stokar
  3 +#
  4 +# This class perfoms the y coordinats conversion for the bar class.
  5 +#
  6 +# There are three cases:
  7 +#
  8 +# 1. Bars all go from zero in positive direction
  9 +# 2. Bars all go from zero to negative direction
  10 +# 3. Bars either go from zero to positive or from zero to negative
  11 +#
  12 +class Gruff::BarConversion
  13 + attr_writer :mode
  14 + attr_writer :zero
  15 + attr_writer :graph_top
  16 + attr_writer :graph_height
  17 + attr_writer :minimum_value
  18 + attr_writer :spread
  19 +
  20 + def getLeftYRightYscaled( data_point, result )
  21 + case @mode
  22 + when 1 then # Case one
  23 + # minimum value >= 0 ( only positiv values )
  24 + result[0] = @graph_top + @graph_height*(1 - data_point) + 1
  25 + result[1] = @graph_top + @graph_height - 1
  26 + when 2 then # Case two
  27 + # only negativ values
  28 + result[0] = @graph_top + 1
  29 + result[1] = @graph_top + @graph_height*(1 - data_point) - 1
  30 + when 3 then # Case three
  31 + # positiv and negativ values
  32 + val = data_point-@minimum_value/@spread
  33 + if ( data_point >= @zero ) then
  34 + result[0] = @graph_top + @graph_height*(1 - (val-@zero)) + 1
  35 + result[1] = @graph_top + @graph_height*(1 - @zero) - 1
  36 + else
  37 + result[0] = @graph_top + @graph_height*(1 - (val-@zero)) + 1
  38 + result[1] = @graph_top + @graph_height*(1 - @zero) - 1
  39 + end
  40 + else
  41 + result[0] = 0.0
  42 + result[1] = 0.0
  43 + end
  44 + end
  45 +
  46 +end
1,070 lib/gruff/base.rb
... ... @@ -0,0 +1,1070 @@
  1 +require 'rubygems'
  2 +require 'RMagick'
  3 +require File.dirname(__FILE__) + '/deprecated'
  4 +
  5 +# = Gruff. Graphs.
  6 +#
  7 +# Author:: Geoffrey Grosenbach boss@topfunky.com
  8 +#
  9 +# Originally Created:: October 23, 2005
  10 +#
  11 +# Extra thanks to Tim Hunter for writing RMagick, and also contributions by
  12 +# Jarkko Laine, Mike Perham, Andreas Schwarz, Alun Eyre, Guillaume Theoret,
  13 +# David Stokar, Paul Rogers, Dave Woodward, Frank Oxener, Kevin Clark, Cies
  14 +# Breijs, Richard Cowin, and a cast of thousands.
  15 +#
  16 +# See Gruff::Base#theme= for setting themes.
  17 +module Gruff
  18 +
  19 + # This is the version of Gruff you are using.
  20 + VERSION = '0.3.0'
  21 +
  22 + class Base
  23 +
  24 + include Magick
  25 + include Deprecated
  26 +
  27 + # Draw extra lines showing where the margins and text centers are
  28 + DEBUG = false
  29 +
  30 + # Used for navigating the array of data to plot
  31 + DATA_LABEL_INDEX = 0
  32 + DATA_VALUES_INDEX = 1
  33 + DATA_COLOR_INDEX = 2
  34 +
  35 + # Space around text elements. Mostly used for vertical spacing
  36 + LEGEND_MARGIN = TITLE_MARGIN = LABEL_MARGIN = 10.0
  37 +
  38 + DEFAULT_TARGET_WIDTH = 800
  39 +
  40 + # Blank space above the graph
  41 + attr_accessor :top_margin
  42 +
  43 + # Blank space below the graph
  44 + attr_accessor :bottom_margin
  45 +
  46 + # Blank space to the right of the graph
  47 + attr_accessor :right_margin
  48 +
  49 + # Blank space to the left of the graph
  50 + attr_accessor :left_margin
  51 +
  52 + # A hash of names for the individual columns, where the key is the array
  53 + # index for the column this label represents.
  54 + #
  55 + # Not all columns need to be named.
  56 + #
  57 + # Example: 0 => 2005, 3 => 2006, 5 => 2007, 7 => 2008
  58 + attr_accessor :labels
  59 +
  60 + # Used internally for spacing.
  61 + #
  62 + # By default, labels are centered over the point they represent.
  63 + attr_accessor :center_labels_over_point
  64 +
  65 + # Used internally for horizontal graph types.
  66 + attr_accessor :has_left_labels
  67 +
  68 + # A label for the bottom of the graph
  69 + attr_accessor :x_axis_label
  70 +
  71 + # A label for the left side of the graph
  72 + attr_accessor :y_axis_label
  73 +
  74 + # attr_accessor :x_axis_increment
  75 +
  76 + # Manually set increment of the horizontal marking lines
  77 + attr_accessor :y_axis_increment
  78 +
  79 + # Get or set the list of colors that will be used to draw the bars or lines.
  80 + attr_accessor :colors
  81 +
  82 + # The large title of the graph displayed at the top
  83 + attr_accessor :title
  84 +
  85 + # Font used for titles, labels, etc. Works best if you provide the full
  86 + # path to the TTF font file. RMagick must be built with the Freetype
  87 + # libraries for this to work properly.
  88 + #
  89 + # Tries to find Bitstream Vera (Vera.ttf) in the location specified by
  90 + # ENV['MAGICK_FONT_PATH']. Uses default RMagick font otherwise.
  91 + #
  92 + # The font= method below fulfills the role of the writer, so we only need
  93 + # a reader here.
  94 + attr_reader :font
  95 +
  96 + attr_accessor :font_color
  97 +
  98 + # Prevent drawing of line markers
  99 + attr_accessor :hide_line_markers
  100 +
  101 + # Prevent drawing of the legend
  102 + attr_accessor :hide_legend
  103 +
  104 + # Prevent drawing of the title
  105 + attr_accessor :hide_title
  106 +
  107 + # Prevent drawing of line numbers
  108 + attr_accessor :hide_line_numbers
  109 +
  110 + # Message shown when there is no data. Fits up to 20 characters. Defaults
  111 + # to "No Data."
  112 + attr_accessor :no_data_message
  113 +
  114 + # The font size of the large title at the top of the graph
  115 + attr_accessor :title_font_size
  116 +
  117 + # Optionally set the size of the font. Based on an 800x600px graph.
  118 + # Default is 20.
  119 + #
  120 + # Will be scaled down if graph is smaller than 800px wide.
  121 + attr_accessor :legend_font_size
  122 +
  123 + # The font size of the labels around the graph
  124 + attr_accessor :marker_font_size
  125 +
  126 + # The color of the auxiliary lines
  127 + attr_accessor :marker_color
  128 +
  129 + # The number of horizontal lines shown for reference
  130 + attr_accessor :marker_count
  131 +
  132 + # You can manually set a minimum value instead of having the values
  133 + # guessed for you.
  134 + #
  135 + # Set it after you have given all your data to the graph object.
  136 + attr_accessor :minimum_value
  137 +
  138 + # You can manually set a maximum value, such as a percentage-based graph
  139 + # that always goes to 100.
  140 + #
  141 + # If you use this, you must set it after you have given all your data to
  142 + # the graph object.
  143 + attr_accessor :maximum_value
  144 +
  145 + # Set to false if you don't want the data to be sorted with largest avg
  146 + # values at the back.
  147 + attr_accessor :sort
  148 +
  149 + # Experimental
  150 + attr_accessor :additional_line_values
  151 +
  152 + # Experimental
  153 + attr_accessor :stacked
  154 +
  155 + # Optionally set the size of the colored box by each item in the legend.
  156 + # Default is 20.0
  157 + #
  158 + # Will be scaled down if graph is smaller than 800px wide.
  159 + attr_accessor :legend_box_size
  160 +
  161 + # If one numerical argument is given, the graph is drawn at 4/3 ratio
  162 + # according to the given width (800 results in 800x600, 400 gives 400x300,
  163 + # etc.).
  164 + #
  165 + # Or, send a geometry string for other ratios ('800x400', '400x225').
  166 + #
  167 + # Looks for Bitstream Vera as the default font. Expects an environment var
  168 + # of MAGICK_FONT_PATH to be set. (Uses RMagick's default font otherwise.)
  169 + def initialize(target_width=DEFAULT_TARGET_WIDTH)
  170 + @top_margin = @bottom_margin = @left_margin = @right_margin = 20.0
  171 +
  172 + if not Numeric === target_width
  173 + geometric_width, geometric_height = target_width.split('x')
  174 + @columns = geometric_width.to_f
  175 + @rows = geometric_height.to_f
  176 + else
  177 + @columns = target_width.to_f
  178 + @rows = target_width.to_f * 0.75
  179 + end
  180 +
  181 + initialize_ivars
  182 +
  183 + reset_themes
  184 + theme_keynote
  185 + end
  186 +
  187 + # Set instance variables for this object.
  188 + #
  189 + # Subclasses can override this, call super, then set values separately.
  190 + #
  191 + # This makes it possible to set defaults in a subclass but still allow
  192 + # developers to change this values in their program.
  193 + def initialize_ivars
  194 + # Internal for calculations
  195 + @raw_columns = 800.0
  196 + @raw_rows = 800.0 * (@rows/@columns)
  197 + @column_count = 0
  198 + @marker_count = nil
  199 + @maximum_value = @minimum_value = nil
  200 + @has_data = false
  201 + @data = Array.new
  202 + @labels = Hash.new
  203 + @labels_seen = Hash.new
  204 + @sort = true
  205 + @title = nil
  206 +
  207 + @scale = @columns / @raw_columns
  208 +
  209 + vera_font_path = File.expand_path('Vera.ttf', ENV['MAGICK_FONT_PATH'])
  210 + @font = File.exists?(vera_font_path) ? vera_font_path : nil
  211 +
  212 + @marker_font_size = 21.0
  213 + @legend_font_size = 20.0
  214 + @title_font_size = 36.0
  215 +
  216 + @legend_box_size = 20.0
  217 +
  218 + @no_data_message = "No Data"
  219 +
  220 + @hide_line_markers = @hide_legend = @hide_title = @hide_line_numbers = false
  221 + @center_labels_over_point = true
  222 + @has_left_labels = false
  223 +
  224 + @additional_line_values = []
  225 + @additional_line_colors = []
  226 + @theme_options = {}
  227 +
  228 + @x_axis_label = @y_axis_label = nil
  229 + @y_axis_increment = nil
  230 + @stacked = nil
  231 + @norm_data = nil
  232 + end
  233 +
  234 + # Sets the top, bottom, left and right margins to +margin+.
  235 + def margins=(margin)
  236 + @top_margin = @left_margin = @right_margin = @bottom_margin = margin
  237 + end
  238 +
  239 + # Sets the font for graph text to the font at +font_path+.
  240 + def font=(font_path)
  241 + @font = font_path
  242 + @d.font = @font
  243 + end
  244 +
  245 + # Add a color to the list of available colors for lines.
  246 + #
  247 + # Example:
  248 + # add_color('#c0e9d3')
  249 + def add_color(colorname)
  250 + @colors << colorname
  251 + end
  252 +
  253 + # Replace the entire color list with a new array of colors. You need to
  254 + # have one more color than the number of datasets you intend to draw. Also
  255 + # aliased as the colors= setter method.
  256 + #
  257 + # Example:
  258 + # replace_colors ['#cc99cc', '#d9e043', '#34d8a2']
  259 + def replace_colors(color_list=[])
  260 + @colors = color_list
  261 + end
  262 +
  263 + # You can set a theme manually. Assign a hash to this method before you
  264 + # send your data.
  265 + #
  266 + # graph.theme = {
  267 + # :colors => %w(orange purple green white red),
  268 + # :marker_color => 'blue',
  269 + # :background_colors => %w(black grey)
  270 + # }
  271 + #
  272 + # :background_image => 'squirrel.png' is also possible.
  273 + #
  274 + # (Or hopefully something better looking than that.)
  275 + #
  276 + def theme=(options)
  277 + reset_themes()
  278 +
  279 + defaults = {
  280 + :colors => ['black', 'white'],
  281 + :additional_line_colors => [],
  282 + :marker_color => 'white',
  283 + :font_color => 'black',
  284 + :background_colors => nil,
  285 + :background_image => nil
  286 + }
  287 + @theme_options = defaults.merge options
  288 +
  289 + @colors = @theme_options[:colors]
  290 + @marker_color = @theme_options[:marker_color]
  291 + @font_color = @theme_options[:font_color] || @marker_color
  292 + @additional_line_colors = @theme_options[:additional_line_colors]
  293 +
  294 + render_background
  295 + end
  296 +
  297 + # A color scheme similar to the popular presentation software.
  298 + def theme_keynote
  299 + # Colors
  300 + @blue = '#6886B4'
  301 + @yellow = '#FDD84E'
  302 + @green = '#72AE6E'
  303 + @red = '#D1695E'
  304 + @purple = '#8A6EAF'
  305 + @orange = '#EFAA43'
  306 + @white = 'white'
  307 + @colors = [@yellow, @blue, @green, @red, @purple, @orange, @white]
  308 +
  309 + self.theme = {
  310 + :colors => @colors,
  311 + :marker_color => 'white',
  312 + :font_color => 'white',
  313 + :background_colors => ['black', '#4a465a']
  314 + }
  315 + end
  316 +
  317 + # A color scheme plucked from the colors on the popular usability blog.
  318 + def theme_37signals
  319 + # Colors
  320 + @green = '#339933'
  321 + @purple = '#cc99cc'
  322 + @blue = '#336699'
  323 + @yellow = '#FFF804'
  324 + @red = '#ff0000'
  325 + @orange = '#cf5910'
  326 + @black = 'black'
  327 + @colors = [@yellow, @blue, @green, @red, @purple, @orange, @black]
  328 +
  329 + self.theme = {
  330 + :colors => @colors,
  331 + :marker_color => 'black',
  332 + :font_color => 'black',
  333 + :background_colors => ['#d1edf5', 'white']
  334 + }
  335 + end
  336 +
  337 + # A color scheme from the colors used on the 2005 Rails keynote
  338 + # presentation at RubyConf.
  339 + def theme_rails_keynote
  340 + # Colors
  341 + @green = '#00ff00'
  342 + @grey = '#333333'
  343 + @orange = '#ff5d00'
  344 + @red = '#f61100'
  345 + @white = 'white'
  346 + @light_grey = '#999999'
  347 + @black = 'black'
  348 + @colors = [@green, @grey, @orange, @red, @white, @light_grey, @black]
  349 +
  350 + self.theme = {
  351 + :colors => @colors,
  352 + :marker_color => 'white',
  353 + :font_color => 'white',
  354 + :background_colors => ['#0083a3', '#0083a3']
  355 + }
  356 + end
  357 +
  358 + # A color scheme similar to that used on the popular podcast site.
  359 + def theme_odeo
  360 + # Colors
  361 + @grey = '#202020'
  362 + @white = 'white'
  363 + @dark_pink = '#a21764'
  364 + @green = '#8ab438'
  365 + @light_grey = '#999999'
  366 + @dark_blue = '#3a5b87'
  367 + @black = 'black'
  368 + @colors = [@grey, @white, @dark_blue, @dark_pink, @green, @light_grey, @black]
  369 +
  370 + self.theme = {
  371 + :colors => @colors,
  372 + :marker_color => 'white',
  373 + :font_color => 'white',
  374 + :background_colors => ['#ff47a4', '#ff1f81']
  375 + }
  376 + end
  377 +
  378 + # A pastel theme
  379 + def theme_pastel
  380 + # Colors
  381 + @colors = [
  382 + '#a9dada', # blue
  383 + '#aedaa9', # green
  384 + '#daaea9', # peach
  385 + '#dadaa9', # yellow
  386 + '#a9a9da', # dk purple
  387 + '#daaeda', # purple
  388 + '#dadada' # grey
  389 + ]
  390 +
  391 + self.theme = {
  392 + :colors => @colors,
  393 + :marker_color => '#aea9a9', # Grey
  394 + :font_color => 'black',
  395 + :background_colors => 'white'
  396 + }
  397 + end
  398 +
  399 + # A greyscale theme
  400 + def theme_greyscale
  401 + # Colors
  402 + @colors = [
  403 + '#282828', #
  404 + '#383838', #
  405 + '#686868', #
  406 + '#989898', #
  407 + '#c8c8c8', #
  408 + '#e8e8e8', #
  409 + ]
  410 +
  411 + self.theme = {
  412 + :colors => @colors,
  413 + :marker_color => '#aea9a9', # Grey
  414 + :font_color => 'black',
  415 + :background_colors => 'white'
  416 + }
  417 + end
  418 +
  419 + # Parameters are an array where the first element is the name of the dataset
  420 + # and the value is an array of values to plot.
  421 + #
  422 + # Can be called multiple times with different datasets for a multi-valued
  423 + # graph.
  424 + #
  425 + # If the color argument is nil, the next color from the default theme will
  426 + # be used.
  427 + #
  428 + # NOTE: If you want to use a preset theme, you must set it before calling
  429 + # data().
  430 + #
  431 + # Example:
  432 + # data("Bart S.", [95, 45, 78, 89, 88, 76], '#ffcc00')
  433 + def data(name, data_points=[], color=nil)
  434 + data_points = Array(data_points) # make sure it's an array
  435 + @data << [name, data_points, (color || increment_color)]
  436 + # Set column count if this is larger than previous counts
  437 + @column_count = (data_points.length > @column_count) ? data_points.length : @column_count
  438 +
  439 + # Pre-normalize
  440 + data_points.each_with_index do |data_point, index|
  441 + next if data_point.nil?
  442 +
  443 + # Setup max/min so spread starts at the low end of the data points
  444 + if @maximum_value.nil? && @minimum_value.nil?
  445 + @maximum_value = @minimum_value = data_point
  446 + end
  447 +
  448 + # TODO Doesn't work with stacked bar graphs
  449 + # Original: @maximum_value = larger_than_max?(data_point, index) ? max(data_point, index) : @maximum_value
  450 + @maximum_value = larger_than_max?(data_point) ? data_point : @maximum_value
  451 + @has_data = true if @maximum_value > 0
  452 +
  453 + @minimum_value = less_than_min?(data_point) ? data_point : @minimum_value
  454 + @has_data = true if @minimum_value < 0
  455 + end
  456 + end
  457 +
  458 + # Writes the graph to a file. Defaults to 'graph.png'
  459 + #
  460 + # Example:
  461 + # write('graphs/my_pretty_graph.png')
  462 + def write(filename="graph.png")
  463 + draw()
  464 + @base_image.write(filename)
  465 + end
  466 +
  467 + # Return the graph as a rendered binary blob.
  468 + def to_blob(fileformat='PNG')
  469 + draw()
  470 + return @base_image.to_blob do
  471 + self.format = fileformat
  472 + end
  473 + end
  474 +
  475 +protected
  476 +
  477 + # Overridden by subclasses to do the actual plotting of the graph.
  478 + #
  479 + # Subclasses should start by calling super() for this method.
  480 + def draw
  481 + make_stacked if @stacked
  482 + setup_drawing
  483 +
  484 + debug {
  485 + # Outer margin
  486 + @d.rectangle( @left_margin, @top_margin,
  487 + @raw_columns - @right_margin, @raw_rows - @bottom_margin)
  488 + # Graph area box
  489 + @d.rectangle( @graph_left, @graph_top, @graph_right, @graph_bottom)
  490 + }
  491 + end
  492 +
  493 + # Calculates size of drawable area and draws the decorations.