gruff 0.10.0-java → 0.13.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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +24 -4
  4. data/.rubocop_todo.yml +94 -42
  5. data/.travis.yml +3 -6
  6. data/CHANGELOG.md +35 -0
  7. data/README.md +10 -1
  8. data/assets/fonts/LICENSE.txt +202 -0
  9. data/assets/fonts/Roboto-Bold.ttf +0 -0
  10. data/assets/fonts/Roboto-Regular.ttf +0 -0
  11. data/gruff.gemspec +8 -3
  12. data/lib/gruff.rb +8 -3
  13. data/lib/gruff/accumulator_bar.rb +0 -2
  14. data/lib/gruff/area.rb +2 -6
  15. data/lib/gruff/bar.rb +35 -35
  16. data/lib/gruff/base.rb +295 -188
  17. data/lib/gruff/bezier.rb +0 -4
  18. data/lib/gruff/bullet.rb +12 -14
  19. data/lib/gruff/dot.rb +8 -33
  20. data/lib/gruff/helper/bar_conversion.rb +34 -19
  21. data/lib/gruff/helper/bar_value_label.rb +68 -0
  22. data/lib/gruff/histogram.rb +25 -25
  23. data/lib/gruff/line.rb +29 -26
  24. data/lib/gruff/mini/bar.rb +1 -1
  25. data/lib/gruff/mini/legend.rb +9 -4
  26. data/lib/gruff/mini/pie.rb +1 -2
  27. data/lib/gruff/mini/side_bar.rb +1 -2
  28. data/lib/gruff/net.rb +19 -20
  29. data/lib/gruff/patch/rmagick.rb +22 -24
  30. data/lib/gruff/patch/string.rb +7 -4
  31. data/lib/gruff/photo_bar.rb +12 -16
  32. data/lib/gruff/pie.rb +19 -30
  33. data/lib/gruff/renderer/bezier.rb +4 -3
  34. data/lib/gruff/renderer/circle.rb +4 -3
  35. data/lib/gruff/renderer/dash_line.rb +4 -3
  36. data/lib/gruff/renderer/dot.rb +4 -3
  37. data/lib/gruff/renderer/ellipse.rb +4 -3
  38. data/lib/gruff/renderer/line.rb +14 -5
  39. data/lib/gruff/renderer/polygon.rb +5 -4
  40. data/lib/gruff/renderer/polyline.rb +4 -3
  41. data/lib/gruff/renderer/rectangle.rb +3 -2
  42. data/lib/gruff/renderer/renderer.rb +31 -38
  43. data/lib/gruff/renderer/text.rb +39 -9
  44. data/lib/gruff/scatter.rb +30 -44
  45. data/lib/gruff/scene.rb +0 -1
  46. data/lib/gruff/side_bar.rb +60 -45
  47. data/lib/gruff/side_stacked_bar.rb +30 -19
  48. data/lib/gruff/spider.rb +18 -17
  49. data/lib/gruff/stacked_area.rb +8 -7
  50. data/lib/gruff/stacked_bar.rb +28 -18
  51. data/lib/gruff/store/{base_data.rb → basic_data.rb} +9 -7
  52. data/lib/gruff/store/custom_data.rb +8 -6
  53. data/lib/gruff/store/store.rb +6 -5
  54. data/lib/gruff/store/xy_data.rb +10 -7
  55. data/lib/gruff/version.rb +1 -1
  56. metadata +36 -9
  57. data/Rakefile +0 -23
  58. data/docker/Dockerfile +0 -14
  59. data/docker/build.sh +0 -4
  60. data/docker/launch.sh +0 -4
  61. data/lib/gruff/helper/bar_value_label_mixin.rb +0 -30
data/lib/gruff/bezier.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'gruff/base'
4
-
5
3
  #
6
4
  # Gruff::Bezier is a special line graph that have
7
5
  # the bezier curve.
@@ -55,7 +53,5 @@ class Gruff::Bezier < Gruff::Base
55
53
  Gruff::Renderer::Bezier.new(color: data_row.color, width: stroke_width).render(poly_points)
56
54
  end
57
55
  end
