gruff 0.5.1-java → 0.10.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 (120) hide show
  1. checksums.yaml +5 -5
  2. data/.editorconfig +14 -0
  3. data/.github/ISSUE_TEMPLATE.md +18 -0
  4. data/.gitignore +3 -0
  5. data/.rubocop.yml +109 -0
  6. data/.rubocop_todo.yml +130 -0
  7. data/.travis.yml +24 -12
  8. data/.yardopts +1 -0
  9. data/{History.txt → CHANGELOG.md} +61 -25
  10. data/Gemfile +3 -7
  11. data/README.md +57 -25
  12. data/Rakefile +6 -201
  13. data/assets/plastik/blue.png +0 -0
  14. data/assets/plastik/green.png +0 -0
  15. data/assets/plastik/red.png +0 -0
  16. data/docker/Dockerfile +14 -0
  17. data/docker/build.sh +4 -0
  18. data/docker/launch.sh +4 -0
  19. data/gruff.gemspec +19 -14
  20. data/init.rb +2 -0
  21. data/lib/gruff.rb +26 -2
  22. data/lib/gruff/accumulator_bar.rb +18 -8
  23. data/lib/gruff/area.rb +33 -19
  24. data/lib/gruff/bar.rb +76 -45
  25. data/lib/gruff/base.rb +337 -613
  26. data/lib/gruff/bezier.rb +34 -19
  27. data/lib/gruff/bullet.rb +51 -62
  28. data/lib/gruff/dot.rb +38 -62
  29. data/lib/gruff/helper/bar_conversion.rb +47 -0
  30. data/lib/gruff/helper/bar_value_label_mixin.rb +30 -0
  31. data/lib/gruff/helper/stacked_mixin.rb +23 -0
  32. data/lib/gruff/histogram.rb +59 -0
  33. data/lib/gruff/line.rb +130 -150
  34. data/lib/gruff/mini/bar.rb +17 -10
  35. data/lib/gruff/mini/legend.rb +24 -36
  36. data/lib/gruff/mini/pie.rb +18 -12
  37. data/lib/gruff/mini/side_bar.rb +26 -12
  38. data/lib/gruff/net.rb +60 -84
  39. data/lib/gruff/patch/rmagick.rb +33 -0
  40. data/lib/gruff/patch/string.rb +10 -0
  41. data/lib/gruff/photo_bar.rb +27 -30
  42. data/lib/gruff/pie.rb +190 -93
  43. data/lib/gruff/renderer/bezier.rb +21 -0
  44. data/lib/gruff/renderer/circle.rb +21 -0
  45. data/lib/gruff/renderer/dash_line.rb +22 -0
  46. data/lib/gruff/renderer/dot.rb +39 -0
  47. data/lib/gruff/renderer/ellipse.rb +21 -0
  48. data/lib/gruff/renderer/line.rb +34 -0
  49. data/lib/gruff/renderer/polygon.rb +23 -0
  50. data/lib/gruff/renderer/polyline.rb +21 -0
  51. data/lib/gruff/renderer/rectangle.rb +19 -0
  52. data/lib/gruff/renderer/renderer.rb +127 -0
  53. data/lib/gruff/renderer/text.rb +42 -0
  54. data/lib/gruff/scatter.rb +156 -180
  55. data/lib/gruff/scene.rb +31 -41
  56. data/lib/gruff/side_bar.rb +77 -63
  57. data/lib/gruff/side_stacked_bar.rb +77 -60
  58. data/lib/gruff/spider.rb +37 -50
  59. data/lib/gruff/stacked_area.rb +32 -30
  60. data/lib/gruff/stacked_bar.rb +87 -49
  61. data/lib/gruff/store/base_data.rb +34 -0
  62. data/lib/gruff/store/custom_data.rb +34 -0
  63. data/lib/gruff/store/store.rb +80 -0
  64. data/lib/gruff/store/xy_data.rb +55 -0
  65. data/lib/gruff/themes.rb +32 -33
  66. data/lib/gruff/version.rb +3 -1
  67. metadata +88 -94
  68. data/Manifest.txt +0 -81
  69. data/RELEASE.md +0 -30
  70. data/assets/bubble.png +0 -0
  71. data/assets/city_scene/background/0000.png +0 -0
  72. data/assets/city_scene/background/0600.png +0 -0
  73. data/assets/city_scene/background/2000.png +0 -0
  74. data/assets/city_scene/clouds/cloudy.png +0 -0
  75. data/assets/city_scene/clouds/partly_cloudy.png +0 -0
  76. data/assets/city_scene/clouds/stormy.png +0 -0
  77. data/assets/city_scene/grass/default.png +0 -0
  78. data/assets/city_scene/haze/true.png +0 -0
  79. data/assets/city_scene/number_sample/1.png +0 -0
  80. data/assets/city_scene/number_sample/2.png +0 -0
  81. data/assets/city_scene/number_sample/default.png +0 -0
  82. data/assets/city_scene/sky/0000.png +0 -0
  83. data/assets/city_scene/sky/0200.png +0 -0
  84. data/assets/city_scene/sky/0400.png +0 -0
  85. data/assets/city_scene/sky/0600.png +0 -0
  86. data/assets/city_scene/sky/0800.png +0 -0
  87. data/assets/city_scene/sky/1000.png +0 -0
  88. data/assets/city_scene/sky/1200.png +0 -0
  89. data/assets/city_scene/sky/1400.png +0 -0
  90. data/assets/city_scene/sky/1500.png +0 -0
  91. data/assets/city_scene/sky/1700.png +0 -0
  92. data/assets/city_scene/sky/2000.png +0 -0
  93. data/assets/pc306715.jpg +0 -0
  94. data/lib/gruff/bar_conversion.rb +0 -46
  95. data/lib/gruff/deprecated.rb +0 -39
  96. data/lib/gruff/stacked_mixin.rb +0 -23
  97. data/test/gruff_test_case.rb +0 -154
  98. data/test/image_compare.rb +0 -58
  99. data/test/test_accumulator_bar.rb +0 -51
  100. data/test/test_area.rb +0 -134
  101. data/test/test_bar.rb +0 -505
  102. data/test/test_base.rb +0 -8
  103. data/test/test_bezier.rb +0 -33
  104. data/test/test_bullet.rb +0 -26
  105. data/test/test_dot.rb +0 -263
  106. data/test/test_legend.rb +0 -68
  107. data/test/test_line.rb +0 -657
  108. data/test/test_mini_bar.rb +0 -33
  109. data/test/test_mini_pie.rb +0 -25
  110. data/test/test_mini_side_bar.rb +0 -36
  111. data/test/test_net.rb +0 -231
  112. data/test/test_photo.rb +0 -41
  113. data/test/test_pie.rb +0 -154
  114. data/test/test_scatter.rb +0 -233
  115. data/test/test_scene.rb +0 -100
  116. data/test/test_side_bar.rb +0 -56
  117. data/test/test_sidestacked_bar.rb +0 -105
  118. data/test/test_spider.rb +0 -226
  119. data/test/test_stacked_area.rb +0 -52
  120. data/test/test_stacked_bar.rb +0 -52
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @private
4
+ module Gruff::Base::StackedMixin
5
+ # Used by StackedBar and child classes.
6
+ #
7
+ # tsal: moved from Base 03 FEB 2007
8
+ def calculate_maximum_by_stack
9
+ # Get sum of each stack
10
+ max_hash = {}
11
+ store.data.each do |data_set|
12
+ data_set.points.each_with_index do |data_point, i|
13
+ max_hash[i] = 0.0 unless max_hash[i]
14
+ max_hash[i] += data_point.to_f
15
+ end
16
+ end
17
+
18
+ max_hash.each_key do |key|
19
+ self.maximum_value = max_hash[key] if max_hash[key] > maximum_value
20
+ end
21
+ self.minimum_value = 0
22
+ end
23
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'histogram'
4
+ require 'gruff/base'
5
+
6
+ #
7
+ # Here's how to set up a Gruff::Histogram.
8
+ #
9
+ # g = Gruff::Histogram.new
10
+ # g.title = 'Histogram Graph'
11
+ # g.minimum_bin = 10
12
+ # g.bin_width = 20
13
+ # g.data :A, [10, 10, 20, 30, 40, 40, 40, 40, 40, 40, 50, 10, 10, 10]
14
+ # g.data :B, [100, 100, 100, 100, 90, 90, 80, 30, 30, 30, 30, 30]
15
+ # g.write('histogram.png')
16
+ #
17
+ class Gruff::Histogram < Gruff::Bar
18
+ def initialize_ivars
19
+ super
20
+ @bin_width = 10
21
+ @minimum_bin = nil
22
+ @maximum_bin = nil
23
+ end
24
+ private :initialize_ivars
25
+
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
45
+ end
46
+
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
51
+ end
52
+ store.add(name, freqs, color)
53
+ end
54
+
55
+ # @private
56
+ class HistogramArray < Array
57
+ include ::Histogram
58
+ end
59
+ end
@@ -1,163 +1,156 @@
1
- require File.dirname(__FILE__) + '/base'
1
+ # frozen_string_literal: true
2
2
 
