gruff 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +10 -1
- data/assets/bubble.png +0 -0
- data/lib/gruff/area.rb +51 -9
- data/lib/gruff/bar.rb +10 -30
- data/lib/gruff/base.rb +115 -23
- data/lib/gruff/line.rb +4 -22
- data/lib/gruff/pie.rb +84 -7
- data/rakefile +1 -1
- data/test/area_test.rb +110 -0
- data/test/bar_test.rb +60 -19
- data/test/line_test.rb +26 -0
- data/test/pie_test.rb +83 -0
- metadata +5 -2
data/CHANGELOG
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
CHANGELOG
|
2
2
|
|
3
|
+
== 0.0.4
|
4
|
+
|
5
|
+
* Added bar graphs
|
6
|
+
* Added area graphs
|
7
|
+
* Added pie graphs
|
8
|
+
* Added render_image_background for using images as background on a theme
|
9
|
+
* Fixed small size legend centering issue
|
10
|
+
* Added initial line marker rounding to significant digits (Christian Winkler)
|
11
|
+
* Line graphs line width is scaled with number of points being drawn (Christian Winkler)
|
12
|
+
|
3
13
|
== 0.0.3
|
4
14
|
|
5
15
|
* Added option to draw line graphs without the lines (points only), thanks to Eric Hodel
|
@@ -11,7 +21,6 @@ CHANGELOG
|
|
11
21
|
* Added bar graphs (initial functionality...will be enhanced)
|
12
22
|
* Removed rendered test output from gem
|
13
23
|
|
14
|
-
|
15
24
|
== 0.0.1
|
16
25
|
|
17
26
|
* Initial release.
|
data/assets/bubble.png
ADDED
Binary file
|
data/lib/gruff/area.rb
CHANGED
@@ -1,15 +1,57 @@
|
|
1
1
|
|
2
2
|
require 'gruff/base'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
4
|
+
class Gruff::Area < Gruff::Base
|
5
|
+
|
6
|
+
def draw
|
7
|
+
super
|
8
|
+
|
9
|
+
@x_increment = @graph_width / (@column_count - 1).to_f
|
10
|
+
@d = @d.stroke 'transparent'
|
11
|
+
|
12
|
+
@norm_data.each do |data_row|
|
13
|
+
poly_points = Array.new
|
14
|
+
prev_x = prev_y = 0.0
|
15
|
+
@d = @d.fill current_color
|
16
|
+
|
17
|
+
data_row[1].each_with_index do |data_point, index|
|
18
|
+
# Use incremented x and scaled y
|
19
|
+
new_x = @graph_left + (@x_increment * index)
|
20
|
+
new_y = @graph_top + (@graph_height - data_point * @graph_height)
|
21
|
+
|
22
|
+
if prev_x > 0 and prev_y > 0 then
|
23
|
+
poly_points << new_x
|
24
|
+
poly_points << new_y
|
25
|
+
|
26
|
+
#@d = @d.polyline(prev_x, prev_y, new_x, new_y)
|
27
|
+
else
|
28
|
+
poly_points << @graph_left
|
29
|
+
poly_points << @graph_bottom - 1
|
30
|
+
poly_points << new_x
|
31
|
+
poly_points << new_y
|
32
|
+
|
33
|
+
#@d = @d.polyline(@graph_left, @graph_bottom, new_x, new_y)
|
34
|
+
end
|
35
|
+
|
36
|
+
draw_label(new_x, index)
|
37
|
+
|
38
|
+
prev_x = new_x
|
39
|
+
prev_y = new_y
|
40
|
+
end
|
41
|
+
|
42
|
+
# Add closing points, draw polygon
|
43
|
+
poly_points << @graph_right
|
44
|
+
poly_points << @graph_bottom - 1
|
45
|
+
poly_points << @graph_left
|
46
|
+
poly_points << @graph_bottom - 1
|
47
|
+
|
48
|
+
@d = @d.polyline(*poly_points)
|
49
|
+
|
50
|
+
increment_color()
|
12
51
|
end
|
13
52
|
|
53
|
+
@d.draw(@base_image)
|
14
54
|
end
|
15
|
-
|
55
|
+
|
56
|
+
|
57
|
+
end
|
data/lib/gruff/bar.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
|
2
2
|
require 'gruff/base'
|
3
3
|
|
4
|
-
|
5
|
-
class Bar < Base
|
4
|
+
class Gruff::Bar < Gruff::Base
|
6
5
|
|
7
6
|
def draw
|
8
7
|
super
|
@@ -10,6 +9,7 @@ module Gruff
|
|
10
9
|
# Setup spacing.
|
11
10
|
#
|
12
11
|
# Columns sit side-by-side.
|
12
|
+
spacing_factor = 0.9
|
13
13
|
@bar_width = @graph_width / (@column_count * @data.length).to_f
|
14
14
|
|
15
15
|
@d = @d.stroke_opacity 0.0
|
@@ -20,41 +20,21 @@ module Gruff
|
|
20
20
|
data_row[1].each_with_index do |data_point, point_index|
|
21
21
|
# Use incremented x and scaled y
|
22
22
|
left_x = @graph_left + (@bar_width * (row_index + point_index + ((@data.length - 1) * point_index)))
|
23
|
-
left_y = @graph_top + (@graph_height - data_point * @graph_height)
|
24
|
-
right_x = left_x + @bar_width
|
23
|
+
left_y = @graph_top + (@graph_height - data_point * @graph_height) + 1
|
24
|
+
right_x = left_x + @bar_width * spacing_factor
|
25
25
|
right_y = @graph_top + @graph_height - 1
|
26
26
|
|
27
27
|
@d = @d.rectangle(left_x, left_y, right_x, right_y)
|
28
|
-
|
29
|
-
#
|
30
|
-
|
28
|
+
|
29
|
+
# Calculate center based on bar_width and current row
|
30
|
+
label_center = @graph_left + (@data.length * @bar_width * point_index) + (@data.length * @bar_width / 2.0)
|
31
|
+
draw_label(label_center, point_index)
|
31
32
|
end
|
32
|
-
|
33
|
+
|
33
34
|
increment_color()
|
34
35
|
end
|
35
36
|
|
36
37
|
@d.draw(@base_image)
|
37
38
|
end
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
# Draws column labels below graph, centered under entire block
|
42
|
-
def draw_label(x_offset, index)
|
43
|
-
# TODO
|
44
|
-
if !@labels[index].nil? && @labels_seen[index].nil?
|
45
|
-
@d.fill = @marker_color
|
46
|
-
@d.font = @font
|
47
|
-
@d.stroke = 'transparent'
|
48
|
-
@d.font_weight = NormalWeight
|
49
|
-
@d.pointsize = scale_fontsize(@marker_pointsize)
|
50
|
-
@d.gravity = CenterGravity
|
51
|
-
@d = @d.annotate_scaled(@base_image,
|
52
|
-
1, 1,
|
53
|
-
x_offset, @raw_rows - 80,
|
54
|
-
@labels[index], @scale)
|
55
|
-
@labels_seen[index] = 1
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
end
|
60
|
-
end
|
40
|
+
end
|
data/lib/gruff/base.rb
CHANGED
@@ -13,9 +13,11 @@ rescue LoadError
|
|
13
13
|
require 'RMagick' # capitalized on Windows
|
14
14
|
end
|
15
15
|
|
16
|
+
require 'yaml'
|
17
|
+
|
16
18
|
module Gruff
|
17
19
|
|
18
|
-
VERSION = '0.0.
|
20
|
+
VERSION = '0.0.4'
|
19
21
|
|
20
22
|
class Base
|
21
23
|
|
@@ -48,6 +50,7 @@ module Gruff
|
|
48
50
|
@marker_pointsize = 21.0
|
49
51
|
@raw_columns = 800.0
|
50
52
|
@raw_rows = 600.0
|
53
|
+
@graph_width = 590.0
|
51
54
|
@column_count = 0
|
52
55
|
@maximum_value = 0
|
53
56
|
@data = Array.new
|
@@ -55,6 +58,10 @@ module Gruff
|
|
55
58
|
@labels_seen = Hash.new
|
56
59
|
@scale = @columns / @raw_columns
|
57
60
|
|
61
|
+
@show_line_markers = true
|
62
|
+
@show_legend = true
|
63
|
+
@show_title = true
|
64
|
+
|
58
65
|
reset_themes()
|
59
66
|
theme_keynote()
|
60
67
|
end
|
@@ -179,7 +186,7 @@ module Gruff
|
|
179
186
|
def to_blob(fileformat='PNG')
|
180
187
|
draw()
|
181
188
|
return @base_image.to_blob do
|
182
|
-
self.format=fileformat
|
189
|
+
self.format = fileformat
|
183
190
|
end
|
184
191
|
end
|
185
192
|
|
@@ -201,6 +208,7 @@ protected
|
|
201
208
|
# - title
|
202
209
|
def setup_drawing
|
203
210
|
normalize()
|
211
|
+
setup_graph_measurements()
|
204
212
|
|
205
213
|
draw_line_markers()
|
206
214
|
draw_legend()
|
@@ -209,35 +217,44 @@ protected
|
|
209
217
|
|
210
218
|
# Make copy of data with values scaled between 0-100
|
211
219
|
def normalize
|
212
|
-
@norm_data
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
220
|
+
if @norm_data.nil?
|
221
|
+
@norm_data = Array.new
|
222
|
+
@data.each do |data_row|
|
223
|
+
norm_data_points = Array.new
|
224
|
+
data_row[1].each do |data_point|
|
225
|
+
norm_data_points << (data_point.to_f/@maximum_value.to_f)
|
226
|
+
end
|
227
|
+
@norm_data << [data_row[0], norm_data_points]
|
217
228
|
end
|
218
|
-
@norm_data << [data_row[0], norm_data_points]
|
219
229
|
end
|
220
230
|
end
|
221
231
|
|
222
|
-
|
223
|
-
def draw_line_markers
|
232
|
+
def setup_graph_measurements
|
224
233
|
@graph_left = 130.0
|
225
|
-
@graph_right = @
|
234
|
+
@graph_right = @graph_left + @graph_width
|
226
235
|
@graph_top = 150.0
|
227
236
|
@graph_bottom = @raw_rows - 110.0
|
228
237
|
@graph_height = @graph_bottom - @graph_top
|
229
|
-
|
238
|
+
end
|
239
|
+
|
240
|
+
# Draws horizontal background lines and labels
|
241
|
+
def draw_line_markers
|
242
|
+
return unless @show_line_markers
|
230
243
|
|
231
244
|
# Draw horizontal line markers and annotate with numbers
|
232
245
|
@d = @d.stroke(@marker_color)
|
233
246
|
@d = @d.stroke_width 1
|
234
|
-
|
235
|
-
|
236
|
-
|
247
|
+
number_of_lines = 4
|
248
|
+
|
249
|
+
# TODO Round maximum marker value to a round number like 100, 0.1, 0.5, etc.
|
250
|
+
increment = significant(@maximum_value.to_f / number_of_lines)
|
251
|
+
inc_graph = @graph_height.to_f / (@maximum_value.to_f / increment)
|
252
|
+
|
253
|
+
(0..number_of_lines).each do |index|
|
254
|
+
y = @graph_top + @graph_height - index.to_f * inc_graph
|
237
255
|
@d = @d.line(@graph_left, y, @graph_right, y)
|
238
|
-
|
239
|
-
marker_label =
|
240
|
-
marker_label = @maximum_value.to_f * (index.to_f/4.to_f) if index > 0
|
256
|
+
|
257
|
+
marker_label = index * increment
|
241
258
|
|
242
259
|
@d.fill = @marker_color
|
243
260
|
@d.font = @font
|
@@ -253,15 +270,24 @@ protected
|
|
253
270
|
|
254
271
|
# Draws a legend with the names of the datasets matched to the colors used to draw them.
|
255
272
|
def draw_legend
|
273
|
+
return unless @show_legend
|
274
|
+
|
256
275
|
@color_index = 0
|
257
|
-
@legend_labels = @
|
276
|
+
@legend_labels = @norm_data.collect {|item| item[0] }
|
258
277
|
|
278
|
+
# Sort norm_data with avg largest values set first (for display)
|
279
|
+
sort_norm_data()
|
280
|
+
|
259
281
|
legend_square_width = 20 # small square with color of this item
|
260
282
|
|
283
|
+
# May fix legend drawing problem at small sizes
|
284
|
+
@d.font = @font
|
285
|
+
@d.pointsize = 20
|
286
|
+
|
261
287
|
metrics = @d.get_type_metrics(@base_image, @legend_labels.join(''))
|
262
288
|
legend_text_width = metrics.width
|
263
|
-
legend_width = legend_text_width + @legend_labels.length *
|
264
|
-
legend_left =
|
289
|
+
legend_width = legend_text_width + (@legend_labels.length * legend_square_width * 2.7)
|
290
|
+
legend_left = (@raw_columns - legend_width) / 2
|
265
291
|
legend_increment = legend_width / @legend_labels.length.to_f
|
266
292
|
|
267
293
|
current_x_offset = legend_left
|
@@ -296,6 +322,8 @@ protected
|
|
296
322
|
end
|
297
323
|
|
298
324
|
def draw_title
|
325
|
+
return unless @show_title
|
326
|
+
|
299
327
|
@d.fill = @marker_color
|
300
328
|
@d.font = @font
|
301
329
|
@d.stroke = 'transparent'
|
@@ -308,11 +336,39 @@ protected
|
|
308
336
|
@title, @scale)
|
309
337
|
end
|
310
338
|
|
339
|
+
##
|
340
|
+
# Draws column labels below graph, centered over x_offset
|
341
|
+
def draw_label(x_offset, index)
|
342
|
+
if !@labels[index].nil? && @labels_seen[index].nil?
|
343
|
+
@d.fill = @marker_color
|
344
|
+
@d.font = @font
|
345
|
+
@d.stroke = 'transparent'
|
346
|
+
@d.font_weight = NormalWeight
|
347
|
+
@d.pointsize = scale_fontsize(@marker_pointsize)
|
348
|
+
@d.gravity = CenterGravity
|
349
|
+
@d = @d.annotate_scaled(@base_image,
|
350
|
+
1, 1,
|
351
|
+
x_offset, @raw_rows - 80,
|
352
|
+
@labels[index], @scale)
|
353
|
+
@labels_seen[index] = 1
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
# Use with a theme definition method to draw a gradiated (or solid color) background.
|
311
358
|
def render_gradiated_background(top_color, bottom_color)
|
312
359
|
Image.new(@columns, @rows,
|
313
360
|
GradientFill.new(0, 0, 100, 0, top_color, bottom_color))
|
314
361
|
end
|
315
362
|
|
363
|
+
# Use with a theme to use an image (800x600 original) background.
|
364
|
+
def render_image_background(image_path)
|
365
|
+
image = Image.read(image_path)
|
366
|
+
if @scale != 1.0
|
367
|
+
image[0].resize!(@scale)
|
368
|
+
end
|
369
|
+
image[0]
|
370
|
+
end
|
371
|
+
|
316
372
|
def current_color
|
317
373
|
@colors[@color_index]
|
318
374
|
end
|
@@ -343,11 +399,47 @@ protected
|
|
343
399
|
return new_fontsize
|
344
400
|
end
|
345
401
|
|
402
|
+
def clip_value_if_greater_than(value, max_value)
|
403
|
+
(value > max_value) ? max_value : value
|
404
|
+
end
|
405
|
+
|
406
|
+
# round down to significant digits
|
407
|
+
def significant(inc)
|
408
|
+
factor = 1.0
|
409
|
+
while (inc < 10)
|
410
|
+
inc *= 10
|
411
|
+
factor /= 10
|
412
|
+
end
|
413
|
+
|
414
|
+
while (inc > 100)
|
415
|
+
inc /= 10
|
416
|
+
factor *= 10
|
417
|
+
end
|
418
|
+
|
419
|
+
res = inc.floor * factor
|
420
|
+
if (res.to_i.to_f == res)
|
421
|
+
res.to_i
|
422
|
+
else
|
423
|
+
res
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
# Sort with largest overall summed value at front of array
|
428
|
+
# so it shows up correctly in the drawn graph.
|
429
|
+
def sort_norm_data
|
430
|
+
@norm_data.sort! { |a,b| sums(b[1]) <=> sums(a[1]) }
|
431
|
+
end
|
432
|
+
|
433
|
+
def sums(data_set)
|
434
|
+
total_sum = 0
|
435
|
+
data_set.collect {|num| total_sum += num }
|
436
|
+
total_sum
|
437
|
+
end
|
438
|
+
|
346
439
|
end
|
347
440
|
|
348
441
|
class ColorlistExhaustedException < StandardError; end
|
349
|
-
|
350
|
-
|
442
|
+
|
351
443
|
end
|
352
444
|
|
353
445
|
|
data/lib/gruff/line.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
|
1
2
|
require 'gruff/base'
|
2
3
|
|
3
4
|
class Gruff::Line < Gruff::Base
|
@@ -24,11 +25,11 @@ class Gruff::Line < Gruff::Base
|
|
24
25
|
super
|
25
26
|
|
26
27
|
@x_increment = @graph_width / (@column_count - 1).to_f
|
27
|
-
circle_radius = 5.0
|
28
|
+
circle_radius = clip_value_if_greater_than(@columns / (@norm_data.first[1].size * 2.5), 5.0)
|
28
29
|
|
29
30
|
@d = @d.stroke_opacity 1.0
|
30
|
-
@d = @d.stroke_width 5.0
|
31
|
-
|
31
|
+
@d = @d.stroke_width clip_value_if_greater_than(@columns / (@norm_data.first[1].size * 4), 5.0)
|
32
|
+
|
32
33
|
@norm_data.each do |data_row|
|
33
34
|
prev_x = prev_y = 0.0
|
34
35
|
@d = @d.stroke current_color
|
@@ -56,24 +57,5 @@ class Gruff::Line < Gruff::Base
|
|
56
57
|
@d.draw(@base_image)
|
57
58
|
end
|
58
59
|
|
59
|
-
private
|
60
|
-
|
61
|
-
##
|
62
|
-
# Draws column labels below graph
|
63
|
-
def draw_label(x_offset, index)
|
64
|
-
if !@labels[index].nil? && @labels_seen[index].nil?
|
65
|
-
@d.fill = @marker_color
|
66
|
-
@d.font = @font
|
67
|
-
@d.stroke = 'transparent'
|
68
|
-
@d.font_weight = NormalWeight
|
69
|
-
@d.pointsize = scale_fontsize(@marker_pointsize)
|
70
|
-
@d.gravity = CenterGravity
|
71
|
-
@d = @d.annotate_scaled(@base_image,
|
72
|
-
1, 1,
|
73
|
-
x_offset, @raw_rows - 80,
|
74
|
-
@labels[index], @scale)
|
75
|
-
@labels_seen[index] = 1
|
76
|
-
end
|
77
|
-
end
|
78
60
|
|
79
61
|
end
|
data/lib/gruff/pie.rb
CHANGED
@@ -1,15 +1,92 @@
|
|
1
1
|
|
2
2
|
require 'gruff/base'
|
3
3
|
|
4
|
-
|
5
|
-
class Pie < Base
|
4
|
+
class Gruff::Pie < Gruff::Base
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
def draw
|
7
|
+
@show_line_markers = false
|
8
|
+
|
9
|
+
super
|
10
10
|
|
11
|
-
|
11
|
+
diameter = @graph_height
|
12
|
+
radius = @graph_height / 2.0
|
13
|
+
top_x = @graph_left + (@graph_width - diameter) / 2.0
|
14
|
+
center_x = @graph_left + (@graph_width / 2.0)
|
15
|
+
center_y = @graph_top + (@graph_height / 2.0)
|
16
|
+
total_sum = sums_for_pie()
|
17
|
+
prev_degrees = 0.0
|
18
|
+
|
19
|
+
@norm_data.each do |data_row|
|
20
|
+
@d = @d.stroke current_color
|
21
|
+
@d = @d.fill 'transparent'
|
22
|
+
@d.stroke_width(200.0)
|
23
|
+
|
24
|
+
current_degrees = (data_row[1][0] / total_sum) * 360.0
|
25
|
+
#@d = @d.pie_slice(center_x, center_y, radius,
|
26
|
+
# current_percent * 100.0)
|
27
|
+
|
28
|
+
#@d = @d.arc(top_x, @graph_top,
|
29
|
+
# top_x + diameter, @graph_top + diameter,
|
30
|
+
# prev_degrees, prev_degrees + current_degrees)
|
31
|
+
radius = 100.0
|
32
|
+
@d = @d.ellipse(center_x, center_y,
|
33
|
+
radius, radius,
|
34
|
+
prev_degrees, prev_degrees + current_degrees)
|
35
|
+
|
36
|
+
|
37
|
+
prev_degrees += current_degrees
|
38
|
+
increment_color()
|
12
39
|
end
|
13
40
|
|
41
|
+
@d.draw(@base_image)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def sums_for_pie
|
47
|
+
total_sum = 0.0
|
48
|
+
@norm_data.collect {|data_row| total_sum += data_row[1][0] }
|
49
|
+
total_sum
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
class Magick::Draw
|
55
|
+
|
56
|
+
def pie_slice(center_x=0.0, center_y=0.0, radius=100.0, percent=0.0, rot_x=0.0)
|
57
|
+
# Okay, this part is as confusing as hell, so pay attention:
|
58
|
+
# This line determines the horizontal portion of the point on the circle where the X-Axis
|
59
|
+
# should end. It's caculated by taking the center of the on-image circle and adding that
|
60
|
+
# to the radius multiplied by the formula for determinig the point on a unit circle that a
|
61
|
+
# angle corresponds to. 3.6 * percent gives us that angle, but it's in degrees, so we need to
|
62
|
+
# convert, hence the muliplication by Pi over 180
|
63
|
+
arc_end_x = radius + (radius * Math.cos((3.6 * percent)*(Math::PI/180.0)))
|
64
|
+
|
65
|
+
# The same goes for here, except it's the vertical point instead of the horizontal one
|
66
|
+
arc_end_y = radius + (radius * Math.sin((3.6 * percent)*(Math::PI/180.0)))
|
67
|
+
|
68
|
+
# Because the SVG path format is seriously screwy, we need to set the large-arc-flag to 1
|
69
|
+
# if the angle of an arc is greater than 180 degrees. I have no idea why this is, but it is.
|
70
|
+
percent > 50 ? large_arc_flag = 1 : large_arc_flag = 0
|
71
|
+
|
72
|
+
# This is also confusing
|
73
|
+
# M tells us to move to an absolute point on the image.
|
74
|
+
# We're moving to the center of the pie
|
75
|
+
# h tells us to move to a relative point.
|
76
|
+
# We're moving to the right edge of the circle.
|
77
|
+
# A tells us to start an absolute elliptical arc.
|
78
|
+
# The first two values are the radii of the ellipse
|
79
|
+
# The third value is the x-axis-rotation (how to rotate the ellipse)
|
80
|
+
# The fourth value is our large-arc-flag
|
81
|
+
# The fifth is the sweep-flag
|
82
|
+
# The sixth and seventh values are the end point of the arc which we calculated previously
|
83
|
+
# More info on the SVG path string format at: http://www.w3.org/TR/SVG/paths.html
|
84
|
+
#
|
85
|
+
#path = "M#{radius + 2},#{radius + 2} h#{radius} A#{radius},#{radius} #{rot_x} #{large_arc_flag},1 #{arc_end_x},#{arc_end_y} z"
|
86
|
+
path = "M#{radius},#{radius} h#{radius} A#{radius},#{radius} #{rot_x} #{large_arc_flag},1 #{arc_end_x},#{arc_end_y} z"
|
87
|
+
puts "PATH: #{path}"
|
88
|
+
|
89
|
+
self.path(path)
|
14
90
|
end
|
15
|
-
|
91
|
+
|
92
|
+
end
|
data/rakefile
CHANGED
@@ -61,6 +61,7 @@ spec = Gem::Specification.new do |s|
|
|
61
61
|
|
62
62
|
s.files = [ "rakefile", "README", "CHANGELOG", "MIT-LICENSE" ]
|
63
63
|
s.files = s.files + Dir.glob( "lib/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
|
64
|
+
s.files = s.files + Dir.glob( "assets/*" ).delete_if { |item| item.include?( "\.svn" ) }
|
64
65
|
s.files = s.files + Dir.glob( "test/**/*" ).delete_if { |item| item.include?( "\.svn" ) || item.include?("\.png") }
|
65
66
|
end
|
66
67
|
|
@@ -70,7 +71,6 @@ Rake::GemPackageTask.new(spec) do |p|
|
|
70
71
|
p.need_zip = true
|
71
72
|
end
|
72
73
|
|
73
|
-
|
74
74
|
desc "Publish the API documentation"
|
75
75
|
task :pgem => [:package] do
|
76
76
|
Rake::SshFilePublisher.new("boss@topfunky.com", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
|
data/test/area_test.rb
ADDED
@@ -0,0 +1,110 @@
|
|
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 TestGruffArea < Test::Unit::TestCase
|
10
|
+
|
11
|
+
def setup
|
12
|
+
@datasets = [
|
13
|
+
[:Jimmy, [25, 36, 86, 39, 25, 31, 79, 88]],
|
14
|
+
[:Charles, [80, 54, 67, 54, 68, 70, 90, 95]],
|
15
|
+
[:Julie, [22, 29, 35, 38, 36, 40, 46, 57]],
|
16
|
+
[:Jane, [95, 95, 95, 90, 85, 80, 88, 100]],
|
17
|
+
[:Philip, [90, 34, 23, 12, 78, 89, 98, 88]],
|
18
|
+
["Arthur", [5, 10, 13, 11, 6, 16, 22, 32]],
|
19
|
+
]
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_area_graph
|
23
|
+
g = Gruff::Area.new
|
24
|
+
g.title = "Visual Multi-Area Graph Test"
|
25
|
+
g.labels = {
|
26
|
+
0 => '5/6',
|
27
|
+
2 => '5/15',
|
28
|
+
4 => '5/24',
|
29
|
+
6 => '5/30',
|
30
|
+
}
|
31
|
+
@datasets.each do |data|
|
32
|
+
g.data(data[0], data[1])
|
33
|
+
end
|
34
|
+
|
35
|
+
# Default theme
|
36
|
+
g.write("test/output/area_keynote.png")
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_resize
|
40
|
+
g = Gruff::Area.new(400)
|
41
|
+
g.title = "Small Size Multi-Area Graph Test"
|
42
|
+
g.labels = {
|
43
|
+
0 => '5/6',
|
44
|
+
2 => '5/15',
|
45
|
+
4 => '5/24',
|
46
|
+
6 => '5/30',
|
47
|
+
}
|
48
|
+
@datasets.each do |data|
|
49
|
+
g.data(data[0], data[1])
|
50
|
+
end
|
51
|
+
|
52
|
+
# Default theme
|
53
|
+
g.write("test/output/area_keynote_small.png")
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_many_datapoints
|
57
|
+
g = Gruff::Area.new
|
58
|
+
g.title = "Many Multi-Area Graph Test"
|
59
|
+
g.labels = {
|
60
|
+
0 => 'June',
|
61
|
+
10 => 'July',
|
62
|
+
30 => 'August',
|
63
|
+
50 => 'September',
|
64
|
+
}
|
65
|
+
g.data('many points', (0..50).collect {|i| rand(100) })
|
66
|
+
|
67
|
+
# Default theme
|
68
|
+
g.write("test/output/area_many.png")
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_many_areas_graph_small
|
72
|
+
g = Gruff::Area.new(400)
|
73
|
+
g.title = "Many Values Area Test 400px"
|
74
|
+
g.labels = {
|
75
|
+
0 => '5/6',
|
76
|
+
10 => '5/15',
|
77
|
+
20 => '5/24',
|
78
|
+
30 => '5/30',
|
79
|
+
40 => '6/4',
|
80
|
+
50 => '6/16'
|
81
|
+
}
|
82
|
+
%w{jimmy jane philip arthur julie bert}.each do |student_name|
|
83
|
+
g.data(student_name, (0..50).collect { |i| rand 100 })
|
84
|
+
end
|
85
|
+
|
86
|
+
# Default theme
|
87
|
+
g.write("test/output/area_many_areas_small.png")
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_area_graph_tiny
|
91
|
+
g = Gruff::Area.new(300)
|
92
|
+
g.title = "Area Test 300px"
|
93
|
+
g.labels = {
|
94
|
+
0 => '5/6',
|
95
|
+
10 => '5/15',
|
96
|
+
20 => '5/24',
|
97
|
+
30 => '5/30',
|
98
|
+
40 => '6/4',
|
99
|
+
50 => '6/16'
|
100
|
+
}
|
101
|
+
%w{jimmy jane philip arthur julie bert}.each do |student_name|
|
102
|
+
g.data(student_name, (0..50).collect { |i| rand 100 })
|
103
|
+
end
|
104
|
+
|
105
|
+
# Default theme
|
106
|
+
g.write("test/output/area_tiny.png")
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
data/test/bar_test.rb
CHANGED
@@ -26,19 +26,16 @@ class TestGruffBar < Test::Unit::TestCase
|
|
26
26
|
g.title = "Visual Multi-Line Bar Graph Test"
|
27
27
|
g.labels = {
|
28
28
|
0 => '5/6',
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
1 => '5/15',
|
30
|
+
2 => '5/24',
|
31
|
+
3 => '5/30',
|
32
32
|
}
|
33
33
|
@datasets.each do |data|
|
34
34
|
g.data(data[0], data[1])
|
35
35
|
end
|
36
36
|
|
37
37
|
g.write("test/output/bar_keynote.png")
|
38
|
-
|
39
|
-
g.theme_37signals
|
40
|
-
g.write("test/output/bar_37signals.png")
|
41
|
-
|
38
|
+
|
42
39
|
g.theme_rails_keynote
|
43
40
|
g.write("test/output/bar_rails_keynote.png")
|
44
41
|
|
@@ -52,25 +49,69 @@ class TestGruffBar < Test::Unit::TestCase
|
|
52
49
|
g.title = "Visual Multi-Line Bar Graph Test"
|
53
50
|
g.labels = {
|
54
51
|
0 => '5/6',
|
55
|
-
|
56
|
-
|
57
|
-
|
52
|
+
1 => '5/15',
|
53
|
+
2 => '5/24',
|
54
|
+
3 => '5/30',
|
58
55
|
}
|
59
56
|
@datasets.each do |data|
|
60
57
|
g.data(data[0], data[1])
|
61
58
|
end
|
62
59
|
|
63
60
|
g.write("test/output/bar_keynote_small.png")
|
64
|
-
|
65
|
-
g.theme_37signals
|
66
|
-
g.write("test/output/bar_37signals_small.png")
|
67
|
-
|
68
|
-
g.theme_rails_keynote
|
69
|
-
g.write("test/output/bar_rails_keynote_small.png")
|
70
|
-
|
71
|
-
g.theme_odeo
|
72
|
-
g.write("test/output/bar_odeo_small.png")
|
73
61
|
end
|
62
|
+
|
63
|
+
def test_bar_image_bg
|
64
|
+
g = Gruff::Bar.new
|
65
|
+
g.title = "Bar Graph With Image Background"
|
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
|
+
|
76
|
+
g.theme_image_based
|
77
|
+
g.write("test/output/bar_image.png")
|
78
|
+
|
79
|
+
g = Gruff::Bar.new(400)
|
80
|
+
g.title = "Bar Graph With Image Background Small"
|
81
|
+
g.labels = {
|
82
|
+
0 => '5/6',
|
83
|
+
1 => '5/15',
|
84
|
+
2 => '5/24',
|
85
|
+
3 => '5/30',
|
86
|
+
}
|
87
|
+
@datasets.each do |data|
|
88
|
+
g.data(data[0], data[1])
|
89
|
+
end
|
90
|
+
|
91
|
+
g.theme_image_based
|
92
|
+
g.write("test/output/bar_image_small.png")
|
93
|
+
|
94
|
+
end
|
95
|
+
|
74
96
|
|
97
|
+
end
|
98
|
+
|
99
|
+
class Gruff::Base
|
100
|
+
# A color scheme from the colors used on the 2005 Rails keynote presentation at RubyConf.
|
101
|
+
def theme_image_based
|
102
|
+
reset_themes()
|
103
|
+
# Colors
|
104
|
+
@green = '#00ff00'
|
105
|
+
@grey = '#333333'
|
106
|
+
@orange = '#ff5d00'
|
107
|
+
@red = '#f61100'
|
108
|
+
@white = 'white'
|
109
|
+
@light_grey = '#999999'
|
110
|
+
@black = 'black'
|
111
|
+
@colors = [@green, @grey, @orange, @red, @white, @light_grey, @black]
|
75
112
|
|
113
|
+
@marker_color = 'white'
|
114
|
+
|
115
|
+
@base_image = render_image_background('assets/bubble.png')
|
116
|
+
end
|
76
117
|
end
|
data/test/line_test.rb
CHANGED
@@ -60,6 +60,14 @@ class TestGruffLine < Test::Unit::TestCase
|
|
60
60
|
end
|
61
61
|
|
62
62
|
g.write("test/output/line_small.png")
|
63
|
+
|
64
|
+
g = Gruff::Line.new(400)
|
65
|
+
g.title = "Small Values Line Graph Test 400px"
|
66
|
+
@datasets.each do |data|
|
67
|
+
g.data(data[0], data[1])
|
68
|
+
end
|
69
|
+
|
70
|
+
g.write("test/output/line_small_small.png")
|
63
71
|
end
|
64
72
|
|
65
73
|
def test_line_large_values
|
@@ -205,6 +213,24 @@ class TestGruffLine < Test::Unit::TestCase
|
|
205
213
|
g.write("test/output/line_dots_small.png")
|
206
214
|
end
|
207
215
|
|
216
|
+
def test_many_lines_graph_small
|
217
|
+
g = Gruff::Line.new(400)
|
218
|
+
g.title = "Many Values Line Test 400px"
|
219
|
+
g.labels = {
|
220
|
+
0 => '5/6',
|
221
|
+
10 => '5/15',
|
222
|
+
20 => '5/24',
|
223
|
+
30 => '5/30',
|
224
|
+
40 => '6/4',
|
225
|
+
50 => '6/16'
|
226
|
+
}
|
227
|
+
%w{jimmy jane philip arthur julie bert}.each do |student_name|
|
228
|
+
g.data(student_name, (0..50).collect { |i| rand 100 })
|
229
|
+
end
|
230
|
+
|
231
|
+
# Default theme
|
232
|
+
g.write("test/output/line_many_lines_small.png")
|
233
|
+
end
|
208
234
|
|
209
235
|
def test_dots_graph_tiny
|
210
236
|
g = Gruff::Line.new(300, false)
|
data/test/pie_test.rb
ADDED
@@ -0,0 +1,83 @@
|
|
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 TestGruffPie < Test::Unit::TestCase
|
10
|
+
|
11
|
+
def setup
|
12
|
+
@datasets = [
|
13
|
+
[:Jimmy, [25]],
|
14
|
+
[:Charles, [80]],
|
15
|
+
[:Julie, [22]],
|
16
|
+
[:Jane, [95]],
|
17
|
+
[:Philip, [90]],
|
18
|
+
["Arthur", [5]],
|
19
|
+
]
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_pie_graph
|
23
|
+
g = Gruff::Pie.new
|
24
|
+
g.title = "Visual Pie Graph Test"
|
25
|
+
@datasets.each do |data|
|
26
|
+
g.data(data[0], data[1])
|
27
|
+
end
|
28
|
+
|
29
|
+
# Default theme
|
30
|
+
g.write("test/output/pie_keynote.png")
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_pie_graph_small
|
34
|
+
g = Gruff::Pie.new(400)
|
35
|
+
g.title = "Visual Pie Graph Test Small"
|
36
|
+
@datasets.each do |data|
|
37
|
+
g.data(data[0], data[1])
|
38
|
+
end
|
39
|
+
|
40
|
+
# Default theme
|
41
|
+
g.write("test/output/pie_keynote_small.png")
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
=begin
|
46
|
+
def test_resize
|
47
|
+
g = Gruff::Pie.new(400)
|
48
|
+
g.title = "Small Size Multi-Pie Graph Test"
|
49
|
+
g.labels = {
|
50
|
+
0 => '5/6',
|
51
|
+
2 => '5/15',
|
52
|
+
4 => '5/24',
|
53
|
+
6 => '5/30',
|
54
|
+
}
|
55
|
+
@datasets.each do |data|
|
56
|
+
g.data(data[0], data[1])
|
57
|
+
end
|
58
|
+
|
59
|
+
# Default theme
|
60
|
+
g.write("test/output/pie_keynote_small.png")
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_pie_graph_tiny
|
64
|
+
g = Gruff::Pie.new(300)
|
65
|
+
g.title = "Pie Test 300px"
|
66
|
+
g.labels = {
|
67
|
+
0 => '5/6',
|
68
|
+
10 => '5/15',
|
69
|
+
20 => '5/24',
|
70
|
+
30 => '5/30',
|
71
|
+
40 => '6/4',
|
72
|
+
50 => '6/16'
|
73
|
+
}
|
74
|
+
%w{jimmy jane philip arthur julie bert}.each do |student_name|
|
75
|
+
g.data(student_name, (0..50).collect { |i| rand 100 })
|
76
|
+
end
|
77
|
+
|
78
|
+
# Default theme
|
79
|
+
g.write("test/output/pie_tiny.png")
|
80
|
+
end
|
81
|
+
=end
|
82
|
+
|
83
|
+
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ 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-
|
6
|
+
version: 0.0.4
|
7
|
+
date: 2005-11-14 00:00:00 -08:00
|
8
8
|
summary: Beautiful graphs for one or multiple datasets.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -40,9 +40,12 @@ files:
|
|
40
40
|
- lib/gruff/base.rb
|
41
41
|
- lib/gruff/line.rb
|
42
42
|
- lib/gruff/pie.rb
|
43
|
+
- assets/bubble.png
|
44
|
+
- test/area_test.rb
|
43
45
|
- test/bar_test.rb
|
44
46
|
- test/line_test.rb
|
45
47
|
- test/output
|
48
|
+
- test/pie_test.rb
|
46
49
|
test_files: []
|
47
50
|
rdoc_options: []
|
48
51
|
extra_rdoc_files: []
|