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
Binary file
Binary file
data/gruff.gemspec CHANGED
@@ -13,7 +13,9 @@ Gem::Specification.new do |s|
13
13
  s.date = Date.today.to_s
14
14
  s.description = 'Beautiful graphs for one or multiple datasets. Can be used on websites or in documents.'
15
15
  s.email = 'boss@topfunky.com'
16
- s.files = `git ls-files`.split($/).reject { |f| f =~ /^test/ }
16
+ s.files = `git ls-files`.split.reject do |f|
17
+ f =~ /^test|^docker|^Rakefile/
18
+ end
17
19
  s.homepage = 'https://github.com/topfunky/gruff'
18
20
  s.require_paths = %w[lib]
19
21
  s.summary = 'Beautiful graphs for one or multiple datasets.'
@@ -27,12 +29,15 @@ Gem::Specification.new do |s|
27
29
  s.add_dependency 'rmagick4j'
28
30
  else
29
31
  s.add_dependency 'rmagick'
30
- s.add_development_dependency 'rubocop', '~> 0.81.0'
32
+ s.add_development_dependency 'rubocop', '~> 1.12.1'
33
+ s.add_development_dependency 'rubocop-performance', '~> 1.10.2'
31
34
  end
32
35
  s.add_dependency 'histogram'
33
- s.required_ruby_version = '>= 1.9.3'
36
+ s.required_ruby_version = '>= 2.4.0'
34
37
 
35
38
  s.add_development_dependency 'rake'
39
+ s.add_development_dependency 'parallel'
36
40
  s.add_development_dependency 'minitest-reporters'
41
+ s.add_development_dependency 'simplecov'
37
42
  s.add_development_dependency 'yard', '~> 0.9.25'
38
43
  end
data/lib/gruff.rb CHANGED
@@ -9,8 +9,13 @@ require 'gruff/version'
9
9
  patch/rmagick
10
10
  patch/string
11
11
 
12
- themes
13
12
  base
13
+
14
+ helper/bar_conversion.rb
15
+ helper/stacked_mixin
16
+ helper/bar_value_label
17
+
18
+ themes
14
19
  area
15
20
  bar
16
21
  bezier
@@ -22,10 +27,10 @@ require 'gruff/version'
22
27
  pie
23
28
  scatter
24
29
  spider
30
+ side_bar
25
31
  stacked_area
26
32
  stacked_bar
27
33
  side_stacked_bar
28
- side_bar
29
34
  accumulator_bar
30
35
 
31
36
  scene
@@ -43,7 +48,7 @@ require 'gruff/version'
43
48
  renderer/text
44
49
 
45
50
  store/store
46
- store/base_data
51
+ store/basic_data
47
52
  store/custom_data
48
53
  store/xy_data
49
54
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'gruff/base'
4
-
5
3
  #
6
4
  # Gruff::AccumulatorBar is a special bar graph that shows a
7
5
  # single dataset as a set of stacked bars.
data/lib/gruff/area.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'gruff/base'
4
-
5
3
  #
6
4
  # Gruff::Area provides an area graph which displays graphically
7
5
  # quantitative data.
@@ -17,10 +15,10 @@ require 'gruff/base'
17
15
  #
18
16
  class Gruff::Area < Gruff::Base
19
17
  # Specifies the filling opacity in area graph. Default is +0.85+.
20
- attr_accessor :fill_opacity
18
+ attr_writer :fill_opacity
21
19
 
22
20
  # Specifies the stroke width in line around area graph. Default is +2.0+.
23
- attr_accessor :stroke_width
21
+ attr_writer :stroke_width
24
22
 
25
23
  def initialize_ivars
26
24
  super
@@ -59,7 +57,5 @@ class Gruff::Area < Gruff::Base
59
57
 
60
58
  Gruff::Renderer::Polygon.new(color: data_row.color, width: @stroke_width, opacity: @fill_opacity).render(poly_points)
61
59
  end
62
-
63
- Gruff::Renderer.finish
64
60
  end
65
61
  end
data/lib/gruff/bar.rb CHANGED
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'gruff/base'
4
- require 'gruff/helper/bar_conversion'
5
-
6
3
  #
7
4
  # Gruff::Bar provide a bar graph that presents categorical data
8
5
  # with rectangular bars.
@@ -20,24 +17,29 @@ require 'gruff/helper/bar_conversion'
20
17
  #
21
18
  class Gruff::Bar < Gruff::Base
22
19
  # Spacing factor applied between bars.
23
- attr_accessor :bar_spacing
20
+ attr_writer :bar_spacing
24
21
 
25
22
  # Spacing factor applied between a group of bars belonging to the same label.
26
- attr_accessor :group_spacing
23
+ attr_writer :group_spacing
27
24
 
28
- # Set the number output format for labels using sprintf.
25
+ # Set the number output format string or lambda.
29
26
  # Default is +"%.2f"+.
30
- attr_accessor :label_formatting
27
+ attr_writer :label_formatting
31
28
 
32
29
  # Output the values for the bars on a bar graph.
33
30
  # Default is +false+.
34
- attr_accessor :show_labels_for_bar_values
31
+ attr_writer :show_labels_for_bar_values
32
+
33
+ # Prevent drawing of column labels below a bar graph. Default is +false+.
34
+ attr_writer :hide_labels
35
35
 
36
36
  def initialize_ivars
37
37
  super
38
38
  @spacing_factor = 0.9
39
+ @group_spacing = 10
39
40
  @label_formatting = nil
40
41
  @show_labels_for_bar_values = false
42
+ @hide_labels = false
41
43
  end
42
44
  private :initialize_ivars
43
45
 
@@ -67,35 +69,35 @@ class Gruff::Bar < Gruff::Base
67
69
 
68
70
  protected
69
71
 