3
- ##
4
- # Here's how to make a Line graph:
3
+ require 'gruff/base'
4
+
5
+ #
6
+ # Here's how to make a Gruff::Line.
5
7
  #
6
8
  # g = Gruff::Line.new
7
9
  # g.title = "A Line Graph"
8
10
  # g.data 'Fries', [20, 23, 19, 8]
9
11
  # g.data 'Hamburgers', [50, 19, 99, 29]
10
- # g.write("test/output/line.png")
12
+ # g.write("line.png")
13
+ #
14
+ # There are also other options described below, such as {#baseline_value}, {#baseline_color},
15
+ # {#hide_dots}, and {#hide_lines}.
11
16
  #
12
- # There are also other options described below, such as #baseline_value, #baseline_color, #hide_dots, and #hide_lines.
13
-
14
17
  class Gruff::Line < Gruff::Base
15
-
16
- # Allow for reference lines ( which are like baseline ... just allowing for more & on both axes )
18
+ # Allow for reference lines ( which are like baseline ... just allowing for more & on both axes ).
17
19
  attr_accessor :reference_lines
18
20
  attr_accessor :reference_line_default_color
19
21
  attr_accessor :reference_line_default_width
20
22
 
21
- # Dimensions of lines and dots; calculated based on dataset size if left unspecified
23
+ # Allow for vertical marker lines.
24
+ attr_accessor :show_vertical_markers
25
+
26
+ # Dimensions of lines and dots; calculated based on dataset size if left unspecified.
22
27
  attr_accessor :line_width