58
-
59
- Gruff::Renderer.finish
60
56
  end
61
57
  end
data/lib/gruff/bullet.rb CHANGED
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'gruff/base'
4
- require 'gruff/themes'
5
-
6
3
  #
7
4
  # A bullet graph is a variation of a bar graph.
8
5
  # http://en.wikipedia.org/wiki/Bullet_graph
@@ -16,10 +13,10 @@ require 'gruff/themes'
16
13
  #
17
14
  class Gruff::Bullet < Gruff::Base
18
15
  def initialize(target_width = '400x40')
16
+ super
17
+
19
18
  if target_width.is_a?(String)
20
- geometric_width, geometric_height = target_width.split('x')
21
- @columns = geometric_width.to_f
22
- @rows = geometric_height.to_f
19
+ @columns, @rows = target_width.split('x').map(&:to_f)
23
20
  else
24
21
  @columns = target_width.to_f
25
22
  @rows = target_width.to_f / 5.0
@@ -27,12 +24,15 @@ class Gruff::Bullet < Gruff::Base
27
24
  @columns.freeze
28
25
  @rows.freeze
29
26
 
30
- initialize_ivars
31
-
32
- reset_themes
33
27
  self.theme = Gruff::Themes::GREYSCALE
28
+ end
29
+
30
+ def initialize_ivars
31
+ super
32
+
34
33
  @title_font_size = 20
35
34
  end
35
+ private :initialize_ivars
36
36
 
37
37
  def data(value, maximum_value, options = {})
38
38
  @value = value.to_f
@@ -55,7 +55,7 @@ class Gruff::Bullet < Gruff::Base
55
55
  margin = 30.0
56
56
  thickness = @raw_rows / 6.0
57
57
  right_margin = margin
58
- graph_left = (@title && (title_width * 1.3)) || margin
58
+ graph_left = [title_width * 1.3, margin].max
59
59
  graph_width = @raw_columns - graph_left - right_margin
60
60
  graph_height = thickness * 3.0
61
61
 
@@ -83,18 +83,16 @@ class Gruff::Bullet < Gruff::Base
83
83
  # Value
84
84
  rect_renderer = Gruff::Renderer::Rectangle.new(color: @font_color)
85
85
  rect_renderer.render(graph_left, thickness, graph_left + graph_width * (@value / maximum_value), thickness * 2)
86
-
87
- Gruff::Renderer.finish
88
86
  end
89
87
 
90
88
  private
91
89
 
92
90
  def draw_title
93
- return unless @title
91
+ return if hide_title?
94
92
 
95
93
  font_height = calculate_caps_height(scale_fontsize(@title_font_size))
96
94
 
97
95
  text_renderer = Gruff::Renderer::Text.new(@title, font: @font, size: @title_font_size, color: @font_color)
98
- text_renderer.render(1.0, 1.0, font_height / 2, font_height / 2, Magick::NorthWestGravity)
96
+ text_renderer.add_to_render_queue(1.0, 1.0, font_height / 2, font_height / 2, Magick::NorthWestGravity)
99
97
  end
100
98
  end
data/lib/gruff/dot.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'gruff/base'
4
-
5
3
  #
6
4
  # Graph with dots and labels along a vertical access.
7
5
  # see: 'Creating More Effective Graphs' by Robbins
@@ -44,8 +42,6 @@ class Gruff::Dot < Gruff::Base
44
42
  draw_label(y_pos, point_index)
45
43
  end
46
44
  end
47
-
48
- Gruff::Renderer.finish
49
45
  end
50
46
 
51
47
  protected
@@ -54,37 +50,17 @@ protected
54
50
  def draw_line_markers
55
51
  return if @hide_line_markers
56
52
 
