gruff 0.2.8 → 0.2.9
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +5 -1
- data/Manifest.txt +15 -10
- data/Rakefile +20 -3
- data/assets/bubble.png +0 -0
- data/assets/plastik/blue.png +0 -0
- data/assets/plastik/green.png +0 -0
- data/assets/plastik/red.png +0 -0
- data/lib/gruff.rb +1 -0
- data/lib/gruff/base.rb +213 -147
- data/lib/gruff/line.rb +11 -0
- data/lib/gruff/mini/legend.rb +3 -3
- data/lib/gruff/mini/side_bar.rb +13 -0
- data/lib/gruff/pie.rb +25 -11
- data/lib/gruff/scene.rb +15 -3
- data/lib/gruff/side_bar.rb +58 -61
- data/lib/gruff/side_stacked_bar.rb +51 -99
- data/lib/gruff/stacked_area.rb +66 -0
- data/lib/gruff/stacked_bar.rb +8 -4
- data/lib/gruff/stacked_mixin.rb +23 -0
- data/test/gruff_test_case.rb +1 -0
- data/test/test_pie.rb +25 -0
- metadata +41 -19
data/CHANGELOG
CHANGED
data/Manifest.txt
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
CHANGELOG
|
2
|
-
Manifest.txt
|
3
2
|
MIT-LICENSE
|
4
|
-
|
3
|
+
Manifest.txt
|
5
4
|
README.txt
|
6
|
-
|
5
|
+
Rakefile
|
6
|
+
assets/bubble.png
|
7
7
|
assets/city_scene/background/0000.png
|
8
8
|
assets/city_scene/background/0600.png
|
9
9
|
assets/city_scene/background/2000.png
|
@@ -26,14 +26,22 @@ assets/city_scene/sky/1400.png
|
|
26
26
|
assets/city_scene/sky/1500.png
|
27
27
|
assets/city_scene/sky/1700.png
|
28
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
|
29
33
|
lib/gruff.rb
|
34
|
+
lib/gruff/accumulator_bar.rb
|
30
35
|
lib/gruff/area.rb
|
31
36
|
lib/gruff/bar.rb
|
32
37
|
lib/gruff/bar_conversion.rb
|
33
|
-
lib/gruff/accumulator_bar.rb
|
34
38
|
lib/gruff/base.rb
|
35
39
|
lib/gruff/deprecated.rb
|
36
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
|
37
45
|
lib/gruff/net.rb
|
38
46
|
lib/gruff/photo_bar.rb
|
39
47
|
lib/gruff/pie.rb
|
@@ -41,15 +49,12 @@ lib/gruff/scene.rb
|
|
41
49
|
lib/gruff/side_bar.rb
|
42
50
|
lib/gruff/side_stacked_bar.rb
|
43
51
|
lib/gruff/spider.rb
|
52
|
+
lib/gruff/stacked_area.rb
|
44
53
|
lib/gruff/stacked_bar.rb
|
45
|
-
lib/gruff/
|
46
|
-
lib/gruff/mini/legend.rb
|
47
|
-
lib/gruff/mini/pie.rb
|
48
|
-
lib/gruff/mini/side_bar.rb
|
54
|
+
lib/gruff/stacked_mixin.rb
|
49
55
|
test/gruff_test_case.rb
|
50
|
-
test/output
|
51
|
-
test/test_area.rb
|
52
56
|
test/test_accumulator_bar.rb
|
57
|
+
test/test_area.rb
|
53
58
|
test/test_bar.rb
|
54
59
|
test/test_base.rb
|
55
60
|
test/test_legend.rb
|
data/Rakefile
CHANGED
@@ -11,6 +11,8 @@ Hoe.new('Gruff', Gruff::VERSION) do |p|
|
|
11
11
|
p.summary = "Beautiful graphs for one or multiple datasets."
|
12
12
|
p.url = "http://nubyonrails.com/pages/gruff"
|
13
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
|
14
16
|
end
|
15
17
|
|
16
18
|
desc "Simple test on packaged files to make sure they are all there"
|
@@ -21,15 +23,30 @@ task :verify => :package do
|
|
21
23
|
end
|
22
24
|
end
|
23
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
|
+
|
24
38
|
##
|
25
39
|
# Catch unmatched tasks and run them as a unit test.
|
26
40
|
#
|
27
41
|
# Makes it possible to do
|
28
|
-
#
|
42
|
+
#
|
29
43
|
# rake pie
|
30
44
|
#
|
31
|
-
# To run the +test/test_pie+
|
45
|
+
# To run the +test/test_pie+ and +test/test_mini_pie+ files.
|
32
46
|
|
33
47
|
rule '' do |t|
|
34
|
-
|
48
|
+
# Rake::Task["clean"].invoke
|
49
|
+
Dir["test/test_*#{t.name}*.rb"].each do |filename|
|
50
|
+
system "ruby #{filename}"
|
51
|
+
end
|
35
52
|
end
|
data/assets/bubble.png
ADDED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/lib/gruff.rb
CHANGED
data/lib/gruff/base.rb
CHANGED
@@ -1,29 +1,26 @@
|
|
1
|
-
|
1
|
+
require 'rubygems'
|
2
|
+
require 'RMagick'
|
3
|
+
require File.dirname(__FILE__) + '/deprecated'
|
4
|
+
|
2
5
|
# = Gruff. Graphs.
|
3
6
|
#
|
4
7
|
# Author:: Geoffrey Grosenbach boss@topfunky.com
|
5
8
|
#
|
6
9
|
# Originally Created:: October 23, 2005
|
7
10
|
#
|
8
|
-
# Extra thanks to Tim Hunter for writing RMagick,
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# Paul Rogers, Dave Woodward, Frank Oxener,
|
13
|
-
# Kevin Clark, Cies Breijs, Richard Cowin,
|
14
|
-
# and a cast of thousands.
|
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
15
|
#
|
16
|
+
# See Gruff::Base#theme= for setting themes.
|
17
|
+
module Gruff
|
16
18
|
|
17
|
-
|
18
|
-
|
19
|
-
require File.dirname(__FILE__) + '/deprecated'
|
19
|
+
# This is the version of Gruff you are using.
|
20
|
+
VERSION = '0.2.9'
|
20
21
|
|
21
|
-
module Gruff
|
22
|
-
|
23
|
-
VERSION = '0.2.8'
|
24
|
-
|
25
22
|
class Base
|
26
|
-
|
23
|
+
|
27
24
|
include Magick
|
28
25
|
include Deprecated
|
29
26
|
|
@@ -35,13 +32,25 @@ module Gruff
|
|
35
32
|
DATA_VALUES_INDEX = 1
|
36
33
|
DATA_COLOR_INDEX = 2
|
37
34
|
|
38
|
-
# Blank space around the edges of the graph
|
39
|
-
TOP_MARGIN = BOTTOM_MARGIN = RIGHT_MARGIN = LEFT_MARGIN = 20.0
|
40
|
-
|
41
35
|
# Space around text elements. Mostly used for vertical spacing
|
42
36
|
LEGEND_MARGIN = TITLE_MARGIN = LABEL_MARGIN = 10.0
|
43
|
-
|
44
|
-
|
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.
|
45
54
|
#
|
46
55
|
# Not all columns need to be named.
|
47
56
|
#
|
@@ -58,12 +67,12 @@ module Gruff
|
|
58
67
|
|
59
68
|
# A label for the bottom of the graph
|
60
69
|
attr_accessor :x_axis_label
|
61
|
-
|
70
|
+
|
62
71
|
# A label for the left side of the graph
|
63
72
|
attr_accessor :y_axis_label
|
64
73
|
|
65
74
|
# attr_accessor :x_axis_increment
|
66
|
-
|
75
|
+
|
67
76
|
# Manually set increment of the horizontal marking lines
|
68
77
|
attr_accessor :y_axis_increment
|
69
78
|
|
@@ -73,71 +82,92 @@ module Gruff
|
|
73
82
|
# The large title of the graph displayed at the top
|
74
83
|
attr_accessor :title
|
75
84
|
|
76
|
-
# Font used for titles, labels, etc. Works best if you provide the full
|
77
|
-
# RMagick must be built with the Freetype
|
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.
|
78
88
|
#
|
79
89
|
# Tries to find Bitstream Vera (Vera.ttf) in the location specified by
|
80
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.
|
81
94
|
attr_reader :font
|
82
95
|
|
83
96
|
attr_accessor :font_color
|
84
97
|
|
85
|
-
#
|
86
|
-
attr_accessor :hide_line_markers
|
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
|
87
109
|
|
88
|
-
# Message shown when there is no data. Fits up to 20 characters. Defaults
|
110
|
+
# Message shown when there is no data. Fits up to 20 characters. Defaults
|
111
|
+
# to "No Data."
|
89
112
|
attr_accessor :no_data_message
|
90
113
|
|
91
114
|
# The font size of the large title at the top of the graph
|
92
115
|
attr_accessor :title_font_size
|
93
116
|
|
94
|
-
# Optionally set the size of the font. Based on an 800x600px graph.
|
117
|
+
# Optionally set the size of the font. Based on an 800x600px graph.
|
118
|
+
# Default is 20.
|
95
119
|
#
|
96
120
|
# Will be scaled down if graph is smaller than 800px wide.
|
97
121
|
attr_accessor :legend_font_size
|
98
122
|
|
99
123
|
# The font size of the labels around the graph
|
100
124
|
attr_accessor :marker_font_size
|
101
|
-
|
125
|
+
|
102
126
|
# The color of the auxiliary lines
|
103
127
|
attr_accessor :marker_color
|
104
128
|
|
105
129
|
# The number of horizontal lines shown for reference
|
106
130
|
attr_accessor :marker_count
|
107
|
-
|
108
131
|
|
109
|
-
# You can manually set a minimum value instead of having the values
|
132
|
+
# You can manually set a minimum value instead of having the values
|
133
|
+
# guessed for you.
|
110
134
|
#
|
111
135
|
# Set it after you have given all your data to the graph object.
|
112
136
|
attr_accessor :minimum_value
|
113
137
|
|
114
|
-
# You can manually set a maximum value, such as a percentage-based graph
|
138
|
+
# You can manually set a maximum value, such as a percentage-based graph
|
139
|
+
# that always goes to 100.
|
115
140
|
#
|
116
|
-
# If you use this, you must set it after you have given all your data to
|
141
|
+
# If you use this, you must set it after you have given all your data to
|
142
|
+
# the graph object.
|
117
143
|
attr_accessor :maximum_value
|
118
|
-
|
119
|
-
# Set to false if you don't want the data to be sorted with largest avg
|
144
|
+
|
145
|
+
# Set to false if you don't want the data to be sorted with largest avg
|
146
|
+
# values at the back.
|
120
147
|
attr_accessor :sort
|
121
|
-
|
148
|
+
|
122
149
|
# Experimental
|
123
150
|
attr_accessor :additional_line_values
|
124
|
-
|
151
|
+
|
125
152
|
# Experimental
|
126
153
|
attr_accessor :stacked
|
127
|
-
|
128
|
-
|
129
|
-
#
|
154
|
+
|
155
|
+
# Optionally set the size of the colored box by each item in the legend.
|
156
|
+
# Default is 20.0
|
130
157
|
#
|
131
158
|
# Will be scaled down if graph is smaller than 800px wide.
|
132
159
|
attr_accessor :legend_box_size
|
133
160
|
|
134
|
-
|
135
|
-
#
|
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.).
|
136
164
|
#
|
137
|
-
# Or, send a geometry string for other ratios ('800x400', '400x225').
|
165
|
+
# Or, send a geometry string for other ratios ('800x400', '400x225').
|
138
166
|
#
|
139
|
-
# Looks for Bitstream Vera as the default font. Expects an environment var
|
140
|
-
|
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
|
141
171
|
|
142
172
|
if not Numeric === target_width
|
143
173
|
geometric_width, geometric_height = target_width.split('x')
|
@@ -154,14 +184,12 @@ module Gruff
|
|
154
184
|
theme_keynote
|
155
185
|
end
|
156
186
|
|
157
|
-
##
|
158
187
|
# Set instance variables for this object.
|
159
188
|
#
|
160
189
|
# Subclasses can override this, call super, then set values separately.
|
161
190
|
#
|
162
191
|
# This makes it possible to set defaults in a subclass but still allow
|
163
192
|
# developers to change this values in their program.
|
164
|
-
|
165
193
|
def initialize_ivars
|
166
194
|
# Internal for calculations
|
167
195
|
@raw_columns = 800.0
|
@@ -202,7 +230,13 @@ module Gruff
|
|
202
230
|
@stacked = nil
|
203
231
|
@norm_data = nil
|
204
232
|
end
|
205
|
-
|
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+.
|
206
240
|
def font=(font_path)
|
207
241
|
@font = font_path
|
208
242
|
@d.font = @font
|
@@ -210,24 +244,24 @@ module Gruff
|
|
210
244
|
|
211
245
|
# Add a color to the list of available colors for lines.
|
212
246
|
#
|
213
|
-
# Example:
|
247
|
+
# Example:
|
214
248
|
# add_color('#c0e9d3')
|
215
249
|
def add_color(colorname)
|
216
250
|
@colors << colorname
|
217
251
|
end
|
218
252
|
|
219
|
-
|
220
|
-
#
|
221
|
-
#
|
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.
|
222
256
|
#
|
223
|
-
# Example:
|
224
|
-
# replace_colors
|
257
|
+
# Example:
|
258
|
+
# replace_colors ['#cc99cc', '#d9e043', '#34d8a2']
|
225
259
|
def replace_colors(color_list=[])
|
226
260
|
@colors = color_list
|
227
261
|
end
|
228
262
|
|
229
|
-
|
230
|
-
#
|
263
|
+
# You can set a theme manually. Assign a hash to this method before you
|
264
|
+
# send your data.
|
231
265
|
#
|
232
266
|
# graph.theme = {
|
233
267
|
# :colors => %w(orange purple green white red),
|
@@ -259,7 +293,7 @@ module Gruff
|
|
259
293
|
|
260
294
|
render_background
|
261
295
|
end
|
262
|
-
|
296
|
+
|
263
297
|
# A color scheme similar to the popular presentation software.
|
264
298
|
def theme_keynote
|
265
299
|
# Colors
|
@@ -279,7 +313,7 @@ module Gruff
|
|
279
313
|
:background_colors => ['black', '#4a465a']
|
280
314
|
}
|
281
315
|
end
|
282
|
-
|
316
|
+
|
283
317
|
# A color scheme plucked from the colors on the popular usability blog.
|
284
318
|
def theme_37signals
|
285
319
|
# Colors
|
@@ -300,7 +334,8 @@ module Gruff
|
|
300
334
|
}
|
301
335
|
end
|
302
336
|
|
303
|
-
# A color scheme from the colors used on the 2005 Rails keynote
|
337
|
+
# A color scheme from the colors used on the 2005 Rails keynote
|
338
|
+
# presentation at RubyConf.
|
304
339
|
def theme_rails_keynote
|
305
340
|
# Colors
|
306
341
|
@green = '#00ff00'
|
@@ -340,19 +375,61 @@ module Gruff
|
|
340
375
|
}
|
341
376
|
end
|
342
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
|
+
|
343
419
|
# Parameters are an array where the first element is the name of the dataset
|
344
420
|
# and the value is an array of values to plot.
|
345
421
|
#
|
346
|
-
# Can be called multiple times with different datasets for a multi-valued
|
422
|
+
# Can be called multiple times with different datasets for a multi-valued
|
423
|
+
# graph.
|
347
424
|
#
|
348
|
-
# If the color argument is nil, the next color from the default theme will
|
425
|
+
# If the color argument is nil, the next color from the default theme will
|
426
|
+
# be used.
|
349
427
|
#
|
350
|
-
# NOTE: If you want to use a preset theme, you must set it before calling
|
428
|
+
# NOTE: If you want to use a preset theme, you must set it before calling
|
429
|
+
# data().
|
351
430
|
#
|
352
431
|
# Example:
|
353
|
-
#
|
354
|
-
# data("Bart S.", [95, 45, 78, 89, 88, 76], '#ffcc00')
|
355
|
-
#
|
432
|
+
# data("Bart S.", [95, 45, 78, 89, 88, 76], '#ffcc00')
|
356
433
|
def data(name, data_points=[], color=nil)
|
357
434
|
data_points = Array(data_points) # make sure it's an array
|
358
435
|
@data << [name, data_points, (color || increment_color)]
|
@@ -380,7 +457,8 @@ module Gruff
|
|
380
457
|
|
381
458
|
# Writes the graph to a file. Defaults to 'graph.png'
|
382
459
|
#
|
383
|
-
# Example:
|
460
|
+
# Example:
|
461
|
+
# write('graphs/my_pretty_graph.png')
|
384
462
|
def write(filename="graph.png")
|
385
463
|
draw()
|
386
464
|
@base_image.write(filename)
|
@@ -405,20 +483,18 @@ protected
|
|
405
483
|
|
406
484
|
debug {
|
407
485
|
# Outer margin
|
408
|
-
@d.rectangle(
|
409
|
-
@raw_columns -
|
486
|
+
@d.rectangle( @left_margin, @top_margin,
|
487
|
+
@raw_columns - @right_margin, @raw_rows - @bottom_margin)
|
410
488
|
# Graph area box
|
411
489
|
@d.rectangle( @graph_left, @graph_top, @graph_right, @graph_bottom)
|
412
490
|
}
|
413
491
|
end
|
414
492
|
|
415
|
-
##
|
416
493
|
# Calculates size of drawable area and draws the decorations.
|
417
494
|
#
|
418
495
|
# * line markers
|
419
496
|
# * legend
|
420
497
|
# * title
|
421
|
-
|
422
498
|
def setup_drawing
|
423
499
|
# Maybe should be done in one of the following functions for more granularity.
|
424
500
|
unless @has_data
|
@@ -458,23 +534,24 @@ protected
|
|
458
534
|
end
|
459
535
|
end
|
460
536
|
|
461
|
-
def calculate_spread
|
537
|
+
def calculate_spread # :nodoc:
|
462
538
|
@spread = @maximum_value.to_f - @minimum_value.to_f
|
463
539
|
@spread = @spread > 0 ? @spread : 1
|
464
540
|
end
|
465
541
|
|
466
|
-
##
|
467
542
|
# Calculates size of drawable area, general font dimensions, etc.
|
468
|
-
|
469
543
|
def setup_graph_measurements
|
470
|
-
@marker_caps_height =
|
471
|
-
|
472
|
-
@
|
473
|
-
|
544
|
+
@marker_caps_height = @hide_line_markers ? 0 :
|
545
|
+
calculate_caps_height(@marker_font_size)
|
546
|
+
@title_caps_height = @hide_title ? 0 :
|
547
|
+
calculate_caps_height(@title_font_size)
|
548
|
+
@legend_caps_height = @hide_legend ? 0 :
|
549
|
+
calculate_caps_height(@legend_font_size)
|
550
|
+
|
474
551
|
if @hide_line_markers
|
475
|
-
(@graph_left,
|
476
|
-
@graph_right_margin,
|
477
|
-
@graph_bottom_margin) = [
|
552
|
+
(@graph_left,
|
553
|
+
@graph_right_margin,
|
554
|
+
@graph_bottom_margin) = [@left_margin, @right_margin, @bottom_margin]
|
478
555
|
else
|
479
556
|
longest_left_label_width = 0
|
480
557
|
if @has_left_labels
|
@@ -484,13 +561,13 @@ protected
|
|
484
561
|
longest_left_label_width = calculate_width(@marker_font_size,
|
485
562
|
label(@maximum_value.to_f))
|
486
563
|
end
|
487
|
-
|
564
|
+
|
488
565
|
# Shift graph if left line numbers are hidden
|
489
566
|
line_number_width = @hide_line_numbers && !@has_left_labels ?
|
490
567
|
0.0 :
|
491
568
|
(longest_left_label_width + LABEL_MARGIN * 2)
|
492
569
|
|
493
|
-
@graph_left =
|
570
|
+
@graph_left = @left_margin +
|
494
571
|
line_number_width +
|
495
572
|
(@y_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN * 2)
|
496
573
|
# Make space for half the width of the rightmost column label.
|
@@ -499,9 +576,9 @@ protected
|
|
499
576
|
extra_room_for_long_label = (last_label >= (@column_count-1) && @center_labels_over_point) ?
|
500
577
|
calculate_width(@marker_font_size, @labels[last_label])/2.0 :
|
501
578
|
0
|
502
|
-
@graph_right_margin =
|
579
|
+
@graph_right_margin = @right_margin + extra_room_for_long_label
|
503
580
|
|
504
|
-
@graph_bottom_margin =
|
581
|
+
@graph_bottom_margin = @bottom_margin +
|
505
582
|
@marker_caps_height + LABEL_MARGIN
|
506
583
|
end
|
507
584
|
|
@@ -510,13 +587,13 @@ protected
|
|
510
587
|
|
511
588
|
# When @hide title, leave a TITLE_MARGIN space for aesthetics.
|
512
589
|
# Same with @hide_legend
|
513
|
-
@graph_top =
|
590
|
+
@graph_top = @top_margin +
|
514
591
|
(@hide_title ? TITLE_MARGIN : @title_caps_height + TITLE_MARGIN * 2) +
|
515
592
|
(@hide_legend ? LEGEND_MARGIN : @legend_caps_height + LEGEND_MARGIN * 2)
|
516
593
|
|
517
|
-
|
518
|
-
|
519
|
-
|
594
|
+
x_axis_label_height = @x_axis_label.nil? ? 0.0 :
|
595
|
+
@marker_caps_height + LABEL_MARGIN
|
596
|
+
@graph_bottom = @raw_rows - @graph_bottom_margin - x_axis_label_height
|
520
597
|
@graph_height = @graph_bottom - @graph_top
|
521
598
|
end
|
522
599
|
|
@@ -547,7 +624,7 @@ protected
|
|
547
624
|
@d.gravity = CenterGravity
|
548
625
|
@d = @d.annotate_scaled( @base_image,
|
549
626
|
1.0, @raw_rows,
|
550
|
-
|
627
|
+
@left_margin + @marker_caps_height / 2.0, 0.0,
|
551
628
|
@y_axis_label, @scale)
|
552
629
|
@d.rotation = -90.0
|
553
630
|
end
|
@@ -636,8 +713,8 @@ protected
|
|
636
713
|
@d = @d.stroke_antialias true
|
637
714
|
end
|
638
715
|
|
639
|
-
# Draws a legend with the names of the datasets
|
640
|
-
#
|
716
|
+
# Draws a legend with the names of the datasets matched to the colors used
|
717
|
+
# to draw them.
|
641
718
|
def draw_legend
|
642
719
|
return if @hide_legend
|
643
720
|
|
@@ -658,8 +735,8 @@ protected
|
|
658
735
|
|
659
736
|
current_x_offset = legend_left
|
660
737
|
current_y_offset = @hide_title ?
|
661
|
-
|
662
|
-
|
738
|
+
@top_margin + LEGEND_MARGIN :
|
739
|
+
@top_margin +
|
663
740
|
TITLE_MARGIN + @title_caps_height +
|
664
741
|
LEGEND_MARGIN
|
665
742
|
|
@@ -695,9 +772,10 @@ protected
|
|
695
772
|
@color_index = 0
|
696
773
|
end
|
697
774
|
|
775
|
+
# Draws a title on the graph.
|
698
776
|
def draw_title
|
699
777
|
return if (@hide_title || @title.nil?)
|
700
|
-
|
778
|
+
|
701
779
|
@d.fill = @font_color
|
702
780
|
@d.font = @font if @font
|
703
781
|
@d.stroke('transparent')
|
@@ -706,15 +784,13 @@ protected
|
|
706
784
|
@d.gravity = NorthGravity
|
707
785
|
@d = @d.annotate_scaled( @base_image,
|
708
786
|
@raw_columns, 1.0,
|
709
|
-
0,
|
787
|
+
0, @top_margin,
|
710
788
|
@title, @scale)
|
711
789
|
end
|
712
790
|
|
713
|
-
##
|
714
791
|
# Draws column labels below graph, centered over x_offset
|
715
|
-
|
792
|
+
#--
|
716
793
|
# TODO Allow WestGravity as an option
|
717
|
-
|
718
794
|
def draw_label(x_offset, index)
|
719
795
|
return if @hide_line_markers
|
720
796
|
|
@@ -736,6 +812,7 @@ protected
|
|
736
812
|
end
|
737
813
|
end
|
738
814
|
|
815
|
+
# Shows an error message because you have no data.
|
739
816
|
def draw_no_data
|
740
817
|
@d.fill = @font_color
|
741
818
|
@d.font = @font if @font
|
@@ -749,11 +826,9 @@ protected
|
|
749
826
|
@no_data_message, @scale)
|
750
827
|
end
|
751
828
|
|
752
|
-
##
|
753
829
|
# Finds the best background to render based on the provided theme options.
|
754
830
|
#
|
755
831
|
# Creates a @base_image to draw on.
|
756
|
-
#
|
757
832
|
def render_background
|
758
833
|
case @theme_options[:background_colors]
|
759
834
|
when Array
|
@@ -765,9 +840,7 @@ protected
|
|
765
840
|
end
|
766
841
|
end
|
767
842
|
|
768
|
-
##
|
769
843
|
# Make a new image at the current size with a solid +color+.
|
770
|
-
|
771
844
|
def render_solid_background(color)
|
772
845
|
Image.new(@columns, @rows) {
|
773
846
|
self.background_color = color
|
@@ -788,7 +861,7 @@ protected
|
|
788
861
|
end
|
789
862
|
image[0]
|
790
863
|
end
|
791
|
-
|
864
|
+
|
792
865
|
# Use with a theme to make a transparent background
|
793
866
|
def render_transparent_background
|
794
867
|
Image.new(@columns, @rows) do
|
@@ -796,20 +869,21 @@ protected
|
|
796
869
|
end
|
797
870
|
end
|
798
871
|
|
872
|
+
# Resets everything to defaults (except data).
|
799
873
|
def reset_themes
|
800
874
|
@color_index = 0
|
801
875
|
@labels_seen = {}
|
802
876
|
@theme_options = {}
|
803
|
-
|
877
|
+
|
804
878
|
@d = Draw.new
|
805
879
|
# Scale down from 800x600 used to calculate drawing.
|
806
880
|
@d = @d.scale(@scale, @scale)
|
807
881
|
end
|
808
882
|
|
809
|
-
def scale(value)
|
883
|
+
def scale(value) # :nodoc:
|
810
884
|
value * @scale
|
811
885
|
end
|
812
|
-
|
886
|
+
|
813
887
|
# Return a comparable fontsize for the current graph.
|
814
888
|
def scale_fontsize(value)
|
815
889
|
new_fontsize = value * @scale
|
@@ -817,32 +891,30 @@ protected
|
|
817
891
|
return new_fontsize
|
818
892
|
end
|
819
893
|
|
820
|
-
def clip_value_if_greater_than(value, max_value)
|
894
|
+
def clip_value_if_greater_than(value, max_value) # :nodoc:
|
821
895
|
(value > max_value) ? max_value : value
|
822
896
|
end
|
823
897
|
|
824
898
|
# Overridden by subclasses such as stacked bar.
|
825
|
-
def larger_than_max?(data_point, index=0)
|
899
|
+
def larger_than_max?(data_point, index=0) # :nodoc:
|
826
900
|
data_point > @maximum_value
|
827
901
|
end
|
828
902
|
|
829
|
-
def less_than_min?(data_point, index=0)
|
903
|
+
def less_than_min?(data_point, index=0) # :nodoc:
|
830
904
|
data_point < @minimum_value
|
831
905
|
end
|
832
906
|
|
833
|
-
##
|
834
907
|
# Overridden by subclasses that need it.
|
835
|
-
def max(data_point, index)
|
908
|
+
def max(data_point, index) # :nodoc:
|
836
909
|
data_point
|
837
910
|
end
|
838
911
|
|
839
|
-
##
|
840
912
|
# Overridden by subclasses that need it.
|
841
|
-
def min(data_point, index)
|
913
|
+
def min(data_point, index) # :nodoc:
|
842
914
|
data_point
|
843
915
|
end
|
844
|
-
|
845
|
-
def significant(inc)
|
916
|
+
|
917
|
+
def significant(inc) # :nodoc:
|
846
918
|
return 1.0 if inc == 0 # Keep from going into infinite loop
|
847
919
|
factor = 1.0
|
848
920
|
while (inc < 10)
|
@@ -863,23 +935,21 @@ protected
|
|
863
935
|
end
|
864
936
|
end
|
865
937
|
|
866
|
-
# Sort with largest overall summed value at front of array
|
867
|
-
#
|
938
|
+
# Sort with largest overall summed value at front of array so it shows up
|
939
|
+
# correctly in the drawn graph.
|
868
940
|
def sort_norm_data
|
869
941
|
@norm_data.sort! { |a,b| sums(b[1]) <=> sums(a[1]) }
|
870
942
|
end
|
871
943
|
|
872
|
-
def sums(data_set)
|
944
|
+
def sums(data_set) # :nodoc:
|
873
945
|
total_sum = 0
|
874
946
|
data_set.collect {|num| total_sum += num.to_f }
|
875
947
|
total_sum
|
876
948
|
end
|
877
949
|
|
878
|
-
##
|
879
950
|
# Used by StackedBar and child classes.
|
880
951
|
#
|
881
952
|
# May need to be moved to the StackedBar class.
|
882
|
-
|
883
953
|
def get_maximum_by_stack
|
884
954
|
# Get sum of each stack
|
885
955
|
max_hash = {}
|
@@ -897,7 +967,7 @@ protected
|
|
897
967
|
@minimum_value = 0
|
898
968
|
end
|
899
969
|
|
900
|
-
def make_stacked
|
970
|
+
def make_stacked # :nodoc:
|
901
971
|
stacked_values = Array.new(@column_count, 0)
|
902
972
|
@data.each do |value_set|
|
903
973
|
value_set[1].each_with_index do |value, index|
|
@@ -908,11 +978,11 @@ protected
|
|
908
978
|
end
|
909
979
|
|
910
980
|
private
|
911
|
-
|
981
|
+
|
912
982
|
# Takes a block and draws it if DEBUG is true.
|
913
983
|
#
|
984
|
+
# Example:
|
914
985
|
# debug { @d.rectangle x1, y1, x2, y2 }
|
915
|
-
#
|
916
986
|
def debug
|
917
987
|
if DEBUG
|
918
988
|
@d = @d.fill 'transparent'
|
@@ -920,7 +990,8 @@ private
|
|
920
990
|
@d = yield
|
921
991
|
end
|
922
992
|
end
|
923
|
-
|
993
|
+
|
994
|
+
# Uses the next color in your color list.
|
924
995
|
def increment_color
|
925
996
|
if @color_index == 0
|
926
997
|
@color_index += 1
|
@@ -937,14 +1008,13 @@ private
|
|
937
1008
|
end
|
938
1009
|
end
|
939
1010
|
|
940
|
-
|
941
|
-
#
|
942
|
-
|
943
|
-
def label(value)
|
1011
|
+
# Return a formatted string representing a number value that should be
|
1012
|
+
# printed as a label.
|
1013
|
+
def label(value)
|
944
1014
|
if (@spread.to_f % @marker_count.to_f == 0) || !@y_axis_increment.nil?
|
945
1015
|
return value.to_i.to_s
|
946
1016
|
end
|
947
|
-
|
1017
|
+
|
948
1018
|
if @spread > 10.0
|
949
1019
|
sprintf("%0i", value)
|
950
1020
|
elsif @spread >= 3.0
|
@@ -954,51 +1024,47 @@ private
|
|
954
1024
|
end
|
955
1025
|
end
|
956
1026
|
|
957
|
-
|
958
|
-
#
|
959
|
-
#
|
960
|
-
# Not scaled since it deals with dimensions that the regular
|
961
|
-
# scaling will handle.
|
1027
|
+
# Returns the height of the capital letter 'X' for the current font and
|
1028
|
+
# size.
|
962
1029
|
#
|
1030
|
+
# Not scaled since it deals with dimensions that the regular scaling will
|
1031
|
+
# handle.
|
963
1032
|
def calculate_caps_height(font_size)
|
964
1033
|
@d.pointsize = font_size
|
965
1034
|
@d.get_type_metrics(@base_image, 'X').height
|
966
1035
|
end
|
967
1036
|
|
968
|
-
##
|
969
1037
|
# Returns the width of a string at this pointsize.
|
970
1038
|
#
|
971
1039
|
# Not scaled since it deals with dimensions that the regular
|
972
1040
|
# scaling will handle.
|
973
|
-
#
|
974
1041
|
def calculate_width(font_size, text)
|
975
1042
|
@d.pointsize = font_size
|
976
1043
|
@d.get_type_metrics(@base_image, text.to_s).width
|
977
1044
|
end
|
978
1045
|
|
979
1046
|
end # Gruff::Base
|
980
|
-
|
1047
|
+
|
981
1048
|
class IncorrectNumberOfDatasetsException < StandardError; end
|
982
|
-
|
983
|
-
end # Gruff
|
984
1049
|
|
1050
|
+
end # Gruff
|
985
1051
|
|
986
1052
|
module Magick
|
987
|
-
|
1053
|
+
|
988
1054
|
class Draw
|
989
|
-
|
990
|
-
# Additional method since Draw.scale doesn't
|
1055
|
+
|
1056
|
+
# Additional method to scale annotation text since Draw.scale doesn't.
|
991
1057
|
def annotate_scaled(img, width, height, x, y, text, scale)
|
992
1058
|
scaled_width = (width * scale) >= 1 ? (width * scale) : 1
|
993
1059
|
scaled_height = (height * scale) >= 1 ? (height * scale) : 1
|
994
|
-
|
995
|
-
self.annotate( img,
|
1060
|
+
|
1061
|
+
self.annotate( img,
|
996
1062
|
scaled_width, scaled_height,
|
997
1063
|
x * scale, y * scale,
|
998
1064
|
text)
|
999
1065
|
end
|
1000
|
-
|
1066
|
+
|
1001
1067
|
end
|
1002
|
-
|
1068
|
+
|
1003
1069
|
end # Magick
|
1004
1070
|
|