23
28
  attr_accessor :dot_radius
24
29
 
30
+ # default is +'circle'+, other options include square.
31
+ attr_accessor :dot_style
32
+
25
33
  # Hide parts of the graph to fit more datapoints, or for a different appearance.
26
34
  attr_accessor :hide_dots, :hide_lines
27
35
 
28
- #accessors for support of xy data
36
+ # accessors for support of xy data.
29
37
  attr_accessor :minimum_x_value
38
+
39
+ # accessors for support of xy data.
30
40
  attr_accessor :maximum_x_value
31
41
 
32
42
  # Get the value if somebody has defined it.
33
43
  def baseline_value
34
- if (@reference_lines.key?(:baseline))
44
+ if @reference_lines.key?(:baseline)
35
45
  @reference_lines[:baseline][:value]
36
- else
37
- nil
38
46
  end
39
47
  end
40
48
 
41
49
  # Set a value for a baseline reference line..
42
50
  def baseline_value=(new_value)
43
- @reference_lines[:baseline] ||= Hash.new
51
+ @reference_lines[:baseline] ||= {}
44
52
  @reference_lines[:baseline][:value] = new_value
45
53
  end
46
54
 
47
55
  def baseline_color
48
- if (@reference_lines.key?(:baseline))
56
+ if @reference_lines.key?(:baseline)
49
57
  @reference_lines[:baseline][:color]
50
- else
51
- nil
52
58
  end
53
59
  end
54
60
 
55
61
  def baseline_color=(new_value)
56
- @reference_lines[:baseline] ||= Hash.new
62
+ @reference_lines[:baseline] ||= {}
57
63
  @reference_lines[:baseline][:color] = new_value
58
64
  end
59
65
 