57
- # Draw horizontal line markers and annotate with numbers
58
- if @y_axis_increment
59
- increment = @y_axis_increment
60
- number_of_lines = (@spread / @y_axis_increment).to_i
61
- else
62
- # Try to use a number of horizontal lines that will come out even.
63
- #
64
- # TODO Do the same for larger numbers...100, 75, 50, 25
65
- if @marker_count.nil?
66
- (3..7).each do |lines|
67
- if @spread % lines == 0.0
68
- @marker_count = lines
69
- break
70
- end
71
- end
72
- @marker_count ||= 5
73
- end
74
- # TODO: Round maximum marker value to a round number like 100, 0.1, 0.5, etc.
75
- increment = (@spread > 0 && @marker_count > 0) ? significant(@spread / @marker_count) : 1
76
- number_of_lines = @marker_count
77
- end
78
-
79
- (0..number_of_lines).each do |index|
80
- marker_label = minimum_value + index * increment
53
+ (0..marker_count).each do |index|
54
+ marker_label = BigDecimal(index.to_s) * BigDecimal(@increment.to_s) + BigDecimal(minimum_value.to_s)
81
55
  x = @graph_left + (marker_label - minimum_value) * @graph_width / @spread
82
- Gruff::Renderer::Line.new(color: @marker_color).render(x, @graph_bottom, x, @graph_bottom + 0.5 * LABEL_MARGIN)
56
+
57
+ line_renderer = Gruff::Renderer::Line.new(color: @marker_color, shadow_color: @marker_shadow_color)
58
+ line_renderer.render(x, @graph_bottom, x, @graph_bottom + 5)
83
59
 
84
60
  unless @hide_line_numbers
85
- label = label(marker_label, increment)
61
+ label = y_axis_label(marker_label, @increment)
86
62
  text_renderer = Gruff::Renderer::Text.new(label, font: @font, size: @marker_font_size, color: @font_color)
87
- text_renderer.render(0, 0, x, @graph_bottom + (LABEL_MARGIN * 2.0), Magick::CenterGravity)
63
+ text_renderer.add_to_render_queue(0, 0, x, @graph_bottom + (LABEL_MARGIN * 1.5), Magick::CenterGravity)
88
64
  end
89
65
  end
90
66
  end
@@ -94,8 +70,7 @@ protected
94
70
 
95
71
  def draw_label(y_offset, index)
96
72
  draw_unique_label(index) do
97
- text_renderer = Gruff::Renderer::Text.new(@labels[index], font: @font, size: @marker_font_size, color: @font_color)
98
- text_renderer.render(@graph_left - LABEL_MARGIN * 2, 1.0, 0.0, y_offset, Magick::EastGravity)
73
+ draw_label_at(@graph_left - LABEL_MARGIN, 1.0, 0.0, y_offset, @labels[index], Magick::EastGravity)
99
74
  end
100
75
  end
101
76
  end
@@ -3,7 +3,7 @@
3
3
  ##
4
4
  # Original Author: David Stokar
5
5
  #
6
- # This class perfoms the y coordinats conversion for the bar class.
6
+ # This class performs the y coordinates conversion for the bar class.
7
7
  #
8
8
  # There are three cases:
9
9
  #
@@ -14,29 +14,44 @@
14
14
  # @private
15
15
  class Gruff::BarConversion
16
16
  attr_writer :mode
17
- attr_writer :zero
18
- attr_writer :graph_top
19
- attr_writer :graph_height
20
- attr_writer :minimum_value
21
- attr_writer :spread
22
17
 
23
- def get_left_y_right_y_scaled(data_point)
18
+ def initialize(top:, bottom:, minimum_value:, maximum_value:, spread:)
19
+ @graph_top = top
20
+ @graph_height = bottom - top
21
+ @spread = spread
22
+ @minimum_value = minimum_value
23
+ @maximum_value = maximum_value
24
+
25
+ if minimum_value >= 0
26
+ # all bars go from zero to positive
27
+ @mode = 1
28
+ elsif maximum_value <= 0
29
+ # all bars go from 0 to negative
30
+ @mode = 2
31
+ else
32
+ # bars either go from zero to negative or to positive
33
+ @mode = 3
34
+ @zero = -minimum_value / @spread
35
+ end
36
+ end
37
+
38
+ def get_top_bottom_scaled(data_point)
24
39
  result = []
25
40
 
26
41
  case @mode
