gruff 0.7.0-java → 0.12.0-java

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.
Files changed (113) hide show
  1. checksums.yaml +5 -5
  2. data/{History.txt → CHANGELOG.md} +81 -25
  3. data/Gemfile +3 -1
  4. data/README.md +51 -23
  5. data/assets/plastik/blue.png +0 -0
  6. data/assets/plastik/green.png +0 -0
  7. data/assets/plastik/red.png +0 -0
  8. data/gruff.gemspec +23 -13
  9. data/init.rb +2 -0
  10. data/lib/gruff.rb +33 -4
  11. data/lib/gruff/accumulator_bar.rb +17 -9
  12. data/lib/gruff/area.rb +31 -21
  13. data/lib/gruff/bar.rb +90 -46
  14. data/lib/gruff/base.rb +476 -710
  15. data/lib/gruff/bezier.rb +29 -18
  16. data/lib/gruff/bullet.rb +58 -71
  17. data/lib/gruff/dot.rb +35 -83
  18. data/lib/gruff/helper/bar_conversion.rb +47 -0
  19. data/lib/gruff/helper/bar_value_label_mixin.rb +33 -0
  20. data/lib/gruff/helper/stacked_mixin.rb +23 -0
  21. data/lib/gruff/histogram.rb +59 -0
  22. data/lib/gruff/line.rb +121 -199
  23. data/lib/gruff/mini/bar.rb +17 -10
  24. data/lib/gruff/mini/legend.rb +26 -38
  25. data/lib/gruff/mini/pie.rb +18 -13
  26. data/lib/gruff/mini/side_bar.rb +25 -12
  27. data/lib/gruff/net.rb +69 -83
  28. data/lib/gruff/patch/rmagick.rb +31 -0
  29. data/lib/gruff/patch/string.rb +13 -0
  30. data/lib/gruff/photo_bar.rb +36 -43
  31. data/lib/gruff/pie.rb +42 -103
  32. data/lib/gruff/renderer/bezier.rb +22 -0
  33. data/lib/gruff/renderer/circle.rb +22 -0
  34. data/lib/gruff/renderer/dash_line.rb +23 -0
  35. data/lib/gruff/renderer/dot.rb +40 -0
  36. data/lib/gruff/renderer/ellipse.rb +22 -0
  37. data/lib/gruff/renderer/line.rb +43 -0
  38. data/lib/gruff/renderer/polygon.rb +24 -0
  39. data/lib/gruff/renderer/polyline.rb +22 -0
  40. data/lib/gruff/renderer/rectangle.rb +20 -0
  41. data/lib/gruff/renderer/renderer.rb +120 -0
  42. data/lib/gruff/renderer/text.rb +57 -0
  43. data/lib/gruff/scatter.rb +128 -201
  44. data/lib/gruff/scene.rb +30 -41
  45. data/lib/gruff/side_bar.rb +100 -68
  46. data/lib/gruff/side_stacked_bar.rb +92 -63
  47. data/lib/gruff/spider.rb +47 -53
  48. data/lib/gruff/stacked_area.rb +37 -34
  49. data/lib/gruff/stacked_bar.rb +99 -54
  50. data/lib/gruff/store/basic_data.rb +36 -0
  51. data/lib/gruff/store/custom_data.rb +36 -0
  52. data/lib/gruff/store/store.rb +81 -0
  53. data/lib/gruff/store/xy_data.rb +58 -0
  54. data/lib/gruff/themes.rb +32 -33
  55. data/lib/gruff/version.rb +3 -1
  56. metadata +74 -102
  57. data/.gitignore +0 -7
  58. data/.travis.yml +0 -19
  59. data/Manifest.txt +0 -81
  60. data/RELEASE.md +0 -30
  61. data/Rakefile +0 -218
  62. data/assets/bubble.png +0 -0
  63. data/assets/city_scene/background/0000.png +0 -0
  64. data/assets/city_scene/background/0600.png +0 -0
  65. data/assets/city_scene/background/2000.png +0 -0
  66. data/assets/city_scene/clouds/cloudy.png +0 -0
  67. data/assets/city_scene/clouds/partly_cloudy.png +0 -0
  68. data/assets/city_scene/clouds/stormy.png +0 -0
  69. data/assets/city_scene/grass/default.png +0 -0
  70. data/assets/city_scene/haze/true.png +0 -0
  71. data/assets/city_scene/number_sample/1.png +0 -0
  72. data/assets/city_scene/number_sample/2.png +0 -0
  73. data/assets/city_scene/number_sample/default.png +0 -0
  74. data/assets/city_scene/sky/0000.png +0 -0
  75. data/assets/city_scene/sky/0200.png +0 -0
  76. data/assets/city_scene/sky/0400.png +0 -0
  77. data/assets/city_scene/sky/0600.png +0 -0
  78. data/assets/city_scene/sky/0800.png +0 -0
  79. data/assets/city_scene/sky/1000.png +0 -0
  80. data/assets/city_scene/sky/1200.png +0 -0
  81. data/assets/city_scene/sky/1400.png +0 -0
  82. data/assets/city_scene/sky/1500.png +0 -0
  83. data/assets/city_scene/sky/1700.png +0 -0
  84. data/assets/city_scene/sky/2000.png +0 -0
  85. data/assets/pc306715.jpg +0 -0
  86. data/lib/gruff/bar_conversion.rb +0 -46
  87. data/lib/gruff/deprecated.rb +0 -39
  88. data/lib/gruff/stacked_mixin.rb +0 -23
  89. data/test/gruff_test_case.rb +0 -152
  90. data/test/image_compare.rb +0 -58
  91. data/test/test_accumulator_bar.rb +0 -51
  92. data/test/test_area.rb +0 -134
  93. data/test/test_bar.rb +0 -505
  94. data/test/test_base.rb +0 -33
  95. data/test/test_bezier.rb +0 -33
  96. data/test/test_bullet.rb +0 -26
  97. data/test/test_dot.rb +0 -263
  98. data/test/test_labels_for_null_data.rb +0 -27
  99. data/test/test_legend.rb +0 -68
  100. data/test/test_line.rb +0 -674
  101. data/test/test_mini_bar.rb +0 -33
  102. data/test/test_mini_pie.rb +0 -25
  103. data/test/test_mini_side_bar.rb +0 -36
  104. data/test/test_net.rb +0 -231
  105. data/test/test_photo.rb +0 -41
  106. data/test/test_pie.rb +0 -194
  107. data/test/test_scatter.rb +0 -270
  108. data/test/test_scene.rb +0 -100
  109. data/test/test_side_bar.rb +0 -56
  110. data/test/test_sidestacked_bar.rb +0 -105
  111. data/test/test_spider.rb +0 -226
  112. data/test/test_stacked_area.rb +0 -52
  113. data/test/test_stacked_bar.rb +0 -68