60
- # Call with target pixel width of graph (800, 400, 300), and/or 'false' to omit lines (points only).
61
- #
62
- # g = Gruff::Line.new(400) # 400px wide with lines
66
+ # Call with target pixel width of graph (+800+, +400+, +300+), and/or +false+ to omit lines (points only).
63
67
  #
64
- # g = Gruff::Line.new(400, false) # 400px wide, no lines (for backwards compatibility)
68
+ # g = Gruff::Line.new(400) # 400px wide with lines
69
+ # g = Gruff::Line.new(400, false) # 400px wide, no lines (for backwards compatibility)
70
+ # g = Gruff::Line.new(false) # Defaults to 800px wide, no lines (for backwards compatibility)
65
71
  #
66
- # g = Gruff::Line.new(false) # Defaults to 800px wide, no lines (for backwards compatibility)
67
- #
68
- # The preferred way is to call hide_dots or hide_lines instead.
72
+ # The preferred way is to call {#hide_dots} or {#hide_lines} instead.
69
73
  def initialize(*args)
70
74
  raise ArgumentError, 'Wrong number of arguments' if args.length > 2
71
- if args.empty? || ((not Numeric === args.first) && (not String === args.first))
75
+
76
+ if args.empty? || (!args.first.is_a?(Numeric) && !args.first.is_a?(String))
72
77
  super()
73
78
  else
74
79
  super args.shift
75
80
  end
76
81
 
77
- @reference_lines = Hash.new
82
+ @reference_lines = {}
78
83
  @reference_line_default_color = 'red'
79
84
  @reference_line_default_width = 5
80
85
 
81
86
  @hide_dots = @hide_lines = false
82
87
  @maximum_x_value = nil
83
88
  @minimum_x_value = nil
89
+
90
+ @dot_style = 'circle'
91
+
92
+ @show_vertical_markers = false
93
+
94
+ @store = Gruff::Store.new(Gruff::Store::XYData)
84
95
  end
85
96
 
86
97
  # This method allows one to plot a dataset with both X and Y data.
87
98
  #
88
- # Parameters are as follows:
89
- # name: string, the title of the dataset
90
- # x_data_points: an array containing the x data points for the graph
91
- # y_data_points: an array containing the y data points for the graph
92
- # color: hex number indicating the line color as an RGB triplet
93
- #
94
- # or
99
+ # @overload dataxy(name, x_data_points = [], y_data_points = [], color = nil)
100
+ # @param name [String] the title of the dataset.
101
+ # @param x_data_points [Array] an array containing the x data points for the graph.
102
+ # @param y_data_points [Array] an array containing the y data points for the graph.
103
+ # @param color [String] hex number indicating the line color as an RGB triplet.
95
104
  #
96
- # name: string, the title of the dataset
97
- # xy_data_points: an array containing both x and y data points for the graph
98
- # color: hex number indicating the line color as an RGB triplet
105
+ # @overload dataxy(name, xy_data_points = [], color = nil)
106
+ # @param name [String] the title of the dataset.
107
+ # @param xy_data_points [Array] an array containing both x and y data points for the graph.
108
+ # @param color [String] hex number indicating the line color as an RGB triplet.
99
109
  #
100
- # Notes:
101
- # -if (x_data_points.length != y_data_points.length) an error is
110
+ # @note
111
+ # - if (x_data_points.length != y_data_points.length) an error is
102
112
  # returned.
103
- # -if the color argument is nil, the next color from the default theme will
113
+ # - if the color argument is nil, the next color from the default theme will
104
114
  # be used.
105
- # -if you want to use a preset theme, you must set it before calling
106
- # dataxy().
115
+ # - if you want to use a preset theme, you must set it before calling {#dataxy}.
107
116
  #
108
- # Example:
117
+ # @example
109
118
  # g = Gruff::Line.new
110
119
  # g.title = "X/Y Dataset"
111
120
  # g.dataxy("Apples", [1,3,4,5,6,10], [1, 2, 3, 4, 4, 3])
112
121
  # g.dataxy("Bapples", [1,3,4,5,7,9], [1, 1, 2, 2, 3, 3])