72
+ def hide_labels?
73
+ @hide_labels
74
+ end
75
+
76
+ def hide_left_label_area?
77
+ @hide_line_markers
78
+ end
79
+
80
+ def hide_bottom_label_area?
81
+ hide_labels?
82
+ end
83
+
84
+ # Value to avoid completely overwriting the coordinate axis
85
+ AXIS_MARGIN = 0.5
86
+
70
87
  def draw_bars
71
88
  # Setup spacing.
72
89
  #
73
90
  # Columns sit side-by-side.
74
91
  @bar_spacing ||= @spacing_factor # space between the bars
75
- @group_spacing ||= 10
76
92
 
77
93
  bar_width = (@graph_width - calculate_spacing) / (column_count * store.length).to_f
78
94
  padding = (bar_width * (1 - @bar_spacing)) / 2
79
95
 
80
96
  # Setup the BarConversion Object
81
- conversion = Gruff::BarConversion.new
82
- conversion.graph_height = @graph_height
83
- conversion.graph_top = @graph_top
84
-
85
- # Set up the right mode [1,2,3] see BarConversion for further explanation
86
- if minimum_value >= 0
87
- # all bars go from zero to positive
88
- conversion.mode = 1
89
- elsif maximum_value <= 0
90
- # all bars go from 0 to negative
91
- conversion.mode = 2
92
- else
93
- # bars either go from zero to negative or to positive
94
- conversion.mode = 3
95
- conversion.spread = @spread
96
- conversion.minimum_value = minimum_value
97
- conversion.zero = -minimum_value / @spread
98
- end
97
+ conversion = Gruff::BarConversion.new(
98
+ top: @graph_top, bottom: @graph_bottom,
99
+ minimum_value: minimum_value, maximum_value: maximum_value, spread: @spread
100
+ )
99
101
 
100
102
  # iterate over all normalised data
101
103
  store.norm_data.each_with_index do |data_row, row_index|
@@ -107,11 +109,11 @@ protected
107
109
  left_x = @graph_left + (bar_width * (row_index + point_index + ((store.length - 1) * point_index))) + padding + group_spacing
108
110
  right_x = left_x + bar_width * @bar_spacing
109
111
  # y
110
- left_y, right_y = conversion.get_left_y_right_y_scaled(data_point)
112
+ left_y, right_y = conversion.get_top_bottom_scaled(data_point)
111
113
 
112
114
  # create new bar
113
115
  rect_renderer = Gruff::Renderer::Rectangle.new(color: data_row.color)
114
- rect_renderer.render(left_x, left_y, right_x, right_y)
116
+ rect_renderer.render(left_x, left_y - AXIS_MARGIN, right_x, right_y - AXIS_MARGIN)
115
117
 
116
118
  # Calculate center based on bar_width and current row
117
119
  label_center = @graph_left + group_spacing + (store.length * bar_width * point_index) + (store.length * bar_width / 2.0)
@@ -119,18 +121,16 @@ protected
119
121
  # Subtract half a bar width to center left if requested
120
122
  draw_label(label_center, point_index)
121
123
  if @show_labels_for_bar_values
122
- raw_value = store.data[row_index].points[point_index]
123
- val = (@label_formatting || '%.2f') % raw_value
124
- y = raw_value >= 0 ? left_y - 30 : left_y + 12
125
- draw_value_label(left_x + (right_x - left_x) / 2, y, val.commify, true)
124
+ bar_value_label = Gruff::BarValueLabel::Bar.new([left_x, left_y, right_x, right_y], store.data[row_index].points[point_index])
125
+ bar_value_label.prepare_rendering(@label_formatting, bar_width) do |x, y, text|
126
+ draw_value_label(x, y, text, true)
127
+ end
126
128
  end
127
129
  end
128
130
  end
129
131
 
130
132
  # Draw the last label if requested
131
133
  draw_label(@graph_right, column_count, Magick::NorthWestGravity) if @center_labels_over_point
132
-
133
- Gruff::Renderer.finish
134
134
  end
135
135
 
136
136
  def calculate_spacing
data/lib/gruff/base.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rmagick'
4
3
  require 'bigdecimal'
5
4
 
6
5
  ##
@@ -17,31 +16,34 @@ require 'bigdecimal'
17
16
  #
18
17
  # See {Gruff::Base#theme=} for setting themes.
19
18
  module Gruff
19
+ using String::GruffCommify
20
+
21
+ # A common base class inherited from class of drawing a graph.
20
22
  class Base
21
23
  # Space around text elements. Mostly used for vertical spacing.
22
24
  LEGEND_MARGIN = TITLE_MARGIN = 20.0
23
- LABEL_MARGIN = 10.0
25
+ LABEL_MARGIN = 15.0
24
26
  DEFAULT_MARGIN = 20.0
25
27
 
26
28
  DEFAULT_TARGET_WIDTH = 800.0
27
29
 
28
30
  # Blank space above the graph. Default is +20+.
29
- attr_accessor :top_margin
31
+ attr_writer :top_margin
30
32
 
31
33
  # Blank space below the graph. Default is +20+.
32
- attr_accessor :bottom_margin
34
+ attr_writer :bottom_margin
33
35
 
34
36
  # Blank space to the right of the graph. Default is +20+.
35
- attr_accessor :right_margin
37
+ attr_writer :right_margin
36
38
 
37
39
  # Blank space to the left of the graph. Default is +20+.
38
- attr_accessor :left_margin
40
+ attr_writer :left_margin
39
41
 
40
42
  # Blank space below the title. Default is +20+.
41
- attr_accessor :title_margin
43
+ attr_writer :title_margin
42
44
 
43
45
  # Blank space below the legend. Default is +20+.
44
- attr_accessor :legend_margin
46
+ attr_writer :legend_margin
45
47
 
46
48
  # A hash of names for the individual columns, where the key is the array
47
49
  # index for the column this label represents.