@@ -1,20 +1,26 @@
1
-
2
- require File.dirname(__FILE__) + '/base'
1
+ # frozen_string_literal: true
3
2
 
4
3
  # Experimental!!! See also the Net graph.
5
4
  #
6
- # Submitted by Kevin Clark http://glu.ttono.us/
5
+ # Here's how to set up a Gruff::Spider.
6
+ #
7
+ # g = Gruff::Spider.new(30)
8
+ # g.title = "Spider Graph"
9
+ # g.data :Strength, [10]
10
+ # g.data :Dexterity, [16]
11
+ # g.data :Constitution, [12]
12
+ # g.data :Intelligence, [12]
13
+ # g.data :Wisdom, [10]
14
+ # g.data 'Charisma', [16]
15
+ # g.write("spider.png")
16
+ #
7
17
  class Gruff::Spider < Gruff::Base
8
-
9
- # Hide all text
10
- attr_reader :hide_text
11
- attr_accessor :hide_axes
12
- attr_reader :transparent_background
13
- attr_accessor :rotation
14
-
18
+ # Hide all text.
19
+ attr_writer :hide_axes
20
+ attr_writer :rotation
21
+
15
22
  def transparent_background=(value)
16
- @transparent_background = value
17
- @base_image = render_transparent_background if value
23
+ Gruff::Renderer.setup_transparent_background(@columns, @rows) if value
18
24
  end
19
25
 
20
26
  def hide_text=(value)