113
122
  # g.dataxy("Capples", [[1,1],[2,3],[3,4],[4,5],[5,7],[6,9]])
114
- # #you can still use the old data method too if you want:
115
- # g.data("Capples", [1, 1, 2, 2, 3, 3])
116
- # #labels will be drawn at the x locations of the keys passed in.
123
+ #
124
+ # # you can still use the old data method too if you want:
125
+ # g.data("Capples", [1, 1, 2, 2, 3, 3])
126
+ #
127
+ # # labels will be drawn at the x locations of the keys passed in.
117
128
  # In this example the lables are drawn at x positions 2, 4, and 6:
118
129
  # g.labels = {0 => '2003', 2 => '2004', 4 => '2005', 6 => '2006'}
119
- # The 0 => '2003' label will be ignored since it is outside the chart range.
120
- def dataxy(name, x_data_points=[], y_data_points=[], color=nil)
121
- raise ArgumentError, 'x_data_points is nil!' if x_data_points.length == 0
130
+ # # The 0 => '2003' label will be ignored since it is outside the chart range.
131
+ def dataxy(name, x_data_points = [], y_data_points = [], color = nil)
132
+ # make sure it's an array
133
+ x_data_points = Array(x_data_points)
134
+ y_data_points = Array(y_data_points)
135
+
136
+ raise ArgumentError, 'x_data_points is nil!' if x_data_points.empty?
122
137
 
123
138
  if x_data_points.all? { |p| p.is_a?(Array) && p.size == 2 }
124
- x_data_points, y_data_points = x_data_points.map { |p| p[0] }, x_data_points.map { |p| p[1] }
139
+ x_data_points, y_data_points = x_data_points.transpose
125
140
  end
126
141
 
127
142
  raise ArgumentError, 'x_data_points.length != y_data_points.length!' if x_data_points.length != y_data_points.length
128
143
 
129
- # call the existing data routine for the y data.
130
- self.data(name, y_data_points, color)
131
-
132
- x_data_points = Array(x_data_points) # make sure it's an array
133
- # append the x data to the last entry that was just added in the @data member
134
- @data.last[DATA_VALUES_X_INDEX] = x_data_points
135
-
136
- # Update the global min/max values for the x data
137
- x_data_points.each do |x_data_point|
138
- next if x_data_point.nil?
139
-
140
- # Setup max/min so spread starts at the low end of the data points
141
- if @maximum_x_value.nil? && @minimum_x_value.nil?
142
- @maximum_x_value = @minimum_x_value = x_data_point
143
- end
144
-
145
- @maximum_x_value = (x_data_point > @maximum_x_value) ?
146
- x_data_point : @maximum_x_value
147
- @minimum_x_value = (x_data_point < @minimum_x_value) ?
148
- x_data_point : @minimum_x_value
149
- end
150
-
144
+ # call the existing data routine for the x/y data.
145
+ store.add(name, y_data_points, color, x_data_points)
151
146
  end
152
147
 
153
148
  def draw_reference_line(reference_line, left, right, top, bottom)
154
- @d = @d.push
155
- @d.stroke_color(reference_line[:color] || @reference_line_default_color)
156
- @d.fill_opacity 0.0
157
- @d.stroke_dasharray(10, 20)
158
- @d.stroke_width(reference_line[:width] || @reference_line_default_width)
159
- @d.line(left, top, right, bottom)
160
- @d = @d.pop
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)
161
154
  end
162
155
 
163
156
  def draw_horizontal_reference_line(reference_line)
@@ -167,118 +160,118 @@ class Gruff::Line < Gruff::Base
167
160
 
168
161
  def draw_vertical_reference_line(reference_line)
169
162
  index = @graph_left + (@x_increment * reference_line[:index])
170
- draw_reference_line(reference_line, index, index, @graph_top, @graph_top + graph_height)
163
+ draw_reference_line(reference_line, index, index, @graph_top, @graph_top + @graph_height)
171
164
  end
172
165
 
173
166
  def draw
174
167
  super
175
168
 
176
- return unless @has_data
169
+ return unless data_given?
177
170
 