27
- when 1 then # Case one
28
- # minimum value >= 0 ( only positive values )
29
- result[0] = @graph_top + @graph_height * (1 - data_point) + 1
30
- result[1] = @graph_top + @graph_height - 1
31
- when 2 then # Case two
32
- # only negative values
33
- result[0] = @graph_top + 1
34
- result[1] = @graph_top + @graph_height * (1 - data_point) - 1
35
- when 3 then # Case three
36
- # positive and negative values
42
+ when 1
43
+ # minimum value >= 0 ( only positive values )
44
+ result[0] = @graph_top + @graph_height * (1 - data_point)
45
+ result[1] = @graph_top + @graph_height
46
+ when 2
47
+ # only negative values
48
+ result[0] = @graph_top
49
+ result[1] = @graph_top + @graph_height * (1 - data_point)
50
+ when 3
51
+ # positive and negative values
37
52
  val = data_point - @minimum_value / @spread
38
- result[0] = @graph_top + @graph_height * (1 - (val - @zero)) + 1
39
- result[1] = @graph_top + @graph_height * (1 - @zero) - 1
53
+ result[0] = @graph_top + @graph_height * (1 - (val - @zero))
54
+ result[1] = @graph_top + @graph_height * (1 - @zero)
40
55
  else
41
56
  result[0] = 0.0
42
57
  result[1] = 0.0
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @private
4
+ module Gruff::BarValueLabel
5
+ using String::GruffCommify
6
+
7
+ # @private
8
+ class Base
9
+ attr_reader :coordinate, :value
10
+
11
+ def initialize(coordinate, value)
12
+ @coordinate = coordinate
13
+ @value = value
14
+ end
15
+ end
16
+
17
+ # @private
18
+ class Bar < Base
19
+ def prepare_rendering(format, _bar_width = 0)
20
+ left_x, left_y, right_x, _right_y = @coordinate
21
+ if format.is_a?(Proc)
22
+ val = format.call(@value)
23
+ else
24
+ val = sprintf(format || '%.2f', @value).commify
25
+ end
26
+
27
+ y = @value >= 0 ? left_y - 30 : left_y + 12
28
+ yield left_x + (right_x - left_x) / 2, y, val
29
+ end
30
+ end
31
+
32
+ # @private
33
+ class SideBar < Base
34
+ def prepare_rendering(format, bar_width = 0)
35
+ left_x, _left_y, right_x, right_y = @coordinate
36
+ if format.is_a?(Proc)
37
+ val = format.call(@value)
38
+ else
39
+ val = sprintf(format || '%.2f', @value).commify
40
+ end
41
+
42
+ x = @value >= 0 ? right_x + 40 : left_x - 40
43
+ yield x, right_y - bar_width / 2, val
44
+ end
45
+ end
46
+
47
+ # @private
48
+ class StackedBar
49
+ def initialize
50
+ @bars = []
51
+ end
52
+
53
+ def add(bar, index)
54
+ bars = @bars[index] || []
55
+ bars << bar
56
+ @bars[index] = bars
57
+ end
58
+
59
+ def prepare_rendering(format, bar_width = 0, &block)
60
+ @bars.each do |bars|
61
+ value = bars.sum(&:value)
62
+ bar = bars.last
63
+ bar_value_label = bar.class.new(bar.coordinate, value)
64
+ bar_value_label.prepare_rendering(format, bar_width, &block)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'histogram'
4
- require 'gruff/base'
5
4
 
6
5
  #
7
6
  # Here's how to set up a Gruff::Histogram.
@@ -15,6 +14,20 @@ require 'gruff/base'
15
14
  # g.write('histogram.png')
16
15
  #
17
16
  class Gruff::Histogram < Gruff::Bar
17
+ # Specifies interpolation between the min and max of the set. Default is +10+.
18
+ attr_writer :bin_width
19
+
20
+ # Specifies minimum value for bin.
21
+ attr_writer :minimum_bin
22
+
23
+ # Specifies maximum value for bin.
24
+ attr_writer :maximum_bin
25
+
26
+ def initialize(*)
27
+ super
28
+ @data = []
29
+ end
30
+
18
31
  def initialize_ivars
19
32
  super
20
33
  @bin_width = 10