@@ -24,16 +30,23 @@ class Gruff::Spider < Gruff::Base
24
30
  def initialize(max_value, target_width = 800)
25
31
  super(target_width)
26
32
  @max_value = max_value
33
+ end
34
+
35
+ def initialize_ivars
36
+ super
27
37
  @hide_legend = true
38
+ @hide_axes = false
39
+ @hide_text = false
28
40
  @rotation = 0
29
41
  end
30
-
42
+ private :initialize_ivars
43
+
31
44
  def draw
32
45
  @hide_line_markers = true
33
-
46
+
34
47
  super
35
48
 
36
- return unless @has_data
49
+ return unless data_given?
37
50
 
38
51
  # Setup basic positioning
39
52
  radius = @graph_height / 2.0
@@ -41,16 +54,14 @@ class Gruff::Spider < Gruff::Base
41
54
  center_y = @graph_top + (@graph_height / 2.0) - 25 # Move graph up a bit
42
55
 
43
56
  @unit_length = radius / @max_value
44
-
45
- additive_angle = (2 * Math::PI)/ @data.size
46
-
57
+
58
+ additive_angle = (2 * Math::PI) / store.length
59
+
47
60
  # Draw axes
48
- draw_axes(center_x, center_y, radius, additive_angle) unless hide_axes
61
+ draw_axes(center_x, center_y, radius, additive_angle) unless @hide_axes
49
62
 
50
63
  # Draw polygon
51
64
  draw_polygon(center_x, center_y, additive_angle)
52
-
53
- @d.draw(@base_image)
54
65
  end
55
66
 
56
67
  private
@@ -60,42 +71,30 @@ private
60
71
  end
61
72
 
62
73
  def draw_label(center_x, center_y, angle, radius, amount)
63
- r_offset = 50 # The distance out from the center of the pie to get point
74
+ r_offset = 50 # The distance out from the center of the pie to get point
64
75
  x_offset = center_x # The label points need to be tweaked slightly
65
76
  y_offset = center_y + 0 # This one doesn't though
66
77
  x = x_offset + ((radius + r_offset) * Math.cos(angle))
67
78
  y = y_offset + ((radius + r_offset) * Math.sin(angle))
68
79
 
69
80
  # Draw label
70
- @d.fill = @marker_color
71
- @d.font = @font if @font
72
- @d.pointsize = scale_fontsize(legend_font_size)
73
- @d.stroke = 'transparent'
74
- @d.font_weight = BoldWeight
75
- @d.gravity = CenterGravity
76
- @d.annotate_scaled( @base_image,
77
- 0, 0,
78
- x, y,
79
- amount, @scale)
81
+ text_renderer = Gruff::Renderer::Text.new(amount, font: @font, size: @legend_font_size, color: @marker_color, weight: Magick::BoldWeight)
82
+ text_renderer.add_to_render_queue(0, 0, x, y, Magick::CenterGravity)
80
83
  end
81
84
 
82
85
  def draw_axes(center_x, center_y, radius, additive_angle, line_color = nil)
83
- return if hide_axes
84
-
85
- current_angle = rotation * Math::PI / 180.0
86
+ return if @hide_axes
86
87
 
87
- @data.each do |data_row|
88
- @d.stroke(line_color || data_row[DATA_COLOR_INDEX])
89
- @d.stroke_width 5.0
88
+ current_angle = @rotation * Math::PI / 180.0
90
89
 
90
+ store.data.each do |data_row|
91
91
  x_offset = radius * Math.cos(current_angle)
92
92
  y_offset = radius * Math.sin(current_angle)
93
93
 
94
- @d.line(center_x, center_y,
95
- center_x + x_offset,
96
- center_y + y_offset)
94
+ Gruff::Renderer::Line.new(color: line_color || data_row.color, width: 5.0)
95
+ .render(center_x, center_y, center_x + x_offset, center_y + y_offset)
97
96
 
98
- draw_label(center_x, center_y, current_angle, radius, data_row[DATA_LABEL_INDEX].to_s) unless hide_text
97
+ draw_label(center_x, center_y, current_angle, radius, data_row.label.to_s) unless @hide_text
99
98
 
100
99
  current_angle += additive_angle
101
100
  end
@@ -103,23 +102,18 @@ private
103
102
 