@@ -50,118 +52,115 @@ module Gruff
50
52
  #
51
53
  # @example
52
54
  # { 0 => 2005, 3 => 2006, 5 => 2007, 7 => 2008 }
53
- attr_accessor :labels
55
+ attr_writer :labels
54
56
 
55
57
  # Used internally for spacing.
56
58
  #
57
59
  # By default, labels are centered over the point they represent.
58
- attr_accessor :center_labels_over_point
60
+ attr_writer :center_labels_over_point
59
61
 
60
62
  # Used internally for horizontal graph types. Default is +false+.
61
- attr_accessor :has_left_labels
63
+ attr_writer :has_left_labels
62
64
 
63
65
  # Set a label for the bottom of the graph.
64
- attr_accessor :x_axis_label
66
+ attr_writer :x_axis_label
65
67
 
66
68
  # Set a label for the left side of the graph.
67
- attr_accessor :y_axis_label
69
+ attr_writer :y_axis_label
68
70
 
69
71
  # Set increment of the vertical marking lines.
70
- attr_accessor :x_axis_increment
72
+ attr_writer :x_axis_increment
71
73
 
72
74
  # Set increment of the horizontal marking lines.
73
- attr_accessor :y_axis_increment
75
+ attr_writer :y_axis_increment
74
76
 
75
77
  # Height of staggering between labels (Bar graph only).
76
- attr_accessor :label_stagger_height
78
+ attr_writer :label_stagger_height
77
79
 
78
80
  # Truncates labels if longer than max specified.
79
- attr_accessor :label_max_size
81
+ attr_writer :label_max_size
80
82
 
81
- # How truncated labels visually appear if they exceed {#label_max_size}.
83
+ # How truncated labels visually appear if they exceed {#label_max_size=}.
82
84
  #
83
85
  # - +:absolute+ - does not show trailing dots to indicate truncation. This is the default.
84
- # - +:trailing_dots+ - shows trailing dots to indicate truncation (note that {#label_max_size}
86
+ # - +:trailing_dots+ - shows trailing dots to indicate truncation (note that {#label_max_size=}
85
87
  # must be greater than 3).
86
- attr_accessor :label_truncation_style
88
+ attr_writer :label_truncation_style
87
89
 
88
90
  # Get or set the list of colors that will be used to draw the bars or lines.
89
91
  attr_accessor :colors
90
92
 
91
93
  # Set the large title of the graph displayed at the top.
92
- attr_accessor :title
93
-
94
- # Font used for titles, labels, etc. Works best if you provide the full
95
- # path to the TTF font file. RMagick must be built with the Freetype
96
- # libraries for this to work properly.
97
- attr_reader :font
94
+ attr_writer :title
98
95
 
99
- # Same as {#font} but for the title.
100
- attr_accessor :title_font
96
+ # Same as {#font=} but for the title.
97
+ attr_writer :title_font
101
98
 
102
99
  # Specifies whether to draw the title bolded or not. Default is +true+.
103
- attr_accessor :bold_title
100
+ attr_writer :bold_title
104
101
 
105
102
  # Specifies the text color.
106
- attr_accessor :font_color
103
+ attr_writer :font_color
107
104
 
108
105
  # Prevent drawing of line markers. Default is +false+.
109
- attr_accessor :hide_line_markers
106
+ attr_writer :hide_line_markers
110
107
 
111
108
  # Prevent drawing of the legend. Default is +false+.
112
- attr_accessor :hide_legend
109
+ attr_writer :hide_legend
113
110
 
114
111
  # Prevent drawing of the title. Default is +false+.
115
- attr_accessor :hide_title
112
+ attr_writer :hide_title
116
113
 
117
114
  # Prevent drawing of line numbers. Default is +false+.
118
- attr_accessor :hide_line_numbers
115
+ attr_writer :hide_line_numbers
119
116
 
120
117
  # Set a message shown when there is no data. Fits up to 20 characters. Defaults
121
118
  # to +"No Data."+.
122
- attr_accessor :no_data_message
119
+ attr_writer :no_data_message
123
120
 
124
121
  # Set the font size of the large title at the top of the graph. Default is +36+.
125
- attr_accessor :title_font_size
122
+ attr_writer :title_font_size
126
123
 
127
124
  # Optionally set the size of the font. Based on an 800x600px graph.
128
125
  # Default is +20+.
129
126
  #
130
127
  # Will be scaled down if the graph is smaller than 800px wide.
131
- attr_accessor :legend_font_size
128
+ attr_writer :legend_font_size
132
129
 
133
130
  # Display the legend under the graph. Default is +false+.
134
- attr_accessor :legend_at_bottom
131
+ attr_writer :legend_at_bottom
135
132
 
136
133
  # The font size of the labels around the graph. Default is +21+.
137
- attr_accessor :marker_font_size
134
+ attr_writer :marker_font_size
138
135
 
139
136
  # Set the color of the auxiliary lines.
140
- attr_accessor :marker_color
137
+ attr_writer :marker_color
141
138
 
142
139
  # Set the shadow color of the auxiliary lines.
143
- attr_accessor :marker_shadow_color
140
+ attr_writer :marker_shadow_color
144
141
 
145
142
  # Set the number of horizontal lines shown for reference.
146
- attr_accessor :marker_count
143
+ attr_writer :marker_count
147
144
 
148
145
  # Set to +true+ if you want the data sets sorted with largest avg values drawn
149
146
  # first. Default is +false+.
150
- attr_accessor :sort
147
+ attr_writer :sort
151
148
 
152
149
  # Set to +true+ if you want the data sets drawn with largest avg values drawn
153
150
  # first. This does not affect the legend. Default is +false+.
154
- attr_accessor :sorted_drawing
151
+ attr_writer :sorted_drawing
155
152
 
156
153
  # Optionally set the size of the colored box by each item in the legend.
157
154
  # Default is +20.0+.
