gruff 0.2.8 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|