104
103
  def draw_polygon(center_x, center_y, additive_angle, color = nil)
105
104
  points = []
106
- current_angle = rotation * Math::PI / 180.0
105
+ current_angle = @rotation * Math::PI / 180.0
107
106
 
108
- @data.each do |data_row|
109
- points << center_x + normalize_points(data_row[DATA_VALUES_INDEX].first) * Math.cos(current_angle)
110
- points << center_y + normalize_points(data_row[DATA_VALUES_INDEX].first) * Math.sin(current_angle)
107
+ store.data.each do |data_row|
108
+ points << center_x + normalize_points(data_row.points.first) * Math.cos(current_angle)
109
+ points << center_y + normalize_points(data_row.points.first) * Math.sin(current_angle)
111
110
  current_angle += additive_angle
112
111
  end
113
112
 
114
- @d.stroke_width 1.0
115
- @d.stroke(color || @marker_color)
116
- @d.fill(color || @marker_color)
117
- @d.fill_opacity 0.4
118
- @d.polygon(*points)
113
+ Gruff::Renderer::Polygon.new(color: color || @marker_color, opacity: 0.4).render(points)
119
114
  end
120
115
 
121
116
  def sums_for_spider
122
- @data.inject(0.0) {|sum, data_row| sum + data_row[DATA_VALUES_INDEX].first}
117
+ store.data.sum { |data_row| data_row.points.first }
123
118
  end
124
-
125
119
  end
@@ -1,67 +1,70 @@
1
+ # frozen_string_literal: true
1
2
 
2
- require File.dirname(__FILE__) + '/base'
3
- require File.dirname(__FILE__) + '/stacked_mixin'
4
-
3
+ #
4
+ # Here's how to set up a Gruff::StackedArea.
5
+ #
6
+ # g = Gruff::StackedArea.new
7
+ # g.title = 'StackedArea Graph'
8
+ # g.data :Jimmy, [25, 36, 86, 39, 25, 31, 79, 88]
9
+ # g.data :Charles, [80, 54, 67, 54, 68, 70, 90, 95]
10
+ # g.data :Julie, [22, 29, 35, 38, 36, 40, 46, 57]
11
+ # g.write('stacked_area.png')
12
+ #
5
13
  class Gruff::StackedArea < Gruff::Base
6
14
  include StackedMixin
7
- attr_accessor :last_series_goes_on_bottom
8
-
15
+ attr_writer :last_series_goes_on_bottom
16
+
17
+ def initialize_ivars
18
+ super
19
+ @last_series_goes_on_bottom = false
20
+ end
21
+ private :initialize_ivars
22
+
9
23
  def draw
10
- get_maximum_by_stack
24
+ calculate_maximum_by_stack
11
25
  super
12
26
 
13
- return unless @has_data
27
+ return unless data_given?
14
28
 
15
- @x_increment = @graph_width / (@column_count - 1).to_f
16
- @d = @d.stroke 'transparent'
29
+ x_increment = @graph_width / (column_count - 1).to_f
17
30
 
18
- height = Array.new(@column_count, 0)
31
+ height = Array.new(column_count, 0)
19
32
 
20
33
  data_points = nil
21
- iterator = last_series_goes_on_bottom ? :reverse_each : :each
22
- @norm_data.send(iterator) do |data_row|
34
+ iterator = @last_series_goes_on_bottom ? :reverse_each : :each
35
+ store.norm_data.public_send(iterator) do |data_row|
23
36
  prev_data_points = data_points
24
- data_points = Array.new
25
-
26
- @d = @d.fill data_row[DATA_COLOR_INDEX]
37
+ data_points = []
27
38
 
28
- data_row[DATA_VALUES_INDEX].each_with_index do |data_point, index|
39
+ data_row.points.each_with_index do |data_point, index|
29
40
  # Use incremented x and scaled y
30
- new_x = @graph_left + (@x_increment * index)
41
+ new_x = @graph_left + (x_increment * index)
31
42
  new_y = @graph_top + (@graph_height - data_point * @graph_height - height[index])
32
43
 
33
44
  height[index] += (data_point * @graph_height)
34
-
45
+
35
46
  data_points << new_x
36
47
  data_points << new_y