158
155
  #
159
156
  # Will be scaled down if graph is smaller than 800px wide.
160
- attr_accessor :legend_box_size
157
+ attr_writer :legend_box_size
158
+
159
+ # Allow passing lambdas to format labels for x axis.
160
+ attr_writer :x_axis_label_format
161
161
 
162
- # With Side Bars use the data label for the marker value to the left of the bar.
163
- # Default is +false+.
164
- attr_accessor :use_data_label
162
+ # Allow passing lambdas to format labels for y axis.
163
+ attr_writer :y_axis_label_format
165
164
 
166
165
  # If one numerical argument is given, the graph is drawn at 4/3 ratio
167
166
  # according to the given width (+800+ results in 800x600, +400+ gives 400x300,
@@ -173,9 +172,7 @@ module Gruff
173
172
  #
174
173
  def initialize(target_width = DEFAULT_TARGET_WIDTH)
175
174
  if target_width.is_a?(String)
176
- geometric_width, geometric_height = target_width.split('x')
177
- @columns = geometric_width.to_f
178
- @rows = geometric_height.to_f
175
+ @columns, @rows = target_width.split('x').map(&:to_f)
179
176
  else
180
177
  @columns = target_width.to_f
181
178
  @rows = target_width.to_f * 0.75
@@ -183,19 +180,14 @@ module Gruff
183
180
  @columns.freeze
184
181
  @rows.freeze
185
182
 
183
+ initialize_graph_scale
186
184
  initialize_ivars
185
+ initialize_store
187
186
 
188
187
  self.theme = Themes::KEYNOTE
189
188
  end
190
189
 
191
- # Set instance variables for this object.
192
- #
193
- # Subclasses can override this, call super, then set values separately.
194
- #
195
- # This makes it possible to set defaults in a subclass but still allow
196
- # developers to change this values in their program.
197
- def initialize_ivars
198
- # Internal for calculations
190
+ def initialize_graph_scale
199
191
  @raw_columns = DEFAULT_TARGET_WIDTH
200
192
  @raw_rows = DEFAULT_TARGET_WIDTH * (@rows / @columns)
201
193
  @raw_columns.freeze
@@ -203,16 +195,29 @@ module Gruff
203
195
 
204
196
  @scale = @columns / @raw_columns
205
197
  @scale.freeze
198
+ end
199
+ protected :initialize_graph_scale
206
200
 
201
+ def initialize_store
202
+ @store = Gruff::Store.new(Gruff::Store::BasicData)
203
+ end
204
+ protected :initialize_store
205
+
206
+ # Initialize instance variable of attributes
207
+ #
208
+ # Subclasses can override this, call super, then set values separately.
209
+ #
210
+ # This makes it possible to set defaults in a subclass but still allow
211
+ # developers to change this values in their program.
212
+ def initialize_ivars
207
213
  @marker_count = nil
208
214
  @maximum_value = @minimum_value = nil
209
- @increment = nil
210
215
  @labels = {}
211
216
  @sort = false
212
217
  @sorted_drawing = false
213
218
  @title = nil
214
- @title_font = nil
215
219
 
220
+ @title_font = nil
216
221
  @font = nil
217
222
  @bold_title = true
218
223
 
@@ -235,14 +240,12 @@ module Gruff
235
240
  @label_max_size = 0
236
241
  @label_truncation_style = :absolute
237
242
 
238
- @theme_options = {}
239
-
240
- @use_data_label = false
241
243
  @x_axis_increment = nil
242
244
  @x_axis_label = @y_axis_label = nil
243
245
  @y_axis_increment = nil
244
246
 
245
- @store = Gruff::Store.new(Gruff::Store::BaseData)
247
+ @x_axis_label_format = nil
248
+ @y_axis_label_format = nil
246
249
  end
247
250
  protected :initialize_ivars
248
251
 
@@ -298,11 +301,20 @@ module Gruff
298
301
  # graph.theme = {
299
302
  # colors: %w(orange purple green white red),
300
303
  # marker_color: 'blue',
301
- # background_colors: ['black', 'grey', :top_bottom]
304
+ # background_colors: ['black', 'grey'],
305
+ # background_direction: :top_bottom
302
306
  # }
303
307
  #
304
308
  # +background_image: 'squirrel.png'+ is also possible.
305
309
  #
310
+ # +background_direction+ accepts one of following parameters.
311
+ # - +:top_bottom+
312
+ # - +:bottom_top+
313
+ # - +:left_right+
314
+ # - +:right_left+
315
+ # - +:topleft_bottomright+
316
+ # - +:topright_bottomleft+
317
+ #
306
318
  # (Or hopefully something better looking than that.)
307
319
  #
308
320
  # @param options [Hash] The optional setting for theme
@@ -408,14 +420,40 @@ module Gruff
408
420
  # @example
409
421
  # write('graphs/my_pretty_graph.png')
410
422
  def write(file_name = 'graph.png')
411
- draw
412
- Gruff::Renderer.write(file_name)
423
+ to_image.write(file_name)
424
+ end
425
+
426
+ # Return a rendered graph image.
427
+ # This can use RMagick's methods to adjust the image before saving.
428
+ #
429
+ # @return [Magick::Image] The rendered image.
430
+ #
431
+ # @example
432
+ # g = Gruff::Line.new
433
+ # g.data :Jimmy, [25, 36, 86, 39, 25, 31, 79, 88]
434
+ # g.data :Charles, [80, 54, 67, 54, 68, 70, 90, 95]
435
+ # image = g.to_image
436
+ # image = image.resize(400, 300).quantize(128, Magick::RGBColorspace)
437
+ # image.write('test.png')
438
+ #
439
+ def to_image
440
+ @to_image ||= begin
441
+ draw
442
+ Gruff::Renderer.finish
443
+ Gruff::Renderer.instance.image
444
+ end
413
445
  end