178
- # Check to see if more than one datapoint was given. NaN can result otherwise.
179
- @x_increment = (@column_count > 1) ? (@graph_width / (@column_count - 1).to_f) : @graph_width
171
+ # Check to see if more than one datapoint was given. NaN can result otherwise.
172
+ @x_increment = (column_count > 1) ? (@graph_width / (column_count - 1).to_f) : @graph_width
180
173
 
181
174
  @reference_lines.each_value do |curr_reference_line|
182
175
  draw_horizontal_reference_line(curr_reference_line) if curr_reference_line.key?(:norm_value)
183
176
  draw_vertical_reference_line(curr_reference_line) if curr_reference_line.key?(:index)
184
177
  end
185
178
 
186
- @norm_data.each do |data_row|
179
+ if @show_vertical_markers
180
+ (0..column_count).each do |column|
181
+ x = @graph_left + @graph_width - column.to_f * @x_increment
182
+
183
+ Gruff::Renderer::Line.new(color: @marker_color).render(x, @graph_bottom, x, @graph_top)
184
+ #If the user specified a marker shadow color, draw a shadow just below it
185
+ if @marker_shadow_color
186
+ Gruff::Renderer::Line.new(color: @marker_shadow_color).render(x + 1, @graph_bottom, x + 1, @graph_top)
187
+ end
188
+ end
189
+ end
190
+
191
+ store.norm_data.each do |data_row|
187
192
  prev_x = prev_y = nil
188
193
 
189
- @one_point = contains_one_point_only?(data_row)
194
+ one_point = contains_one_point_only?(data_row)
190
195
 
191
- data_row[DATA_VALUES_INDEX].each_with_index do |data_point, index|
192
- unless data_point
193
- prev_x = prev_y = nil
194
- next
195
- end
196
- x_data = data_row[DATA_VALUES_X_INDEX]
197
- if x_data == nil
196
+ data_row.coordinates.each_with_index do |(x_data, y_data), index|
197
+ if x_data.nil?
198
198
  #use the old method: equally spaced points along the x-axis
199
199
  new_x = @graph_left + (@x_increment * index)
200
200
  draw_label(new_x, index)
201
201
  else
202
- new_x = get_x_coord(x_data[index], @graph_width, @graph_left)
202
+ new_x = get_x_coord(x_data, @graph_width, @graph_left)
203
203
  @labels.each do |label_pos, _|
204
204
  draw_label(@graph_left + ((label_pos - @minimum_x_value) * @graph_width) / (@maximum_x_value - @minimum_x_value), label_pos)
205
205
  end
206
206
  end
207
+ unless y_data # we can't draw a line for a null data point, we can still label the axis though
208
+ prev_x = prev_y = nil
209
+ next
210
+ end
207
211
 
208
- new_y = @graph_top + (@graph_height - data_point * @graph_height)
212
+ new_y = @graph_top + (@graph_height - y_data * @graph_height)
209
213
 
210
214
  # Reset each time to avoid thin-line errors
211
- @d = @d.stroke data_row[DATA_COLOR_INDEX]
212
- @d = @d.fill data_row[DATA_COLOR_INDEX]
213
- @d = @d.stroke_opacity 1.0
214
- @d = @d.stroke_width line_width ||
215
- clip_value_if_greater_than(@columns / (@norm_data.first[DATA_VALUES_INDEX].size * 4), 5.0)
216
-
217
- circle_radius = dot_radius ||
218
- clip_value_if_greater_than(@columns / (@norm_data.first[DATA_VALUES_INDEX].size * 2.5), 5.0)
219
-
220
- if !@hide_lines && !prev_x.nil? && !prev_y.nil?
221
- @d = @d.line(prev_x, prev_y, new_x, new_y)
222
- elsif @one_point
223
- # Show a circle if there's just one_point
224
- @d = @d.circle(new_x, new_y, new_x - circle_radius, new_y)
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)
217
+
218
+ if !@hide_lines && prev_x && prev_y
219
+ Gruff::Renderer::Line.new(color: data_row.color, width: stroke_width)
220
+ .render(prev_x, prev_y, new_x, new_y)
225
221
  end
226
- @d = @d.circle(new_x, new_y, new_x - circle_radius, new_y) unless @hide_dots
227
222
 