37
-
38
- draw_label(new_x, index)
39
48
 
49
+ draw_label(new_x, index)
40
50
  end
41
51
 
52
+ poly_points = data_points.dup
42
53
  if prev_data_points
43
- poly_points = data_points.dup
44
- (prev_data_points.length/2 - 1).downto(0) do |i|
45
- poly_points << prev_data_points[2*i]
46
- poly_points << prev_data_points[2*i+1]
54
+ (prev_data_points.length / 2 - 1).downto(0) do |i|
55
+ poly_points << prev_data_points[2 * i]
56
+ poly_points << prev_data_points[2 * i + 1]
47
57
  end
48
- poly_points << data_points[0]
49
- poly_points << data_points[1]
50
58
  else
51
- poly_points = data_points.dup
52
59
  poly_points << @graph_right
53
60
  poly_points << @graph_bottom - 1
54
61
  poly_points << @graph_left
55
62
  poly_points << @graph_bottom - 1
56
- poly_points << data_points[0]
57
- poly_points << data_points[1]
58
63
  end
59
- @d = @d.polyline(*poly_points)
64
+ poly_points << data_points[0]
65
+ poly_points << data_points[1]
60
66
 
67
+ Gruff::Renderer::Polygon.new(color: data_row.color).render(poly_points)
61
68
  end
62
-
63
- @d.draw(@base_image)
64
69
  end
65
-
66
-
67
70
  end
@@ -1,61 +1,106 @@
1
+ # frozen_string_literal: true
1
2
 
2
- require File.dirname(__FILE__) + '/base'
3
- require File.dirname(__FILE__) + '/stacked_mixin'
4
-
3
+ #
4
+ # Here's how to set up a Gruff::StackedBar.
5
+ #
6
+ # g = Gruff::StackedBar.new
7
+ # g.title = 'StackedBar Graph'
8
+ # g.data :Art, [0, 5, 8, 15]
9
+ # g.data :Philosophy, [10, 3, 2, 8]
10
+ # g.data :Science, [2, 15, 8, 11]
11
+ # g.write('stacked_bar.png')
12
+ #
5
13
  class Gruff::StackedBar < Gruff::Base
6
- include StackedMixin
7
-
8
- # Spacing factor applied between bars
9
- attr_accessor :bar_spacing
10
-
11
- # Number of pixels between bar segments
12
- attr_accessor :segment_spacing
13
-
14
- # Draws a bar graph, but multiple sets are stacked on top of each other.
15
- def draw
16
- get_maximum_by_stack
17
- super
18
- return unless @has_data
19
-
20
- # Setup spacing.
21
- #
22
- # Columns sit stacked.
23
- @bar_spacing ||= 0.9
24
- @segment_spacing ||= 1
25
- @bar_width = @graph_width / @column_count.to_f
26
- padding = (@bar_width * (1 - @bar_spacing)) / 2
27
-
28
- @d = @d.stroke_opacity 0.0
29
-
30
- height = Array.new(@column_count, 0)
31
-
32
- @norm_data.each_with_index do |data_row, row_index|
33
- data_row[DATA_VALUES_INDEX].each_with_index do |data_point, point_index|
34
- @d = @d.fill data_row[DATA_COLOR_INDEX]
35
-
36
- # Calculate center based on bar_width and current row
37
- label_center = @graph_left + (@bar_width * point_index) + (@bar_width * @bar_spacing / 2.0)
38
- draw_label(label_center, point_index)
39
-
40
- next if (data_point == 0)
41
- # Use incremented x and scaled y
42
- left_x = @graph_left + (@bar_width * point_index) + padding
43
- left_y = @graph_top + (@graph_height -
44
- data_point * @graph_height -
45
- height[point_index]) + @segment_spacing
46
- right_x = left_x + @bar_width * @bar_spacing
47
- right_y = @graph_top + @graph_height - height[point_index] - @segment_spacing
48
-
49
- # update the total height of the current stacked bar
50
- height[point_index] += (data_point * @graph_height )
51
-
52
- @d = @d.rectangle(left_x, left_y, right_x, right_y)
53
-
54
- end
14
+ include StackedMixin
15
+ include BarValueLabelMixin
16
+
17
+ # Spacing factor applied between bars.
18
+ attr_writer :bar_spacing
19
+
20
+ # Number of pixels between bar segments.
21
+ attr_writer :segment_spacing
22
+
23
+ # Set the number output format for labels using sprintf.
24
+ # Default is +"%.2f"+.
25
+ attr_writer :label_formatting
26
+
27
+ # Output the values for the bars on a bar graph.
28
+ # Default is +false+.
29
+ attr_writer :show_labels_for_bar_values
30
+
31
+ # Prevent drawing of column labels below a stacked bar graph. Default is +false+.
32
+ attr_writer :hide_labels
33
+
34
+ def initialize_ivars
35
+ super
36
+ @bar_spacing = 0.9
37
+ @segment_spacing = 2
38
+ @label_formatting = nil
39
+ @show_labels_for_bar_values = false
40
+ @hide_labels = false
41
+ end
42
+ private :initialize_ivars
43
+
44
+ # Draws a bar graph, but multiple sets are stacked on top of each other.
45
+ def draw
46
+ calculate_maximum_by_stack
47
+ super
48
+ return unless data_given?
49
+
50
+ # Setup spacing.
51
+ #
52
+ # Columns sit stacked.
53
+ bar_width = @graph_width / column_count.to_f
54
+ padding = (bar_width * (1 - @bar_spacing)) / 2
55
+
56
+ height = Array.new(column_count, 0)
57
+ bar_value_label = BarValueLabel.new(column_count, bar_width)
58
+
59
+ store.norm_data.each_with_index do |data_row, row_index|
60
+ data_row.points.each_with_index do |data_point, point_index|
61
+ next if data_point == 0
55
62
 