414
446
 
415
447
  # Return the graph as a rendered binary blob.
416
- def to_blob(file_format = 'PNG')
417
- draw
418
- Gruff::Renderer.to_blob(file_format)
448
+ #
449
+ # @param image_format [String] The image format of binary blob.
450
+ #
451
+ # @deprecated Please use +to_image.to_blob+ instead.
452
+ def to_blob(image_format = 'PNG')
453
+ warn '#to_blob is deprecated. Please use `to_image.to_blob` instead'
454
+ to_image.to_blob do
455
+ self.format = image_format
456
+ end
419
457
  end
420
458
 
421
459
  protected
@@ -478,6 +516,18 @@ module Gruff
478
516
  store.columns
479
517
  end
480
518
 
519
+ def marker_count
520
+ @marker_count ||= begin
521
+ count = nil
522
+ (3..7).each do |lines|
523
+ if @spread.to_f % lines == 0.0
524
+ count = lines and break
525
+ end
526
+ end
527
+ count || 4
528
+ end
529
+ end
530
+
481
531
  # Make copy of data with values scaled between 0-100
482
532
  def normalize
483
533
  store.normalize(minimum: minimum_value, spread: @spread)
@@ -492,61 +542,33 @@ module Gruff
492
542
  @hide_title || @title.nil? || @title.empty?
493
543
  end
494
544
 
495
- ##
496
- # Calculates size of drawable area, general font dimensions, etc.
497
-
498
- def setup_graph_measurements
499
- @marker_caps_height = @hide_line_markers ? 0 : calculate_caps_height(@marker_font_size)
500
- @title_caps_height = hide_title? ? 0 : calculate_caps_height(@title_font_size) * @title.lines.to_a.size
501
- @legend_caps_height = @hide_legend ? 0 : calculate_caps_height(@legend_font_size)
502
-
503
- if @hide_line_markers
504
- @graph_left = @left_margin
505
- @graph_right_margin = @right_margin
506
- @graph_bottom_margin = @bottom_margin
507
- else
508
- if @has_left_labels
509
- longest_left_label_width = calculate_width(@marker_font_size,
510
- labels.values.reduce('') { |value, memo| (value.to_s.length > memo.to_s.length) ? value : memo }) * 1.25
511
- else
512
- longest_left_label_width = calculate_width(@marker_font_size,
513
- label(maximum_value.to_f, @increment))
514
- end
515
-
516
- # Shift graph if left line numbers are hidden
517
- line_number_width = @hide_line_numbers && !@has_left_labels ? 0.0 : (longest_left_label_width + LABEL_MARGIN * 2)
545
+ def hide_labels?
546
+ @hide_line_markers
547
+ end
518
548
 
519
- @graph_left = @left_margin + line_number_width + (@y_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN * 2)
549
+ def hide_left_label_area?
550
+ @hide_line_markers
551
+ end
520
552
 
521
- # Make space for half the width of the rightmost column label.
522
- # Might be greater than the number of columns if between-style bar markers are used.
523
- last_label = @labels.keys.max.to_i
524
- extra_room_for_long_label = begin
525
- (last_label >= (column_count - 1) && @center_labels_over_point) ? calculate_width(@marker_font_size, @labels[last_label]) / 2.0 : 0
526
- end
527
- @graph_right_margin = @right_margin + extra_room_for_long_label
553
+ def hide_bottom_label_area?
554
+ @hide_line_markers
555
+ end
528
556
 
529
- @graph_bottom_margin = @bottom_margin + @marker_caps_height + LABEL_MARGIN
530
- end
557
+ ##
558
+ # Calculates size of drawable area, general font dimensions, etc.
531
559
 
532
- @graph_right = @raw_columns - @graph_right_margin
533
- @graph_width = @raw_columns - @graph_left - @graph_right_margin
560
+ def setup_graph_measurements
561
+ @marker_caps_height = setup_marker_caps_height
562
+ @title_caps_height = setup_title_caps_height
563
+ @legend_caps_height = setup_legend_caps_height
534
564
 
535
- # When @hide title, leave a title_margin space for aesthetics.
536
- # Same with @hide_legend
537
- @graph_top = begin
538
- if @legend_at_bottom
539
- @top_margin
540
- else
541
- @top_margin +
542
- (hide_title? ? title_margin : @title_caps_height + title_margin) +
543
- (@hide_legend ? legend_margin : @legend_caps_height + legend_margin)
544
- end
545
- end
565
+ margin_on_right = graph_right_margin
566
+ @graph_right = @raw_columns - margin_on_right
567
+ @graph_left = setup_left_margin
568
+ @graph_top = setup_top_margin
569
+ @graph_bottom = setup_bottom_margin
546
570
 
547
- x_axis_label_height = @x_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN
548
- # FIXME: Consider chart types other than bar
549
- @graph_bottom = @raw_rows - @graph_bottom_margin - x_axis_label_height - @label_stagger_height
571
+ @graph_width = @raw_columns - @graph_left - margin_on_right
550
572
  @graph_height = @graph_bottom - @graph_top
551
573
  end
552
574
 
@@ -556,17 +578,17 @@ module Gruff
556
578
  # X Axis
557
579
  # Centered vertically and horizontally by setting the
558
580
  # height to 1.0 and the width to the width of the graph.
559
- x_axis_label_y_coordinate = @graph_bottom + LABEL_MARGIN * 2 + @marker_caps_height
581
+ x_axis_label_y_coordinate = @graph_bottom + LABEL_MARGIN + @marker_caps_height
560
582
 
561
583
  # TODO: Center between graph area
562
584
  text_renderer = Gruff::Renderer::Text.new(@x_axis_label, font: @font, size: @marker_font_size, color: @font_color)