228
- prev_x, prev_y = new_x, new_y
223
+ if one_point || !@hide_dots
224
+ Gruff::Renderer::Dot.new(@dot_style, color: data_row.color, width: stroke_width).render(new_x, new_y, circle_radius)
225
+ end
226
+
227
+ prev_x = new_x
228
+ prev_y = new_y
229
229
  end
230
230
  end
231
231
 
232
- @d.draw(@base_image)
232
+ Gruff::Renderer.finish
233
233
  end
234
234
 
235
+ private
236
+
235
237
  def setup_data
238
+ # Update the global min/max values for the x data
239
+ @maximum_x_value ||= store.max_x
240
+ @minimum_x_value ||= store.min_x
236
241
 
237
242
  # Deal with horizontal reference line values that exceed the existing minimum & maximum values.
238
- possible_maximums = [@maximum_value.to_f]
239
- possible_minimums = [@minimum_value.to_f]
243
+ possible_maximums = [maximum_value.to_f]
244
+ possible_minimums = [minimum_value.to_f]
240
245
 
241
246
  @reference_lines.each_value do |curr_reference_line|
242
- if (curr_reference_line.key?(:value))
247
+ if curr_reference_line.key?(:value)
243
248
  possible_maximums << curr_reference_line[:value].to_f
244
249
  possible_minimums << curr_reference_line[:value].to_f
245
250
  end
246
251
  end
247
252
 
248
- @maximum_value = possible_maximums.max
249
- @minimum_value = possible_minimums.min
253
+ self.maximum_value = possible_maximums.max
254
+ self.minimum_value = possible_minimums.min
250
255
 
251
256
  super
252
257
  end
253
258
 
254
- def normalize(force=false)
255
- super(force)
259
+ def normalize
260
+ return unless data_given?
256
261
 
257
- @reference_lines.each_value do |curr_reference_line|
262
+ spread_x = @maximum_x_value.to_f - @minimum_x_value.to_f
263
+ store.normalize(minimum_x: @minimum_x_value, spread_x: spread_x, minimum_y: minimum_value, spread_y: @spread)
258
264
 
259
- # We only care about horizontal markers ... for normalization.
265
+ @reference_lines.each_value do |curr_reference_line|
266
+ # We only care about horizontal markers ... for normalization.
260
267
  # Vertical markers won't have a :value, they will have an :index
261
268
 
262
- curr_reference_line[:norm_value] = ((curr_reference_line[:value].to_f - @minimum_value) / @spread.to_f) if (curr_reference_line.key?(:value))
263
-
269
+ curr_reference_line[:norm_value] = ((curr_reference_line[:value].to_f - minimum_value) / @spread.to_f) if curr_reference_line.key?(:value)
264
270
  end
265
-
266
- #normalize the x data if it is specified
267
- @data.each_with_index do |data_row, index|
268
- norm_x_data_points = []
269
- if data_row[DATA_VALUES_X_INDEX] != nil
270
- data_row[DATA_VALUES_X_INDEX].each do |x_data_point|
271
- norm_x_data_points << ((x_data_point.to_f - @minimum_x_value.to_f) /
272
- (@maximum_x_value.to_f - @minimum_x_value.to_f))
273
- end
274
- @norm_data[index] << norm_x_data_points
275
- end
276
- end
277
-
278
271
  end
279
272
 
280
273
  def sort_norm_data
281
- super unless @data.any? { |d| d[DATA_VALUES_X_INDEX] }
274
+ super unless store.data.any?(&:x_points)
282
275
  end
283
276
 
284
277
  def get_x_coord(x_data_point, width, offset)
@@ -286,19 +279,6 @@ class Gruff::Line < Gruff::Base
286
279
  end
287
280
 
288
281
  def contains_one_point_only?(data_row)
289
- # Spin through data to determine if there is just one_value present.
290
- one_point = false
291
- data_row[DATA_VALUES_INDEX].each do |data_point|
292
- unless data_point.nil?
293
- if one_point
294
- # more than one point, bail
295
- return false
296
- end
297
- # there is at least one data point
298
- one_point = true
299
- end
300
- end
301
- one_point
282
+ data_row.y_points.compact.count == 1
302
283
  end
303
-
304
284
  end