@@ -23,33 +36,20 @@ class Gruff::Histogram < Gruff::Bar
23
36
  end
24
37
  private :initialize_ivars
25
38
 
26
- # Specifies interpolation between the min and max of the set. Default is +10+.
27
- def bin_width=(width)
28
- raise 'bin_width= should be called before set the data.' unless store.empty?
29
-
30
- @bin_width = width
31
- end
32
-
33
- # Specifies minimum value for bin.
34
- def minimum_bin=(min)
35
- raise 'minimum_bin= should be called before set the data.' unless store.empty?
36
-
37
- @minimum_bin = min
38
- end
39
-
40
- # Specifies maximum value for bin.
41
- def maximum_bin=(max)
42
- raise 'maximum_bin= should be called before set the data.' unless store.empty?
43
-
44
- @maximum_bin = max
39
+ def data(name, data_points = [], color = nil)
40
+ @data << [name, data_points, color]
45
41
  end
46
42
 
47
- def data(name, data_points = [], color = nil)
48
- bins, freqs = HistogramArray.new(data_points).histogram(bin_width: @bin_width, min: @minimum_bin, max: @maximum_bin)
49
- bins.each_with_index do |bin, index|
50
- labels[index] = bin
43
+ def draw
44
+ @data.each do |(name, data_points, color)|
45
+ bins, freqs = HistogramArray.new(data_points).histogram(bin_width: @bin_width, min: @minimum_bin, max: @maximum_bin)
46
+ bins.each_with_index do |bin, index|
47
+ @labels[index] = bin
48
+ end
49
+ store.add(name, freqs, color)
51
50
  end
52
- store.add(name, freqs, color)
51
+
52
+ super
53
53
  end
54
54
 
55
55
  # @private
data/lib/gruff/line.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'gruff/base'
4
-
5
3
  #
6
4
  # Here's how to make a Gruff::Line.
7
5
  #
@@ -12,32 +10,32 @@ require 'gruff/base'
12
10
  # g.write("line.png")
13
11
  #
14
12
  # There are also other options described below, such as {#baseline_value}, {#baseline_color},
15
- # {#hide_dots}, and {#hide_lines}.
13
+ # {#hide_dots=}, and {#hide_lines=}.
16
14
  #
17
15
  class Gruff::Line < Gruff::Base
18
16
  # Allow for reference lines ( which are like baseline ... just allowing for more & on both axes ).
19
17
  attr_accessor :reference_lines
20
- attr_accessor :reference_line_default_color
21
- attr_accessor :reference_line_default_width
18
+ attr_writer :reference_line_default_color
19
+ attr_writer :reference_line_default_width
22
20
 
23
21
  # Allow for vertical marker lines.
24
- attr_accessor :show_vertical_markers
22
+ attr_writer :show_vertical_markers
25
23
 
26
24
  # Dimensions of lines and dots; calculated based on dataset size if left unspecified.
27
- attr_accessor :line_width
28
- attr_accessor :dot_radius
25
+ attr_writer :line_width
26
+ attr_writer :dot_radius
29
27
 
30
28
  # default is +'circle'+, other options include square.
31
- attr_accessor :dot_style
29
+ attr_writer :dot_style
32
30
 
33
- # Hide parts of the graph to fit more datapoints, or for a different appearance.
34
- attr_accessor :hide_dots, :hide_lines
31
+ # Hide parts of the graph to fit more data points, or for a different appearance.
32
+ attr_writer :hide_dots, :hide_lines
35
33
 
36
34
  # accessors for support of xy data.
37
- attr_accessor :minimum_x_value
35
+ attr_writer :minimum_x_value
38
36
 
39
37
  # accessors for support of xy data.
40
- attr_accessor :maximum_x_value
38
+ attr_writer :maximum_x_value
41
39
 
42
40
  # Get the value if somebody has defined it.
43
41
  def baseline_value
@@ -69,7 +67,7 @@ class Gruff::Line < Gruff::Base
69
67
  # g = Gruff::Line.new(400, false) # 400px wide, no lines (for backwards compatibility)
70
68
  # g = Gruff::Line.new(false) # Defaults to 800px wide, no lines (for backwards compatibility)