563
- text_renderer.render(@raw_columns, 1.0, 0.0, x_axis_label_y_coordinate)
585
+ text_renderer.add_to_render_queue(@raw_columns, 1.0, 0.0, x_axis_label_y_coordinate)
564
586
  end
565
587
 
566
588
  if @y_axis_label
567
589
  # Y Axis, rotated vertically
568
590
  text_renderer = Gruff::Renderer::Text.new(@y_axis_label, font: @font, size: @marker_font_size, color: @font_color, rotation: -90)
569
- text_renderer.render(1.0, @raw_rows, @left_margin + @marker_caps_height / 2.0, 0.0, Magick::CenterGravity)
591
+ text_renderer.add_to_render_queue(1.0, @raw_rows, @left_margin + @marker_caps_height / 2.0, 0.0, Magick::CenterGravity)
570
592
  end
571
593
  end
572
594
 
@@ -577,31 +599,21 @@ module Gruff
577
599
  increment_scaled = @graph_height.to_f / (@spread / @increment)
578
600
 
579
601
  # Draw horizontal line markers and annotate with numbers
580
- (0..@marker_count).each do |index|
602
+ (0..marker_count).each do |index|
581
603
  y = @graph_top + @graph_height - index.to_f * increment_scaled
582
604
 
583
- Gruff::Renderer::Line.new(color: @marker_color).render(@graph_left, y, @graph_right, y)
584
- #If the user specified a marker shadow color, draw a shadow just below it
585
- if @marker_shadow_color
586
- Gruff::Renderer::Line.new(color: @marker_shadow_color).render(@graph_left, y + 1, @graph_right, y + 1)
587
- end
605
+ line_renderer = Gruff::Renderer::Line.new(color: @marker_color, shadow_color: @marker_shadow_color)
606
+ line_renderer.render(@graph_left, y, @graph_right, y)
588
607
 
589
608
  unless @hide_line_numbers
590
609
  marker_label = BigDecimal(index.to_s) * BigDecimal(@increment.to_s) + BigDecimal(minimum_value.to_s)
591
- label = label(marker_label, @increment)
610
+ label = y_axis_label(marker_label, @increment)
592
611
  text_renderer = Gruff::Renderer::Text.new(label, font: @font, size: @marker_font_size, color: @font_color)
593
- text_renderer.render(@graph_left - LABEL_MARGIN, 1.0, 0.0, y, Magick::EastGravity)
612
+ text_renderer.add_to_render_queue(@graph_left - LABEL_MARGIN, 1.0, 0.0, y, Magick::EastGravity)
594
613
  end
595
614
  end
596
615
  end
597
616
 
598
- # Return the sum of values in an array.
599
- #
600
- # Duplicated to not conflict with active_support in Rails.
601
- def sum(arr)
602
- arr.reduce(0) { |i, m| m + i }
603
- end
604
-
605
617
  # Return a calculation of center
606
618
  def center(size)
607
619
  (@raw_columns - size) / 2
@@ -613,27 +625,15 @@ module Gruff
613
625
  return if @hide_legend
614
626
 
615
627
  legend_labels = store.data.map(&:label)
616
-
617
628
  legend_square_width = @legend_box_size # small square with color of this item
629
+ label_widths = calculate_legend_label_widths_for_each_line(legend_labels, legend_square_width)
618
630
 
619
- # May fix legend drawing problem at small sizes
620
- label_widths = [[]] # Used to calculate line wrap
621
- legend_labels.each do |label|
622
- width = calculate_width(@legend_font_size, label)
623
- label_width = width + legend_square_width * 2.7
624
- label_widths.last.push label_width
625
-
626
- if sum(label_widths.last) > (@raw_columns * 0.9)
627
- label_widths.push [label_widths.last.pop]
628
- end
629
- end
630
-
631
- current_x_offset = center(sum(label_widths.first))
631
+ current_x_offset = center(label_widths.first.sum)
632
632
  current_y_offset = begin
633
633
  if @legend_at_bottom
634
- @graph_height + title_margin
634
+ @graph_bottom + @legend_margin + @legend_caps_height + LABEL_MARGIN
635
635
  else
636
- hide_title? ? @top_margin + title_margin : @top_margin + title_margin + @title_caps_height
636
+ hide_title? ? @top_margin + @title_margin : @top_margin + @title_margin + @title_caps_height
637
637
  end
638
638
  end
639
639
 
@@ -642,7 +642,7 @@ module Gruff
642
642
 
643
643
  # Draw label
644
644
  text_renderer = Gruff::Renderer::Text.new(legend_label, font: @font, size: @legend_font_size, color: @font_color)
645
- text_renderer.render(@raw_columns, 1.0, current_x_offset + (legend_square_width * 1.7), current_y_offset, Magick::WestGravity)
645
+ text_renderer.add_to_render_queue(@raw_columns, 1.0, current_x_offset + (legend_square_width * 1.7), current_y_offset, Magick::WestGravity)
646
646
 
647
647
  # Now draw box with color of this dataset
648
648
  rect_renderer = Gruff::Renderer::Rectangle.new(color: store.data[index].color)
@@ -651,23 +651,19 @@ module Gruff
651
651
  current_x_offset + legend_square_width,
652
652
  current_y_offset + legend_square_width / 2.0)
653
653
 
654
- width = calculate_width(legend_font_size, legend_label)
655
- current_string_offset = width + (legend_square_width * 2.7)
654
+ width = calculate_width(@legend_font_size, legend_label)
655
+ current_x_offset += width + (legend_square_width * 2.7)
656
+ label_widths.first.shift
656
657
 
657
658
  # Handle wrapping
658
- label_widths.first.shift
659
659
  if label_widths.first.empty?
660
660
  label_widths.shift
661
- current_x_offset = center(sum(label_widths.first)) unless label_widths.empty?
662
- line_height = [@legend_caps_height, legend_square_width].max + legend_margin
661
+ current_x_offset = center(label_widths.first.sum) unless label_widths.empty?
662
+ line_height = [@legend_caps_height, legend_square_width].max + @legend_margin
663
663
  unless label_widths.empty?
