gruff 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +7 -0
- data/assets/pc306715.jpg +0 -0
- data/lib/gruff.rb +3 -0
- data/lib/gruff/bar.rb +3 -0
- data/lib/gruff/base.rb +42 -18
- data/lib/gruff/line.rb +16 -4
- data/lib/gruff/photo_bar.rb +92 -0
- data/lib/gruff/side_stacked_bar.rb +119 -0
- data/lib/gruff/stacked_bar.rb +2 -1
- data/rakefile +5 -0
- data/test/area_test.rb +29 -1
- data/test/bar_test.rb +38 -19
- data/test/line_test.rb +90 -8
- data/test/photo_test.rb +44 -0
- data/test/pie_test.rb +18 -0
- data/test/sidestacked_bar_test.rb +88 -0
- data/test/stacked_bar_test.rb +6 -19
- metadata +40 -31
- data/assets/plastik-yellow.png +0 -0
data/CHANGELOG
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
CHANGELOG
|
2
2
|
|
3
|
+
== 0.0.8
|
4
|
+
|
5
|
+
* NEW Sidestacked Bar Graphs. [Alun Eyre]
|
6
|
+
* baseline_value larger than data will now show correctly. [Mike Perham]
|
7
|
+
* hide_dots and hide_lines are now options for line graphs.
|
8
|
+
*
|
9
|
+
|
3
10
|
== 0.0.6
|
4
11
|
|
5
12
|
* Fixed hang when no data is passed.
|
data/assets/pc306715.jpg
ADDED
Binary file
|
data/lib/gruff.rb
CHANGED
@@ -8,3 +8,6 @@ require File.dirname(__FILE__) + '/gruff/bar'
|
|
8
8
|
require File.dirname(__FILE__) + '/gruff/line'
|
9
9
|
require File.dirname(__FILE__) + '/gruff/pie'
|
10
10
|
require File.dirname(__FILE__) + '/gruff/stacked_bar'
|
11
|
+
require File.dirname(__FILE__) + '/gruff/side_stacked_bar'
|
12
|
+
require File.dirname(__FILE__) + '/gruff/photo_bar'
|
13
|
+
|
data/lib/gruff/bar.rb
CHANGED
@@ -20,6 +20,9 @@ class Gruff::Bar < Gruff::Base
|
|
20
20
|
@d = @d.fill current_color
|
21
21
|
|
22
22
|
data_row[1].each_with_index do |data_point, point_index|
|
23
|
+
# TODO Try this out
|
24
|
+
##data_point = 0 if data_point.nil?
|
25
|
+
|
23
26
|
# Use incremented x and scaled y
|
24
27
|
left_x = @graph_left + (@bar_width * (row_index + point_index + ((@data.length - 1) * point_index)))
|
25
28
|
left_y = @graph_top + (@graph_height - data_point * @graph_height) + 1
|
data/lib/gruff/base.rb
CHANGED
@@ -3,9 +3,13 @@
|
|
3
3
|
#
|
4
4
|
# Author:: Geoffrey Grosenbach boss@topfunky.com
|
5
5
|
#
|
6
|
-
# Date:: October 23, 2005
|
6
|
+
# Date Created:: October 23, 2005
|
7
7
|
#
|
8
8
|
#
|
9
|
+
# Other contributors:
|
10
|
+
#
|
11
|
+
# Jarkko Laine, Mike Perham, Andreas Schwarz, Alun Eyre, Guillaume Theoret, and others.
|
12
|
+
#
|
9
13
|
|
10
14
|
require 'RMagick'
|
11
15
|
|
@@ -13,7 +17,7 @@ require 'yaml'
|
|
13
17
|
|
14
18
|
module Gruff
|
15
19
|
|
16
|
-
VERSION = '0.0.
|
20
|
+
VERSION = '0.0.8'
|
17
21
|
|
18
22
|
class Base
|
19
23
|
|
@@ -33,20 +37,28 @@ module Gruff
|
|
33
37
|
# RMagick must be built with the Freetype libraries for this to work properly.
|
34
38
|
attr_accessor :font
|
35
39
|
|
40
|
+
attr_accessor :hide_line_markers, :hide_legend, :hide_title
|
41
|
+
|
36
42
|
# Graph is drawn at 4/3 ratio (800x600, 400x300, etc.).
|
37
43
|
#
|
38
44
|
# Looks for Bitstream Vera as the default font. Expects an environment var of MAGICK_FONT_PATH to be set.
|
39
45
|
# (Uses RMagick's default font otherwise.)
|
40
46
|
def initialize(target_width=800)
|
41
|
-
|
42
|
-
|
47
|
+
|
48
|
+
if not Numeric === target_width
|
49
|
+
geometric_width, geometric_height = target_width.split('x')
|
50
|
+
@columns = geometric_width.to_f
|
51
|
+
@rows = geometric_height.to_f
|
52
|
+
else
|
53
|
+
@columns = target_width.to_f
|
54
|
+
@rows = target_width.to_f * 0.75
|
55
|
+
end
|
43
56
|
|
44
57
|
# Internal for calculations
|
45
58
|
@font = File.expand_path('Vera.ttf', ENV['MAGICK_FONT_PATH'])
|
46
59
|
@marker_pointsize = 21.0
|
47
60
|
@raw_columns = 800.0
|
48
|
-
@raw_rows =
|
49
|
-
@graph_width = 590.0
|
61
|
+
@raw_rows = 800.0 * (@rows/@columns)
|
50
62
|
@column_count = 0
|
51
63
|
@maximum_value = 0
|
52
64
|
@has_data = false
|
@@ -55,9 +67,7 @@ module Gruff
|
|
55
67
|
@labels_seen = Hash.new
|
56
68
|
@scale = @columns / @raw_columns
|
57
69
|
|
58
|
-
@
|
59
|
-
@show_legend = true
|
60
|
-
@show_title = true
|
70
|
+
@hide_line_markers = @hide_legend = @hide_title = false
|
61
71
|
|
62
72
|
reset_themes()
|
63
73
|
theme_keynote()
|
@@ -245,16 +255,28 @@ protected
|
|
245
255
|
end
|
246
256
|
|
247
257
|
def setup_graph_measurements
|
248
|
-
|
249
|
-
|
258
|
+
# TODO Separate horizontal lines from line number labels so they can be shown or hidden independently
|
259
|
+
# TODO Get width of longest left-hand vertical text label and space left margin accordingly
|
260
|
+
unless @hide_line_markers
|
261
|
+
@graph_left = 130.0 # TODO Calculate based on string width of labels
|
262
|
+
@graph_right_margin = 80.0 # TODO see previous line
|
263
|
+
@graph_bottom_margin = 80.0
|
264
|
+
else
|
265
|
+
@graph_left = @graph_right_margin = @graph_bottom_margin = 40
|
266
|
+
end
|
267
|
+
|
268
|
+
@graph_right = @raw_columns - @graph_right_margin
|
269
|
+
|
270
|
+
@graph_width = @raw_columns - @graph_left - @graph_right_margin
|
271
|
+
|
250
272
|
@graph_top = 150.0
|
251
|
-
@graph_bottom = @raw_rows -
|
273
|
+
@graph_bottom = @raw_rows - @graph_bottom_margin
|
252
274
|
@graph_height = @graph_bottom - @graph_top
|
253
275
|
end
|
254
276
|
|
255
277
|
# Draws horizontal background lines and labels
|
256
278
|
def draw_line_markers
|
257
|
-
return
|
279
|
+
return if @hide_line_markers
|
258
280
|
|
259
281
|
# Draw horizontal line markers and annotate with numbers
|
260
282
|
@d = @d.stroke(@marker_color)
|
@@ -285,7 +307,7 @@ protected
|
|
285
307
|
|
286
308
|
# Draws a legend with the names of the datasets matched to the colors used to draw them.
|
287
309
|
def draw_legend
|
288
|
-
return
|
310
|
+
return if @hide_legend
|
289
311
|
|
290
312
|
# Sort norm_data with avg largest values set first (for display)
|
291
313
|
sort_norm_data()
|
@@ -337,7 +359,7 @@ protected
|
|
337
359
|
end
|
338
360
|
|
339
361
|
def draw_title
|
340
|
-
return
|
362
|
+
return if (@hide_title || @title.nil?)
|
341
363
|
|
342
364
|
@d.fill = @marker_color
|
343
365
|
@d.font = @font
|
@@ -354,6 +376,8 @@ protected
|
|
354
376
|
##
|
355
377
|
# Draws column labels below graph, centered over x_offset
|
356
378
|
def draw_label(x_offset, index)
|
379
|
+
return unless @show_line_markers
|
380
|
+
|
357
381
|
if !@labels[index].nil? && @labels_seen[index].nil?
|
358
382
|
@d.fill = @marker_color
|
359
383
|
@d.font = @font
|
@@ -363,7 +387,7 @@ protected
|
|
363
387
|
@d.gravity = CenterGravity
|
364
388
|
@d = @d.annotate_scaled(@base_image,
|
365
389
|
1, 1,
|
366
|
-
x_offset, @raw_rows -
|
390
|
+
x_offset, @raw_rows - (@graph_bottom_margin - 30),
|
367
391
|
@labels[index], @scale)
|
368
392
|
@labels_seen[index] = 1
|
369
393
|
end
|
@@ -392,7 +416,7 @@ protected
|
|
392
416
|
def render_image_background(image_path)
|
393
417
|
image = Image.read(image_path)
|
394
418
|
if @scale != 1.0
|
395
|
-
image[0].resize!(@scale)
|
419
|
+
image[0].resize!(@scale) # TODO Resize with new scale (crop if necessary for wide graph)
|
396
420
|
end
|
397
421
|
image[0]
|
398
422
|
end
|
@@ -441,7 +465,7 @@ protected
|
|
441
465
|
end
|
442
466
|
|
443
467
|
|
444
|
-
#
|
468
|
+
# Round down to significant digits
|
445
469
|
def significant(inc)
|
446
470
|
factor = 1.0
|
447
471
|
while (inc < 10)
|
data/lib/gruff/line.rb
CHANGED
@@ -8,6 +8,8 @@ class Gruff::Line < Gruff::Base
|
|
8
8
|
|
9
9
|
# Color of the baseline
|
10
10
|
attr_accessor :baseline_color
|
11
|
+
|
12
|
+
attr_accessor :hide_dots, :hide_lines
|
11
13
|
|
12
14
|
#
|
13
15
|
# Call with target pixel width of graph (800, 400, 300), and/or 'false' to omit lines (points only).
|
@@ -17,14 +19,18 @@ class Gruff::Line < Gruff::Base
|
|
17
19
|
# g = Gruff::Line.new(400, false) # 400px wide, no lines
|
18
20
|
#
|
19
21
|
# g = Gruff::Line.new(false) # Defaults to 800px wide, no lines
|
22
|
+
#
|
23
|
+
# TODO Remove and go back to normal. Call hide_dots or hide_lines instead
|
20
24
|
def initialize(*args)
|
21
25
|
raise ArgumentError, "Wrong number of arguments" if args.length > 2
|
22
|
-
if args.empty? or not Numeric === args.first then
|
26
|
+
if args.empty? or ((not Numeric === args.first) && (not String === args.first)) then
|
23
27
|
super()
|
24
28
|
else
|
25
29
|
super args.shift
|
26
30
|
end
|
27
|
-
|
31
|
+
|
32
|
+
@hide_dots = false
|
33
|
+
@hide_lines = args.empty? ? false : !args.shift # For backwards compatibility. Use g.hide_lines = true from now on.
|
28
34
|
@baseline_color = 'red'
|
29
35
|
end
|
30
36
|
|
@@ -63,10 +69,10 @@ class Gruff::Line < Gruff::Base
|
|
63
69
|
|
64
70
|
new_y = @graph_top + (@graph_height - data_point * @graph_height)
|
65
71
|
|
66
|
-
if
|
72
|
+
if !@hide_lines and prev_x > 0 and prev_y > 0 then
|
67
73
|
@d = @d.line(prev_x, prev_y, new_x, new_y)
|
68
74
|
end
|
69
|
-
@d = @d.circle(new_x, new_y, new_x - circle_radius, new_y)
|
75
|
+
@d = @d.circle(new_x, new_y, new_x - circle_radius, new_y) unless @hide_dots
|
70
76
|
|
71
77
|
prev_x = new_x
|
72
78
|
prev_y = new_y
|
@@ -79,7 +85,13 @@ class Gruff::Line < Gruff::Base
|
|
79
85
|
end
|
80
86
|
|
81
87
|
def normalize
|
88
|
+
@maximum_value = max(@maximum_value.to_f, @baseline_value.to_f)
|
82
89
|
super
|
83
90
|
@norm_baseline = (@baseline_value.to_f / @maximum_value.to_f) if @baseline_value
|
84
91
|
end
|
92
|
+
|
93
|
+
def max(a, b)
|
94
|
+
(a < b ? b : a)
|
95
|
+
end
|
96
|
+
|
85
97
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/base'
|
2
|
+
|
3
|
+
class Gruff::PhotoBar < Gruff::Base
|
4
|
+
|
5
|
+
# TODO
|
6
|
+
#
|
7
|
+
# define base and cap in yml
|
8
|
+
# allow for image directory to be located elsewhere
|
9
|
+
# more exact measurements for bar heights (go all the way to the bottom of the graph)
|
10
|
+
# option to tile images instead of use a single image
|
11
|
+
# drop base label a few px lower so photo bar graphs can have a base dropping over the lower marker line
|
12
|
+
#
|
13
|
+
|
14
|
+
# The name of a pre-packaged photo-based theme.
|
15
|
+
attr_accessor :theme
|
16
|
+
|
17
|
+
def draw
|
18
|
+
super
|
19
|
+
|
20
|
+
return unless @has_data
|
21
|
+
|
22
|
+
# TODO init_photo_bar_graphics() inside an overriden draw_legend()
|
23
|
+
init_photo_bar_graphics()
|
24
|
+
|
25
|
+
#Draw#define_clip_path()
|
26
|
+
#Draw#clip_path(pathname)
|
27
|
+
#Draw#composite....with bar graph image OverCompositeOp
|
28
|
+
#
|
29
|
+
# See also
|
30
|
+
#
|
31
|
+
# Draw.pattern # define an image to tile as the filling of a draw object
|
32
|
+
#
|
33
|
+
|
34
|
+
# Setup spacing.
|
35
|
+
#
|
36
|
+
# Columns sit side-by-side.
|
37
|
+
spacing_factor = 0.9
|
38
|
+
@bar_width = current_color.columns
|
39
|
+
|
40
|
+
@norm_data.each_with_index do |data_row, row_index|
|
41
|
+
|
42
|
+
data_row[1].each_with_index do |data_point, point_index|
|
43
|
+
data_point = 0 if data_point.nil?
|
44
|
+
# Use incremented x and scaled y
|
45
|
+
left_x = @graph_left + (@bar_width * (row_index + point_index + ((@data.length - 1) * point_index)))
|
46
|
+
left_y = @graph_top + (@graph_height - data_point * @graph_height) + 1
|
47
|
+
right_x = left_x + @bar_width * spacing_factor
|
48
|
+
right_y = @graph_top + @graph_height - 1
|
49
|
+
|
50
|
+
bar_image_width = current_color.columns
|
51
|
+
bar_image_height = right_y.to_f - left_y.to_f
|
52
|
+
|
53
|
+
# Crop to scale for data
|
54
|
+
bar_image = current_color.crop(0, 0, bar_image_width, bar_image_height)
|
55
|
+
|
56
|
+
@d.gravity = NorthWestGravity
|
57
|
+
@d = @d.composite(left_x, left_y, bar_image_width, bar_image_height, bar_image)
|
58
|
+
|
59
|
+
# Calculate center based on bar_width and current row
|
60
|
+
label_center = @graph_left + (@data.length * @bar_width * point_index) + (@data.length * @bar_width / 2.0)
|
61
|
+
draw_label(label_center, point_index)
|
62
|
+
end
|
63
|
+
|
64
|
+
increment_color()
|
65
|
+
end
|
66
|
+
|
67
|
+
@d.draw(@base_image)
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
# Return the chosen theme or the default
|
72
|
+
def theme
|
73
|
+
@theme || 'plastik'
|
74
|
+
end
|
75
|
+
|
76
|
+
protected
|
77
|
+
|
78
|
+
# Sets up colors with a list of images that will be used.
|
79
|
+
# Images should be 340px tall
|
80
|
+
def init_photo_bar_graphics
|
81
|
+
color_list = Array.new
|
82
|
+
theme_dir = File.dirname(__FILE__) + '/../../assets/' + theme
|
83
|
+
|
84
|
+
Dir.open(theme_dir).each do |file|
|
85
|
+
next unless /\.png$/.match(file)
|
86
|
+
color_list << Image.read("#{theme_dir}/#{file}").first
|
87
|
+
end
|
88
|
+
@colors = color_list
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# new gruff graph type added to enable sideways stacking bar charts (basically looks like a x/y
|
2
|
+
# flip of a standard stacking bar chart)
|
3
|
+
#
|
4
|
+
# alun.eyre@googlemail.com
|
5
|
+
#
|
6
|
+
require File.dirname(__FILE__) + '/base'
|
7
|
+
|
8
|
+
class Gruff::SideStackedBar < Gruff::Base
|
9
|
+
|
10
|
+
# instead of base class version, draws vertical background lines and label
|
11
|
+
def draw_line_markers
|
12
|
+
|
13
|
+
return unless @show_line_markers
|
14
|
+
|
15
|
+
# Draw horizontal line markers and annotate with numbers
|
16
|
+
@d = @d.stroke(@marker_color)
|
17
|
+
@d = @d.stroke_width 1
|
18
|
+
number_of_lines = 5
|
19
|
+
|
20
|
+
# TODO Round maximum marker value to a round number like 100, 0.1, 0.5, etc.
|
21
|
+
increment = significant(@maximum_value.to_f / number_of_lines)
|
22
|
+
(0..number_of_lines).each do |index|
|
23
|
+
|
24
|
+
line_diff = (@graph_right - @graph_left) / number_of_lines
|
25
|
+
x = @graph_right - (line_diff * index) - 1
|
26
|
+
@d = @d.line(x, @graph_bottom, x, @graph_top)
|
27
|
+
|
28
|
+
diff = index - number_of_lines
|
29
|
+
marker_label = diff.abs * increment
|
30
|
+
|
31
|
+
@d.fill = @marker_color
|
32
|
+
@d.font = @font
|
33
|
+
@d.stroke = 'transparent'
|
34
|
+
@d.pointsize = scale_fontsize(@marker_pointsize)
|
35
|
+
# @d.gravity = NorthGravity
|
36
|
+
@d = @d.annotate_scaled( @base_image,
|
37
|
+
100, 20,
|
38
|
+
x - (@marker_pointsize/1.5), @graph_bottom + 40,
|
39
|
+
marker_label.to_s, @scale)
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# instead of base class version, modified to enable us to draw on the Y axis instead of X
|
45
|
+
def draw_label(y_offset, index)
|
46
|
+
if !@labels[index].nil? && @labels_seen[index].nil?
|
47
|
+
@d.fill = @marker_color
|
48
|
+
@d.font = @font
|
49
|
+
@d.stroke = 'transparent'
|
50
|
+
@d.font_weight = NormalWeight
|
51
|
+
@d.pointsize = scale_fontsize(@marker_pointsize)
|
52
|
+
@d.gravity = CenterGravity
|
53
|
+
@d = @d.annotate_scaled(@base_image,
|
54
|
+
1, 1,
|
55
|
+
@graph_left / 2, y_offset,
|
56
|
+
@labels[index], @scale)
|
57
|
+
@labels_seen[index] = 1
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def draw
|
62
|
+
super
|
63
|
+
|
64
|
+
return unless @has_data
|
65
|
+
|
66
|
+
# Setup spacing.
|
67
|
+
#
|
68
|
+
# Columns sit stacked.
|
69
|
+
spacing_factor = 0.9
|
70
|
+
|
71
|
+
@bar_width = @graph_height / @column_count.to_f
|
72
|
+
@d = @d.stroke_opacity 0.0
|
73
|
+
height = Array.new(@column_count, 0)
|
74
|
+
length = Array.new(@column_count, @graph_left)
|
75
|
+
|
76
|
+
@norm_data.each_with_index do |data_row, row_index|
|
77
|
+
@d = @d.fill current_color
|
78
|
+
|
79
|
+
data_row[1].each_with_index do |data_point, point_index|
|
80
|
+
|
81
|
+
## using the original calcs from the stacked bar chart to get the difference between
|
82
|
+
## part of the bart chart we wish to stack.
|
83
|
+
temp1 = @graph_left + (@graph_width -
|
84
|
+
data_point * @graph_width -
|
85
|
+
height[point_index]) + 1
|
86
|
+
temp2 = @graph_left + @graph_width - height[point_index] - 1
|
87
|
+
difference = temp2 - temp1
|
88
|
+
|
89
|
+
left_x = length[point_index] #+ 1
|
90
|
+
left_y = @graph_top + (@bar_width * point_index)
|
91
|
+
right_x = left_x + difference
|
92
|
+
right_y = left_y + @bar_width * spacing_factor
|
93
|
+
length[point_index] += difference
|
94
|
+
height[point_index] += (data_point * @graph_width - 2)
|
95
|
+
|
96
|
+
@d = @d.rectangle(left_x, left_y, right_x, right_y)
|
97
|
+
|
98
|
+
# Calculate center based on bar_width and current row
|
99
|
+
label_center = @graph_top + (@bar_width * point_index) + (@bar_width * spacing_factor / 2.0)
|
100
|
+
draw_label(label_center, point_index)
|
101
|
+
end
|
102
|
+
|
103
|
+
increment_color()
|
104
|
+
end
|
105
|
+
|
106
|
+
@d.draw(@base_image)
|
107
|
+
end
|
108
|
+
|
109
|
+
protected
|
110
|
+
|
111
|
+
def larger_than_max?(data_point, index=0)
|
112
|
+
max(data_point, index) > @maximum_value
|
113
|
+
end
|
114
|
+
|
115
|
+
def max(data_point, index)
|
116
|
+
@data.inject(0) {|sum, item| sum + item[1][index]}
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
data/lib/gruff/stacked_bar.rb
CHANGED
@@ -3,6 +3,7 @@ require File.dirname(__FILE__) + '/base'
|
|
3
3
|
|
4
4
|
class Gruff::StackedBar < Gruff::Base
|
5
5
|
|
6
|
+
# Draws a bar graph, but multiple sets are stacked on top of each other.
|
6
7
|
def draw
|
7
8
|
super
|
8
9
|
|
@@ -46,7 +47,7 @@ class Gruff::StackedBar < Gruff::Base
|
|
46
47
|
@d.draw(@base_image)
|
47
48
|
end
|
48
49
|
|
49
|
-
|
50
|
+
protected
|
50
51
|
|
51
52
|
def larger_than_max?(data_point, index=0)
|
52
53
|
max(data_point, index) > @maximum_value
|
data/rakefile
CHANGED
@@ -21,6 +21,11 @@ RUBY_FORGE_USER = "topfunky"
|
|
21
21
|
desc "Default Task"
|
22
22
|
task :default => [ :test ]
|
23
23
|
|
24
|
+
desc "Clean images generated by tests"
|
25
|
+
task :clean do
|
26
|
+
rm FileList['test/output/*.png']
|
27
|
+
end
|
28
|
+
|
24
29
|
# Run the unit tests
|
25
30
|
Rake::TestTask.new { |t|
|
26
31
|
t.libs << "test"
|
data/test/area_test.rb
CHANGED
@@ -17,6 +17,17 @@ class TestGruffArea < Test::Unit::TestCase
|
|
17
17
|
[:Philip, [90, 34, 23, 12, 78, 89, 98, 88]],
|
18
18
|
["Arthur", [5, 10, 13, 11, 6, 16, 22, 32]],
|
19
19
|
]
|
20
|
+
@sample_labels = {
|
21
|
+
0 => '5/6',
|
22
|
+
1 => '5/15',
|
23
|
+
2 => '5/24',
|
24
|
+
3 => '5/30',
|
25
|
+
4 => '6/4',
|
26
|
+
5 => '6/12',
|
27
|
+
6 => '6/21',
|
28
|
+
7 => '6/28',
|
29
|
+
}
|
30
|
+
|
20
31
|
end
|
21
32
|
|
22
33
|
def test_area_graph
|
@@ -105,6 +116,23 @@ class TestGruffArea < Test::Unit::TestCase
|
|
105
116
|
# Default theme
|
106
117
|
g.write("test/output/area_tiny.png")
|
107
118
|
end
|
119
|
+
|
120
|
+
def test_wide
|
121
|
+
g = setup_basic_graph('800x400')
|
122
|
+
g.title = "Area Wide"
|
123
|
+
g.write("test/output/area_wide.png")
|
124
|
+
end
|
125
|
+
|
126
|
+
protected
|
127
|
+
|
128
|
+
def setup_basic_graph(size=800)
|
129
|
+
g = Gruff::Area.new(size)
|
130
|
+
g.title = "My Graph Title"
|
131
|
+
g.labels = @sample_labels
|
132
|
+
@datasets.each do |data|
|
133
|
+
g.data(data[0], data[1])
|
134
|
+
end
|
135
|
+
return g
|
136
|
+
end
|
108
137
|
|
109
138
|
end
|
110
|
-
|
data/test/bar_test.rb
CHANGED
@@ -61,23 +61,45 @@ class TestGruffBar < Test::Unit::TestCase
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def test_bar_image_bg
|
64
|
-
g =
|
65
|
-
g.title = "
|
66
|
-
g.labels = {
|
67
|
-
0 => '5/6',
|
68
|
-
1 => '5/15',
|
69
|
-
2 => '5/24',
|
70
|
-
3 => '5/30',
|
71
|
-
}
|
72
|
-
@datasets.each do |data|
|
73
|
-
g.data(data[0], data[1])
|
74
|
-
end
|
75
|
-
|
64
|
+
g = setup_basic_graph()
|
65
|
+
g.title = "With Image Background"
|
76
66
|
g.theme_image_based
|
77
67
|
g.write("test/output/bar_image.png")
|
78
68
|
|
79
|
-
g =
|
80
|
-
g.title = "
|
69
|
+
g = setup_basic_graph(400)
|
70
|
+
g.title = "With Image Background Small"
|
71
|
+
g.theme_image_based
|
72
|
+
g.write("test/output/bar_image_small.png")
|
73
|
+
|
74
|
+
g = setup_basic_graph('800x400')
|
75
|
+
g.title = "With Image Background Small"
|
76
|
+
g.theme_image_based
|
77
|
+
g.write("test/output/bar_image_wide.png")
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_no_line_markers
|
81
|
+
g = setup_basic_graph(400)
|
82
|
+
g.title = "No Line Markers"
|
83
|
+
g.hide_line_markers = true
|
84
|
+
g.write("test/output/bar_no_line_markers.png")
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_wide_graph
|
88
|
+
g = setup_basic_graph('800x400')
|
89
|
+
g.title = "Wide Graph"
|
90
|
+
g.write("test/output/bar_wide_graph.png")
|
91
|
+
|
92
|
+
g = setup_basic_graph('400x200')
|
93
|
+
g.title = "Wide Graph Small"
|
94
|
+
g.write("test/output/bar_wide_graph_small.png")
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
protected
|
99
|
+
|
100
|
+
def setup_basic_graph(size=800)
|
101
|
+
g = Gruff::Bar.new(size)
|
102
|
+
g.title = "My Bar Graph"
|
81
103
|
g.labels = {
|
82
104
|
0 => '5/6',
|
83
105
|
1 => '5/15',
|
@@ -87,10 +109,7 @@ class TestGruffBar < Test::Unit::TestCase
|
|
87
109
|
@datasets.each do |data|
|
88
110
|
g.data(data[0], data[1])
|
89
111
|
end
|
90
|
-
|
91
|
-
g.theme_image_based
|
92
|
-
g.write("test/output/bar_image_small.png")
|
93
|
-
|
112
|
+
g
|
94
113
|
end
|
95
114
|
|
96
115
|
|
@@ -112,6 +131,6 @@ class Gruff::Base
|
|
112
131
|
|
113
132
|
@marker_color = 'white'
|
114
133
|
|
115
|
-
@base_image = render_image_background('assets/
|
134
|
+
@base_image = render_image_background('assets/pc306715.jpg')
|
116
135
|
end
|
117
136
|
end
|
data/test/line_test.rb
CHANGED
@@ -19,6 +19,17 @@ class TestGruffLine < Test::Unit::TestCase
|
|
19
19
|
[:Philip, [90, 34, 23, 12, 78, 89, 98, 88]],
|
20
20
|
["Arthur", [5, 10, 13, 11, 6, 16, 22, 32]],
|
21
21
|
]
|
22
|
+
|
23
|
+
@sample_labels = {
|
24
|
+
0 => '5/6',
|
25
|
+
1 => '5/15',
|
26
|
+
2 => '5/24',
|
27
|
+
3 => '5/30',
|
28
|
+
4 => '6/4',
|
29
|
+
5 => '6/12',
|
30
|
+
6 => '6/21',
|
31
|
+
7 => '6/28',
|
32
|
+
}
|
22
33
|
end
|
23
34
|
|
24
35
|
def test_line_graph_with_themes
|
@@ -103,10 +114,10 @@ class TestGruffLine < Test::Unit::TestCase
|
|
103
114
|
def test_similar_high_end_values
|
104
115
|
g = Gruff::Line.new
|
105
116
|
g.title = "Similar High End Values Test"
|
106
|
-
g.data('similar points',
|
117
|
+
g.data('similar points', %w(29.43 29.459 29.498 29.53 29.548 29.589 29.619 29.66 29.689 29.74 29.769 29.79 29.808 29.828 29.849 29.878).collect {|i| i.to_f} )
|
107
118
|
|
108
119
|
# Default theme
|
109
|
-
g.write("test/output/
|
120
|
+
g.write("test/output/line_similar_high_end_values.png")
|
110
121
|
end
|
111
122
|
|
112
123
|
|
@@ -244,6 +255,72 @@ class TestGruffLine < Test::Unit::TestCase
|
|
244
255
|
g.write("test/output/line_some_nil_points.png")
|
245
256
|
end
|
246
257
|
|
258
|
+
def test_no_title
|
259
|
+
g = Gruff::Line.new(400)
|
260
|
+
g.labels = @sample_labels
|
261
|
+
@datasets.each do |data|
|
262
|
+
g.data(data[0], data[1])
|
263
|
+
end
|
264
|
+
|
265
|
+
g.write("test/output/line_no_title.png")
|
266
|
+
end
|
267
|
+
|
268
|
+
def test_no_line_markers
|
269
|
+
g = setup_basic_graph(400)
|
270
|
+
g.title = "No Line Markers"
|
271
|
+
g.hide_line_markers = true
|
272
|
+
g.write("test/output/line_no_line_markers.png")
|
273
|
+
end
|
274
|
+
|
275
|
+
def test_no_legend
|
276
|
+
g = setup_basic_graph(400)
|
277
|
+
g.title = "No Legend"
|
278
|
+
g.hide_legend = true
|
279
|
+
g.write("test/output/line_no_legend.png")
|
280
|
+
end
|
281
|
+
|
282
|
+
def test_nothing_but_the_graph
|
283
|
+
g = setup_basic_graph(400)
|
284
|
+
g.title = "THIS TITLE SHOULD NOT DISPLAY!!!"
|
285
|
+
g.hide_line_markers = true
|
286
|
+
g.hide_legend = true
|
287
|
+
g.hide_title = true
|
288
|
+
g.write("test/output/line_nothing_but_the_graph.png")
|
289
|
+
end
|
290
|
+
|
291
|
+
def test_baseline_larger_than_data
|
292
|
+
g = setup_basic_graph(400)
|
293
|
+
g.title = "Baseline Larger Than Data"
|
294
|
+
g.baseline_value = 150
|
295
|
+
g.write("test/output/line_large_baseline.png")
|
296
|
+
end
|
297
|
+
|
298
|
+
|
299
|
+
def test_hide_dots
|
300
|
+
g = setup_basic_graph(400)
|
301
|
+
g.title = "Hide Dots"
|
302
|
+
g.hide_dots = true
|
303
|
+
g.write("test/output/line_hide_dots.png")
|
304
|
+
end
|
305
|
+
|
306
|
+
def test_hide_lines
|
307
|
+
g = setup_basic_graph(400)
|
308
|
+
g.title = "Hide Lines"
|
309
|
+
g.hide_lines = true
|
310
|
+
g.write("test/output/line_hide_lines.png")
|
311
|
+
end
|
312
|
+
|
313
|
+
def test_wide_graph
|
314
|
+
g = setup_basic_graph('800x400')
|
315
|
+
g.title = "Wide Graph"
|
316
|
+
g.write("test/output/line_wide_graph.png")
|
317
|
+
|
318
|
+
g = setup_basic_graph('400x200')
|
319
|
+
g.title = "Wide Graph Small"
|
320
|
+
g.write("test/output/line_wide_graph_small.png")
|
321
|
+
end
|
322
|
+
|
323
|
+
|
247
324
|
protected
|
248
325
|
|
249
326
|
def line_graph_with_themes(size=nil)
|
@@ -254,12 +331,7 @@ protected
|
|
254
331
|
end
|
255
332
|
|
256
333
|
g.title = "Multi-Line Graph Test #{size}"
|
257
|
-
g.labels =
|
258
|
-
0 => '5/6',
|
259
|
-
2 => '5/15',
|
260
|
-
4 => '5/24',
|
261
|
-
6 => '5/30',
|
262
|
-
}
|
334
|
+
g.labels = @sample_labels
|
263
335
|
@datasets.each do |data|
|
264
336
|
g.data(data[0], data[1])
|
265
337
|
end
|
@@ -278,6 +350,16 @@ protected
|
|
278
350
|
g.theme_odeo
|
279
351
|
g.write("test/output/line_theme_odeo_#{size}.png")
|
280
352
|
end
|
353
|
+
|
354
|
+
def setup_basic_graph(size=800)
|
355
|
+
g = Gruff::Line.new(size)
|
356
|
+
g.title = "My Graph Title"
|
357
|
+
g.labels = @sample_labels
|
358
|
+
@datasets.each do |data|
|
359
|
+
g.data(data[0], data[1])
|
360
|
+
end
|
361
|
+
return g
|
362
|
+
end
|
281
363
|
|
282
364
|
end
|
283
365
|
|
data/test/photo_test.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
$:.unshift(File.dirname(__FILE__) + "/../lib/")
|
4
|
+
|
5
|
+
require 'test/unit'
|
6
|
+
require 'gruff'
|
7
|
+
|
8
|
+
class TestGruffPhotoBar < Test::Unit::TestCase
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@datasets = [
|
12
|
+
[:Jimmy, [25, 36, 86, 39]],
|
13
|
+
[:Charles, [80, 54, 67, 54]],
|
14
|
+
# [:Charity, [0, nil, 100, 90]],
|
15
|
+
]
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_bar_graph
|
19
|
+
bar_graph_sized
|
20
|
+
bar_graph_sized(400)
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def bar_graph_sized(size=800)
|
27
|
+
g = Gruff::PhotoBar.new(size)
|
28
|
+
g.title = "Photo Bar Graph Test #{size}px"
|
29
|
+
g.labels = {
|
30
|
+
0 => '5/6',
|
31
|
+
1 => '5/15',
|
32
|
+
2 => '5/24',
|
33
|
+
3 => '5/30',
|
34
|
+
}
|
35
|
+
@datasets.each do |data|
|
36
|
+
g.data(*data)
|
37
|
+
end
|
38
|
+
|
39
|
+
g.theme = 'plastik'
|
40
|
+
|
41
|
+
g.write("test/output/photo_plastik_#{size}.png")
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
data/test/pie_test.rb
CHANGED
@@ -17,6 +17,7 @@ class TestGruffPie < Test::Unit::TestCase
|
|
17
17
|
[:Philip, [90]],
|
18
18
|
["Arthur", [5]],
|
19
19
|
]
|
20
|
+
|
20
21
|
end
|
21
22
|
|
22
23
|
def test_pie_graph
|
@@ -79,5 +80,22 @@ class TestGruffPie < Test::Unit::TestCase
|
|
79
80
|
g.write("test/output/pie_tiny.png")
|
80
81
|
end
|
81
82
|
=end
|
83
|
+
|
84
|
+
def test_wide
|
85
|
+
g = setup_basic_graph('800x400')
|
86
|
+
g.title = "Wide Pie"
|
87
|
+
g.write("test/output/pie_wide.png")
|
88
|
+
end
|
89
|
+
|
90
|
+
protected
|
91
|
+
|
92
|
+
def setup_basic_graph(size=800)
|
93
|
+
g = Gruff::Pie.new(size)
|
94
|
+
g.title = "My Graph Title"
|
95
|
+
@datasets.each do |data|
|
96
|
+
g.data(data[0], data[1])
|
97
|
+
end
|
98
|
+
return g
|
99
|
+
end
|
82
100
|
|
83
101
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
$:.unshift(File.dirname(__FILE__) + "/../lib/")
|
4
|
+
#$:.unshift File.dirname(__FILE__) + "/fixtures/helpers"
|
5
|
+
|
6
|
+
require 'test/unit'
|
7
|
+
require 'gruff'
|
8
|
+
|
9
|
+
class TestGruffSideSideStackedBar < Test::Unit::TestCase
|
10
|
+
|
11
|
+
# TODO Delete old output files once when starting tests
|
12
|
+
|
13
|
+
def setup
|
14
|
+
@datasets = [
|
15
|
+
[:Jimmy, [25, 36, 86, 39]],
|
16
|
+
[:Charles, [80, 54, 67, 54]],
|
17
|
+
[:Julie, [22, 29, 35, 38]],
|
18
|
+
#[:Jane, [95, 95, 95, 90, 85, 80, 88, 100]],
|
19
|
+
#[:Philip, [90, 34, 23, 12, 78, 89, 98, 88]],
|
20
|
+
#["Arthur", [5, 10, 13, 11, 6, 16, 22, 32]],
|
21
|
+
]
|
22
|
+
@sample_labels = {
|
23
|
+
0 => '5/6',
|
24
|
+
1 => '5/15',
|
25
|
+
2 => '5/24'
|
26
|
+
}
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_bar_graph
|
31
|
+
g = Gruff::SideStackedBar.new
|
32
|
+
g.title = "Visual Stacked Bar Graph Test"
|
33
|
+
g.labels = {
|
34
|
+
0 => '5/6',
|
35
|
+
1 => '5/15',
|
36
|
+
2 => '5/24',
|
37
|
+
3 => '5/30',
|
38
|
+
}
|
39
|
+
@datasets.each do |data|
|
40
|
+
g.data(data[0], data[1])
|
41
|
+
end
|
42
|
+
|
43
|
+
g.write("test/output/side_stacked_bar_keynote.png")
|
44
|
+
|
45
|
+
g.theme_rails_keynote
|
46
|
+
g.write("test/output/side_stacked_bar_rails_keynote.png")
|
47
|
+
|
48
|
+
g.theme_odeo
|
49
|
+
g.write("test/output/side_stacked_bar_odeo.png")
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def test_bar_graph_small
|
54
|
+
g = Gruff::SideStackedBar.new(400)
|
55
|
+
g.title = "Visual Stacked Bar Graph Test"
|
56
|
+
g.labels = {
|
57
|
+
0 => '5/6',
|
58
|
+
1 => '5/15',
|
59
|
+
2 => '5/24',
|
60
|
+
3 => '5/30',
|
61
|
+
}
|
62
|
+
@datasets.each do |data|
|
63
|
+
g.data(data[0], data[1])
|
64
|
+
end
|
65
|
+
|
66
|
+
g.write("test/output/side_stacked_bar_keynote_small.png")
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_wide
|
70
|
+
g = setup_basic_graph('800x400')
|
71
|
+
g.title = "Wide SSBar"
|
72
|
+
g.write("test/output/side_stacked_bar_wide.png")
|
73
|
+
end
|
74
|
+
|
75
|
+
protected
|
76
|
+
|
77
|
+
def setup_basic_graph(size=800)
|
78
|
+
g = Gruff::SideStackedBar.new(size)
|
79
|
+
g.title = "My Graph Title"
|
80
|
+
g.labels = @sample_labels
|
81
|
+
@datasets.each do |data|
|
82
|
+
g.data(data[0], data[1])
|
83
|
+
end
|
84
|
+
return g
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
data/test/stacked_bar_test.rb
CHANGED
@@ -19,6 +19,12 @@ class TestGruffStackedBar < Test::Unit::TestCase
|
|
19
19
|
#[:Philip, [90, 34, 23, 12, 78, 89, 98, 88]],
|
20
20
|
#["Arthur", [5, 10, 13, 11, 6, 16, 22, 32]],
|
21
21
|
]
|
22
|
+
@sample_labels = {
|
23
|
+
0 => '5/6',
|
24
|
+
1 => '5/15',
|
25
|
+
2 => '5/24'
|
26
|
+
}
|
27
|
+
|
22
28
|
end
|
23
29
|
|
24
30
|
def test_bar_graph
|
@@ -95,22 +101,3 @@ class TestGruffStackedBar < Test::Unit::TestCase
|
|
95
101
|
|
96
102
|
|
97
103
|
end
|
98
|
-
|
99
|
-
class Gruff::Base
|
100
|
-
def theme_image_based
|
101
|
-
reset_themes()
|
102
|
-
# Colors
|
103
|
-
@green = '#00ff00'
|
104
|
-
@grey = '#333333'
|
105
|
-
@orange = '#ff5d00'
|
106
|
-
@red = '#f61100'
|
107
|
-
@white = 'white'
|
108
|
-
@light_grey = '#999999'
|
109
|
-
@black = 'black'
|
110
|
-
@colors = [@green, @grey, @orange, @red, @white, @light_grey, @black]
|
111
|
-
|
112
|
-
@marker_color = 'white'
|
113
|
-
|
114
|
-
@base_image = render_image_background('assets/bubble.png')
|
115
|
-
end
|
116
|
-
end
|
metadata
CHANGED
@@ -3,11 +3,11 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: gruff
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.0.
|
7
|
-
date: 2005-12-
|
6
|
+
version: 0.0.8
|
7
|
+
date: 2005-12-31 00:00:00 -08:00
|
8
8
|
summary: Beautiful graphs for one or multiple datasets.
|
9
9
|
require_paths:
|
10
|
-
|
10
|
+
- lib
|
11
11
|
email: boss@topfunky.com
|
12
12
|
homepage: http://www.topfunky.com
|
13
13
|
rubyforge_project: gruff
|
@@ -18,43 +18,52 @@ bindir: bin
|
|
18
18
|
has_rdoc: true
|
19
19
|
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
20
|
requirements:
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
version: 0.0.0
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
25
24
|
version:
|
26
25
|
platform: ruby
|
27
26
|
signing_key:
|
28
27
|
cert_chain:
|
29
28
|
authors:
|
30
|
-
|
29
|
+
- Geoffrey Grosenbach
|
31
30
|
files:
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
31
|
+
- rakefile
|
32
|
+
- README
|
33
|
+
- CHANGELOG
|
34
|
+
- MIT-LICENSE
|
35
|
+
- lib/gruff
|
36
|
+
- lib/gruff.rb
|
37
|
+
- lib/gruff/area.rb
|
38
|
+
- lib/gruff/bar.rb
|
39
|
+
- lib/gruff/base.rb
|
40
|
+
- lib/gruff/line.rb
|
41
|
+
- lib/gruff/photo_bar.rb
|
42
|
+
- lib/gruff/pie.rb
|
43
|
+
- lib/gruff/side_stacked_bar.rb
|
44
|
+
- lib/gruff/stacked_bar.rb
|
45
|
+
- assets/bubble.png
|
46
|
+
- assets/pc306715.jpg
|
47
|
+
- assets/plastik
|
48
|
+
- test/area_test.rb
|
49
|
+
- test/bar_test.rb
|
50
|
+
- test/line_test.rb
|
51
|
+
- test/output
|
52
|
+
- test/photo_test.rb
|
53
|
+
- test/pie_test.rb
|
54
|
+
- test/sidestacked_bar_test.rb
|
55
|
+
- test/stacked_bar_test.rb
|
53
56
|
test_files: []
|
57
|
+
|
54
58
|
rdoc_options: []
|
59
|
+
|
55
60
|
extra_rdoc_files: []
|
61
|
+
|
56
62
|
executables: []
|
63
|
+
|
57
64
|
extensions: []
|
65
|
+
|
58
66
|
requirements:
|
59
|
-
|
60
|
-
dependencies: []
|
67
|
+
- none
|
68
|
+
dependencies: []
|
69
|
+
|
data/assets/plastik-yellow.png
DELETED
Binary file
|