71
69
  #
72
- # The preferred way is to call {#hide_dots} or {#hide_lines} instead.
70
+ # The preferred way is to call {#hide_dots=} or {#hide_lines=} instead.
73
71
  def initialize(*args)
74
72
  raise ArgumentError, 'Wrong number of arguments' if args.length > 2
75
73
 
@@ -78,7 +76,15 @@ class Gruff::Line < Gruff::Base
78
76
  else
79
77
  super args.shift
80
78
  end
79
+ end
80
+
81
+ def initialize_store
82
+ @store = Gruff::Store.new(Gruff::Store::XYData)
83
+ end
84
+ private :initialize_store
81
85
 
86
+ def initialize_ivars
87
+ super
82
88
  @reference_lines = {}
83
89
  @reference_line_default_color = 'red'
84
90
  @reference_line_default_width = 5
@@ -87,12 +93,13 @@ class Gruff::Line < Gruff::Base
87
93
  @maximum_x_value = nil
88
94
  @minimum_x_value = nil
89
95
 
96
+ @line_width = nil
97
+ @dot_radius = nil
90
98
  @dot_style = 'circle'
91
99
 
92
100
  @show_vertical_markers = false
93
-
94
- @store = Gruff::Store.new(Gruff::Store::XYData)
95
101
  end
102
+ private :initialize_ivars
96
103
 
97
104
  # This method allows one to plot a dataset with both X and Y data.
98
105
  #
@@ -125,7 +132,7 @@ class Gruff::Line < Gruff::Base
125
132
  # g.data("Capples", [1, 1, 2, 2, 3, 3])
126
133
  #
127
134
  # # labels will be drawn at the x locations of the keys passed in.
128
- # In this example the lables are drawn at x positions 2, 4, and 6:
135
+ # In this example the labels are drawn at x positions 2, 4, and 6:
129
136
  # g.labels = {0 => '2003', 2 => '2004', 4 => '2005', 6 => '2006'}
130
137
  # # The 0 => '2003' label will be ignored since it is outside the chart range.
131
138
  def dataxy(name, x_data_points = [], y_data_points = [], color = nil)
@@ -146,11 +153,9 @@ class Gruff::Line < Gruff::Base
146
153
  end
147
154
 
148
155
  def draw_reference_line(reference_line, left, right, top, bottom)
149
- config = {
150
- color: reference_line[:color] || @reference_line_default_color,
151
- width: reference_line[:width] || @reference_line_default_width
152
- }
153
- Gruff::Renderer::DashLine.new(config).render(left, top, right, bottom)
156
+ color = reference_line[:color] || @reference_line_default_color
157
+ width = reference_line[:width] || @reference_line_default_width
158
+ Gruff::Renderer::DashLine.new(color: color, width: width).render(left, top, right, bottom)
154
159
  end
155
160
 
156
161
  def draw_horizontal_reference_line(reference_line)
@@ -212,8 +217,8 @@ class Gruff::Line < Gruff::Base
212
217
  new_y = @graph_top + (@graph_height - y_data * @graph_height)
213
218
 
214
219
  # Reset each time to avoid thin-line errors
215
- stroke_width = line_width || clip_value_if_greater_than(@columns / (store.norm_data.first.y_points.size * 4), 5.0)
216
- circle_radius = dot_radius || clip_value_if_greater_than(@columns / (store.norm_data.first.y_points.size * 2.5), 5.0)
220
+ stroke_width = @line_width || clip_value_if_greater_than(@columns / (store.norm_data.first.y_points.size * 4), 5.0)
221
+ circle_radius = @dot_radius || clip_value_if_greater_than(@columns / (store.norm_data.first.y_points.size * 2.5), 5.0)
217
222
 
218
223
  if !@hide_lines && prev_x && prev_y
219
224
  Gruff::Renderer::Line.new(color: data_row.color, width: stroke_width)
@@ -228,8 +233,6 @@ class Gruff::Line < Gruff::Base
228
233
  prev_y = new_y
229
234
  end
230
235
  end
231
-
232
- Gruff::Renderer.finish
233
236
  end
234
237
 
235
238
  private