664
664
  # Wrap to next line and shrink available graph dimensions
665
665
  current_y_offset += line_height
666
- @graph_top += line_height
667
- @graph_height = @graph_bottom - @graph_top
668
666
  end
669
- else
670
- current_x_offset += current_string_offset
671
667
  end
672
668
  end
673
669
  end
@@ -680,12 +676,12 @@ module Gruff
680
676
  font_weight = @bold_title ? Magick::BoldWeight : Magick::NormalWeight
681
677
  font_size = @title_font_size
682
678
 
683
- metrics = Renderer::Text.metrics(@title, font_size, font_weight)
679
+ metrics = Renderer::Text.metrics(@title, font, font_size, font_weight)
684
680
  if metrics.width > @raw_columns
685
681
  font_size = font_size * (@raw_columns / metrics.width) * 0.95
686
682
  end
687
683
  text_renderer = Gruff::Renderer::Text.new(@title, font: font, size: font_size, color: @font_color, weight: font_weight)
688
- text_renderer.render(@raw_columns, 1.0, 0, @top_margin)
684
+ text_renderer.add_to_render_queue(@raw_columns, 1.0, 0, @top_margin)
689
685
  end
690
686
 
691
687
  # Draws column labels below graph, centered over x_offset
@@ -700,17 +696,14 @@ module Gruff
700
696
  # TODO: See if index.odd? is the best stragegy
701
697
  y_offset += @label_stagger_height if index.odd?
702
698
 
703
- label_text = truncate_label_text(labels[index].to_s)
704
-
705
699
  if x_offset >= @graph_left && x_offset <= @graph_right
706
- text_renderer = Gruff::Renderer::Text.new(label_text, font: @font, size: @marker_font_size, color: @font_color)
707
- text_renderer.render(1.0, 1.0, x_offset, y_offset, gravity)
700
+ draw_label_at(1.0, 1.0, x_offset, y_offset, @labels[index], gravity)
708
701
  end
709
702
  end
710
703
  end
711
704
 
712
705
  def draw_unique_label(index)
713
- return if @hide_line_markers
706
+ return if hide_labels?
714
707
 
715
708
  @labels_seen ||= {}
716
709
  if !@labels[index].nil? && @labels_seen[index].nil?
@@ -719,18 +712,24 @@ module Gruff
719
712
  end
720
713
  end
721
714
 
715
+ def draw_label_at(width, height, x, y, text, gravity = Magick::NorthGravity)
716
+ label_text = truncate_label_text(text)
717
+ text_renderer = Gruff::Renderer::Text.new(label_text, font: @font, size: @marker_font_size, color: @font_color)
718
+ text_renderer.add_to_render_queue(width, height, x, y, gravity)
719
+ end
720
+
722
721
  # Draws the data value over the data point in bar graphs
723
722
  def draw_value_label(x_offset, y_offset, data_point, bar_value = false)
724
723
  return if @hide_line_markers && !bar_value
725
724
 
726
725
  text_renderer = Gruff::Renderer::Text.new(data_point, font: @font, size: @marker_font_size, color: @font_color)
727
- text_renderer.render(1.0, 1.0, x_offset, y_offset)
726
+ text_renderer.add_to_render_queue(1.0, 1.0, x_offset, y_offset)
728
727
  end
729
728
 
730
729
  # Shows an error message because you have no data.
731
730
  def draw_no_data
732
731
  text_renderer = Gruff::Renderer::Text.new(@no_data_message, font: @font, size: 80, color: @font_color)
733
- text_renderer.render(@raw_columns, @raw_rows / 2.0, 0, 10, Magick::CenterGravity)
732
+ text_renderer.render(@raw_columns, @raw_rows, 0, 0, Magick::CenterGravity)
734
733
  end
735
734
 
736
735
  # Resets everything to defaults (except data).
@@ -794,7 +793,67 @@ module Gruff
794
793
 
795
794
  private
796
795
 
796
+ def setup_marker_caps_height
797
+ hide_bottom_label_area? ? 0 : calculate_caps_height(@marker_font_size)
798
+ end
799
+
800
+ def setup_title_caps_height
801
+ hide_title? ? 0 : calculate_caps_height(@title_font_size) * @title.lines.to_a.size
802
+ end
803
+
804
+ def setup_legend_caps_height
805
+ @hide_legend ? 0 : calculate_caps_height(@legend_font_size)
806
+ end
807
+
808
+ def graph_right_margin
809
+ @hide_line_markers ? @right_margin : @right_margin + extra_room_for_long_label
810
+ end
811
+
812
+ def extra_room_for_long_label
813
+ # Make space for half the width of the rightmost column label.
814
+ # Might be greater than the number of columns if between-style bar markers are used.
815
+ last_label = @labels.keys.max.to_i
816
+ (last_label >= (column_count - 1) && @center_labels_over_point) ? calculate_width(@marker_font_size, @labels[last_label]) / 2.0 : 0
817
+ end
818
+
819
+ def setup_left_margin
820
+ return @left_margin if hide_left_label_area?
821
+
822
+ text = begin
823
+ if @has_left_labels
824
+ @labels.values.reduce('') { |value, memo| (value.to_s.length > memo.to_s.length) ? value : memo }
825
+ else
826
+ y_axis_label(maximum_value.to_f, @increment)
827
+ end
828
+ end
829
+ longest_left_label_width = calculate_width(@marker_font_size, truncate_label_text(text))
830
+ longest_left_label_width *= 1.25 if @has_left_labels
831
+
832
+ # Shift graph if left line numbers are hidden
833
+ line_number_width = @hide_line_numbers && !@has_left_labels ? 0.0 : (longest_left_label_width + LABEL_MARGIN * 2)
834
+
835
+ @left_margin + line_number_width + (@y_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN * 2)
836
+ end
837
+
838
+ def setup_top_margin
839
+ # When @hide title, leave a title_margin space for aesthetics.
840
+ # Same with @hide_legend
841
+ @top_margin +
842
+ (hide_title? ? @title_margin : @title_caps_height + @title_margin) +
843
+ ((@hide_legend || @legend_at_bottom) ? @legend_margin : calculate_legend_height + @legend_margin)
844
+ end
845
+
846
+ def setup_bottom_margin
847
+ graph_bottom_margin = hide_bottom_label_area? ? @bottom_margin : @bottom_margin + @marker_caps_height + LABEL_MARGIN
848
+ graph_bottom_margin += (calculate_legend_height + @legend_margin) if @legend_at_bottom
849
+
850
+ x_axis_label_height = @x_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN
851
+ # FIXME: Consider chart types other than bar
852
+ @raw_rows - graph_bottom_margin - x_axis_label_height - @label_stagger_height
853
+ end
854
+
797
855
  def truncate_label_text(text)