63
+ # Use incremented x and scaled y
64
+ left_x = @graph_left + (bar_width * point_index) + padding
65
+ left_y = @graph_top + (@graph_height -
66
+ data_point * @graph_height -
67
+ height[point_index]) + @segment_spacing
68
+ right_x = left_x + bar_width * @bar_spacing
69
+ right_y = @graph_top + @graph_height - height[point_index]
70
+
71
+ # update the total height of the current stacked bar
72
+ height[point_index] += (data_point * @graph_height)
73
+
74
+ rect_renderer = Gruff::Renderer::Rectangle.new(color: data_row.color)
75
+ rect_renderer.render(left_x, left_y, right_x, right_y)
76
+
77
+ # Calculate center based on bar_width and current row
78
+ label_center = left_x + bar_width * @bar_spacing / 2.0
79
+ draw_label(label_center, point_index)
80
+
81
+ bar_value_label.coordinates[point_index] = [left_x, left_y, right_x, right_y]
82
+ bar_value_label.values[point_index] += store.data[row_index].points[point_index]
83
+ end
84
+ end
85
+
86
+ if @show_labels_for_bar_values
87
+ bar_value_label.prepare_rendering(@label_formatting) do |x, y, text|
88
+ draw_value_label(x, y, text, true)
56
89
  end
57
-
58
- @d.draw(@base_image)
59
90
  end
91
+ end
92
+
93
+ protected
94
+
95
+ def hide_labels?
96
+ @hide_labels
97
+ end
98
+
99
+ def hide_left_label_area?
100
+ @hide_line_markers
101
+ end
60
102
 
103
+ def hide_bottom_label_area?
104
+ hide_labels?
105
+ end
61
106
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gruff
4
+ class Store
5
+ # @private
6
+ class BasicData < Struct.new(:label, :points, :color)
7
+ def initialize(label, points, color)
8
+ super(label.to_s, Array(points), color)
9
+ end
10
+
11
+ def empty?
12
+ points.empty?
13
+ end
14
+
15
+ def columns
16
+ points.length
17
+ end
18
+
19
+ def min
20
+ points.compact.min
21
+ end
22
+
23
+ def max
24
+ points.compact.max
25
+ end
26
+
27
+ def normalize(minimum:, spread:)
28
+ norm_points = points.map do |point|
29
+ point.nil? ? nil : (point.to_f - minimum.to_f) / spread
30
+ end
31
+
32
+ self.class.new(label, norm_points, color)
33
+ end
34
+ end
35
+ end
36
+ end