856
+ text = text.to_s
798
857
  return text if text.size <= @label_max_size
799
858
 
800
859
  if @label_truncation_style == :trailing_dots
@@ -823,7 +882,7 @@ module Gruff
823
882
  else
824
883
  value.to_s
825
884
  end
826
- elsif (@spread.to_f % (@marker_count.to_f == 0 ? 1 : @marker_count.to_f) == 0) || !@y_axis_increment.nil?
885
+ elsif (@spread.to_f % (marker_count.to_f == 0 ? 1 : marker_count.to_f) == 0) || !@y_axis_increment.nil?
827
886
  value.to_i.to_s
828
887
  elsif @spread > 10.0
829
888
  sprintf('%0i', value)
@@ -838,17 +897,74 @@ module Gruff
838
897
  parts.join('.')
839
898
  end
840
899
 
900
+ def x_axis_label(value, increment)
901
+ if @x_axis_label_format
902
+ @x_axis_label_format.call(value)
903
+ else
904
+ label(value, increment)
905
+ end
906
+ end
907
+
908
+ def y_axis_label(value, increment)
909
+ if @y_axis_label_format
910
+ @y_axis_label_format.call(value)
911
+ else
912
+ label(value, increment)
913
+ end
914
+ end
915
+
916
+ def calculate_legend_label_widths_for_each_line(legend_labels, legend_square_width)
917
+ # May fix legend drawing problem at small sizes
918
+ label_widths = [[]] # Used to calculate line wrap
919
+ legend_labels.each do |label|
920
+ width = calculate_width(@legend_font_size, label)
921
+ label_width = width + legend_square_width * 2.7
922
+ label_widths.last.push label_width
923
+
924
+ if label_widths.last.sum > (@raw_columns * 0.9)
925
+ label_widths.push [label_widths.last.pop]
926
+ end
927
+ end
928
+
929
+ label_widths
930
+ end
931
+
932
+ def calculate_legend_height
933
+ return 0.0 if @hide_legend
934
+
935
+ legend_labels = store.data.map(&:label)
936
+ legend_square_width = @legend_box_size
937
+ label_widths = calculate_legend_label_widths_for_each_line(legend_labels, legend_square_width)
938
+ legend_height = 0.0
939
+
940
+ legend_labels.each_with_index do |legend_label, _index|
941
+ next if legend_label.empty?
942
+
943
+ label_widths.first.shift
944
+ if label_widths.first.empty?
945
+ label_widths.shift
946
+ line_height = [@legend_caps_height, legend_square_width].max + @legend_margin
947
+ unless label_widths.empty?
948
+ # Wrap to next line and shrink available graph dimensions
949
+ legend_height += line_height
950
+ end
951
+ end
952
+ end
953
+
954
+ legend_height + @legend_caps_height
955
+ end
956
+
841
957
  # Returns the height of the capital letter 'X' for the current font and
842
958
  # size.
843
959
  #
844
960
  # Not scaled since it deals with dimensions that the regular scaling will
845
961
  # handle.
846
962
  def calculate_caps_height(font_size)
847
- metrics = Renderer::Text.metrics('X', font_size)
963
+ metrics = Renderer::Text.metrics('X', @font, font_size)
848
964
  metrics.height
849
965
  end
850
966
 
851
- # Returns the width of a string at this pointsize.
967
+ # Returns the width of a string at this point size.
852
968
  #
853
969
  # Not scaled since it deals with dimensions that the regular
854
970
  # scaling will handle.
@@ -856,7 +972,7 @@ module Gruff
856
972
  text = text.to_s
857
973
  return 0 if text.empty?
858
974
 
859
- metrics = Renderer::Text.metrics(text, font_size)
975
+ metrics = Renderer::Text.metrics(text, @font, font_size)
860
976
  metrics.width
861
977
  end
862
978
 
@@ -865,19 +981,10 @@ module Gruff
865
981
  # Try to use a number of horizontal lines that will come out even.
866
982
  #
867
983
  # TODO Do the same for larger numbers...100, 75, 50, 25
868
- if @marker_count.nil?
869
- (3..7).each do |lines|
870
- if @spread % lines == 0.0
871
- @marker_count = lines
872
- break
873
- end
874
- end
875
- @marker_count ||= 4
876
- end
877
- @increment = (@spread > 0 && @marker_count > 0) ? significant(@spread / @marker_count) : 1
984
+ @increment = (@spread > 0 && marker_count > 0) ? significant(@spread / marker_count) : 1
878
985
  else
879
986
  # TODO: Make this work for negative values
880
- @marker_count = (@spread / @y_axis_increment).to_i
987
+ self.marker_count = (@spread / @y_axis_increment).to_i
881
988
  @increment = @y_axis_increment
882
989
  end
883
990
  end