gruff 0.9.0-java → 0.12.2-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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +21 -4
  3. data/.rubocop_todo.yml +103 -49
  4. data/.travis.yml +3 -6
  5. data/CHANGELOG.md +30 -0
  6. data/README.md +4 -0
  7. data/gruff.gemspec +8 -3
  8. data/lib/gruff.rb +9 -3
  9. data/lib/gruff/accumulator_bar.rb +13 -5
  10. data/lib/gruff/area.rb +22 -5
  11. data/lib/gruff/bar.rb +38 -10
  12. data/lib/gruff/base.rb +325 -236
  13. data/lib/gruff/bezier.rb +18 -4
  14. data/lib/gruff/bullet.rb +22 -14
  15. data/lib/gruff/dot.rb +20 -33
  16. data/lib/gruff/helper/bar_conversion.rb +7 -7
  17. data/lib/gruff/helper/bar_value_label_mixin.rb +3 -0
  18. data/lib/gruff/helper/stacked_mixin.rb +1 -1
  19. data/lib/gruff/histogram.rb +59 -0
  20. data/lib/gruff/line.rb +33 -28
  21. data/lib/gruff/mini/bar.rb +10 -2
  22. data/lib/gruff/mini/legend.rb +9 -4
  23. data/lib/gruff/mini/pie.rb +9 -3
  24. data/lib/gruff/mini/side_bar.rb +18 -4
  25. data/lib/gruff/net.rb +41 -21
  26. data/lib/gruff/patch/rmagick.rb +22 -24
  27. data/lib/gruff/patch/string.rb +9 -4
  28. data/lib/gruff/photo_bar.rb +12 -16
  29. data/lib/gruff/pie.rb +24 -34
  30. data/lib/gruff/renderer/bezier.rb +4 -3
  31. data/lib/gruff/renderer/circle.rb +4 -3
  32. data/lib/gruff/renderer/dash_line.rb +4 -3
  33. data/lib/gruff/renderer/dot.rb +4 -3
  34. data/lib/gruff/renderer/ellipse.rb +4 -3
  35. data/lib/gruff/renderer/line.rb +14 -5
  36. data/lib/gruff/renderer/polygon.rb +5 -4
  37. data/lib/gruff/renderer/polyline.rb +4 -3
  38. data/lib/gruff/renderer/rectangle.rb +3 -2
  39. data/lib/gruff/renderer/renderer.rb +31 -38
  40. data/lib/gruff/renderer/text.rb +29 -7
  41. data/lib/gruff/scatter.rb +26 -24
  42. data/lib/gruff/scene.rb +0 -1
  43. data/lib/gruff/side_bar.rb +51 -20
  44. data/lib/gruff/side_stacked_bar.rb +42 -15
  45. data/lib/gruff/spider.rb +29 -17
  46. data/lib/gruff/stacked_area.rb +19 -8
  47. data/lib/gruff/stacked_bar.rb +34 -13
  48. data/lib/gruff/store/{base_data.rb → basic_data.rb} +9 -7
  49. data/lib/gruff/store/custom_data.rb +8 -6
  50. data/lib/gruff/store/store.rb +7 -6
  51. data/lib/gruff/store/xy_data.rb +10 -7
  52. data/lib/gruff/version.rb +1 -1
  53. metadata +33 -8
  54. data/Rakefile +0 -23
  55. data/docker/Dockerfile +0 -14
  56. data/docker/build.sh +0 -4
  57. data/docker/launch.sh +0 -4
@@ -1,10 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'gruff/base'
4
-
5
- # A special bar graph that shows a single dataset as a set of
6
- # stacked bars. The bottom bar shows the running total and
7
- # the top bar shows the new value being added to the array.
3
+ #
4
+ # Gruff::AccumulatorBar is a special bar graph that shows a
5
+ # single dataset as a set of stacked bars.
6
+ # The bottom bar shows the running total and the top bar shows
7
+ # the new value being added to the array.
8
+ #
9
+ # Here's how to set up a Gruff::AccumulatorBar.
10
+ #
11
+ # g = Gruff::AccumulatorBar.new
12
+ # g.title = 'Your Savings'
13
+ # g.data 'First', [1, 1, 1]
14
+ # g.write('accumulator_bar.png')
15
+ #
8
16
  class Gruff::AccumulatorBar < Gruff::StackedBar
9
17
  def draw
10
18
  raise(Gruff::IncorrectNumberOfDatasetsException) unless store.length == 1
data/lib/gruff/area.rb CHANGED
@@ -1,11 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'gruff/base'
4
-
3
+ #
4
+ # Gruff::Area provides an area graph which displays graphically
5
+ # quantitative data.
6
+ #
7
+ # Here's how to set up a Gruff::Area.
8
+ #
9
+ # g = Gruff::Area.new
10
+ # g.title = 'Area Graph'
11
+ # g.data :Jimmy, [25, 36, 86, 39, 25, 31, 79, 88]
12
+ # g.data :Charles, [80, 54, 67, 54, 68, 70, 90, 95]
13
+ # g.data :Julie, [22, 29, 35, 38, 36, 40, 46, 57]
14
+ # g.write('area.png')
15
+ #
5
16
  class Gruff::Area < Gruff::Base
17
+ # Specifies the filling opacity in area graph. Default is +0.85+.
18
+ attr_writer :fill_opacity
19
+
20
+ # Specifies the stroke width in line around area graph. Default is +2.0+.
21
+ attr_writer :stroke_width
22
+
6
23
  def initialize_ivars
7
24
  super
8
25
  @sorted_drawing = true
26
+ @fill_opacity = 0.85
27
+ @stroke_width = 2.0
9
28
  end
10
29
  private :initialize_ivars
11
30
 
@@ -36,9 +55,7 @@ class Gruff::Area < Gruff::Base
36
55
  poly_points << @graph_left
37
56
  poly_points << @graph_bottom - 1
38
57
 
39
- Gruff::Renderer::Polygon.new(color: data_row.color).render(poly_points)
58
+ Gruff::Renderer::Polygon.new(color: data_row.color, width: @stroke_width, opacity: @fill_opacity).render(poly_points)
40
59
  end
41
-
42
- Gruff::Renderer.finish
43
60
  end
44
61
  end
data/lib/gruff/bar.rb CHANGED
@@ -1,28 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'gruff/base'
4
- require 'gruff/helper/bar_conversion'
5
-
3
+ #
4
+ # Gruff::Bar provide a bar graph that presents categorical data
5
+ # with rectangular bars.
6
+ #
7
+ # Here's how to set up a Gruff::Bar.
8
+ #
9
+ # g = Gruff::Bar.new
10
+ # g.title = 'Bar Graph With Manual Colors'
11
+ # g.spacing_factor = 0.1
12
+ # g.group_spacing = 20
13
+ # g.data :Art, [0, 5, 8, 15], '#990000'
14
+ # g.data :Philosophy, [10, 3, 2, 8], '#009900'
15
+ # g.data :Science, [2, 15, 8, 11], '#990099'
16
+ # g.write('bar.png')
17
+ #
6
18
  class Gruff::Bar < Gruff::Base
19
+ using String::GruffCommify
20
+
7
21
  # Spacing factor applied between bars.
8
- attr_accessor :bar_spacing
22
+ attr_writer :bar_spacing
9
23
 
10
24
  # Spacing factor applied between a group of bars belonging to the same label.
11
- attr_accessor :group_spacing
25
+ attr_writer :group_spacing
12
26
 
13
27
  # Set the number output format for labels using sprintf.
14
28
  # Default is +"%.2f"+.
15
- attr_accessor :label_formatting
29
+ attr_writer :label_formatting
16
30
 
17
31
  # Output the values for the bars on a bar graph.
18
32
  # Default is +false+.
19
- attr_accessor :show_labels_for_bar_values
33
+ attr_writer :show_labels_for_bar_values
34
+
35
+ # Prevent drawing of column labels below a bar graph. Default is +false+.
36
+ attr_writer :hide_labels
20
37
 
21
38
  def initialize_ivars
22
39
  super
23
40
  @spacing_factor = 0.9
41
+ @group_spacing = 10
24
42
  @label_formatting = nil
25
43
  @show_labels_for_bar_values = false
44
+ @hide_labels = false
26
45
  end
27
46
  private :initialize_ivars
28
47
 
@@ -52,12 +71,23 @@ class Gruff::Bar < Gruff::Base
52
71
 
53
72
  protected
54
73
 
74
+ def hide_labels?
75
+ @hide_labels
76
+ end
77
+
78
+ def hide_left_label_area?
79
+ @hide_line_markers
80
+ end
81
+
82
+ def hide_bottom_label_area?
83
+ hide_labels?
84
+ end
85
+
55
86
  def draw_bars
56
87
  # Setup spacing.
57
88
  #
58
89
  # Columns sit side-by-side.
59
90
  @bar_spacing ||= @spacing_factor # space between the bars
60
- @group_spacing ||= 10
61
91
 
62
92
  bar_width = (@graph_width - calculate_spacing) / (column_count * store.length).to_f
63
93
  padding = (bar_width * (1 - @bar_spacing)) / 2
@@ -114,8 +144,6 @@ protected
114
144
 
115
145
  # Draw the last label if requested
116
146
  draw_label(@graph_right, column_count, Magick::NorthWestGravity) if @center_labels_over_point
117
-
118
- Gruff::Renderer.finish
119
147
  end
120
148
 
121
149
  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,33 +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
- THOUSAND_SEPARATOR = ','
29
-
30
- # Blank space above the graph.
31
- attr_accessor :top_margin
30
+ # Blank space above the graph. Default is +20+.
31
+ attr_writer :top_margin
32
32
 
33
- # Blank space below the graph.
34
- attr_accessor :bottom_margin
33
+ # Blank space below the graph. Default is +20+.
34
+ attr_writer :bottom_margin
35
35
 
36
- # Blank space to the right of the graph.
37
- attr_accessor :right_margin
36
+ # Blank space to the right of the graph. Default is +20+.
37
+ attr_writer :right_margin
38
38
 
39
- # Blank space to the left of the graph.
40
- attr_accessor :left_margin
39
+ # Blank space to the left of the graph. Default is +20+.
40
+ attr_writer :left_margin
41
41
 
42
- # Blank space below the title.
43
- attr_accessor :title_margin
42
+ # Blank space below the title. Default is +20+.
43
+ attr_writer :title_margin
44
44
 
45
- # Blank space below the legend.
46
- attr_accessor :legend_margin
45
+ # Blank space below the legend. Default is +20+.
46
+ attr_writer :legend_margin
47
47
 
48
48
  # A hash of names for the individual columns, where the key is the array
49
49
  # index for the column this label represents.
@@ -52,129 +52,125 @@ module Gruff
52
52
  #
53
53
  # @example
54
54
  # { 0 => 2005, 3 => 2006, 5 => 2007, 7 => 2008 }
55
- attr_accessor :labels
55
+ attr_writer :labels
56
56
 
57
57
  # Used internally for spacing.
58
58
  #
59
59
  # By default, labels are centered over the point they represent.
60
- attr_accessor :center_labels_over_point
60
+ attr_writer :center_labels_over_point
61
61
 
62
- # Used internally for horizontal graph types.
63
- attr_accessor :has_left_labels
62
+ # Used internally for horizontal graph types. Default is +false+.
63
+ attr_writer :has_left_labels
64
64
 
65
- # A label for the bottom of the graph.
66
- attr_accessor :x_axis_label
65
+ # Set a label for the bottom of the graph.
66
+ attr_writer :x_axis_label
67
67
 
68
- # A label for the left side of the graph.
69
- attr_accessor :y_axis_label
68
+ # Set a label for the left side of the graph.
69
+ attr_writer :y_axis_label
70
70
 
71
- # Manually set increment of the vertical marking lines.
72
- attr_accessor :x_axis_increment
71
+ # Set increment of the vertical marking lines.
72
+ attr_writer :x_axis_increment
73
73
 
74
- # Manually set increment of the horizontal marking lines.
75
- attr_accessor :y_axis_increment
74
+ # Set increment of the horizontal marking lines.
75
+ attr_writer :y_axis_increment
76
76
 
77
77
  # Height of staggering between labels (Bar graph only).
78
- attr_accessor :label_stagger_height
78
+ attr_writer :label_stagger_height
79
79
 
80
80
  # Truncates labels if longer than max specified.
81
- attr_accessor :label_max_size
81
+ attr_writer :label_max_size
82
82
 
83
- # How truncated labels visually appear if they exceed {#label_max_size}.
83
+ # How truncated labels visually appear if they exceed {#label_max_size=}.
84
84
  #
85
85
  # - +:absolute+ - does not show trailing dots to indicate truncation. This is the default.
86
- # - +: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=}
87
87
  # must be greater than 3).
88
- attr_accessor :label_truncation_style
88
+ attr_writer :label_truncation_style
89
89
 
90
90
  # Get or set the list of colors that will be used to draw the bars or lines.
91
91
  attr_accessor :colors
92
92
 
93
- # The large title of the graph displayed at the top.
94
- attr_accessor :title
95
-
96
- # Font used for titles, labels, etc. Works best if you provide the full
97
- # path to the TTF font file. RMagick must be built with the Freetype
98
- # libraries for this to work properly.
99
- attr_reader :font
93
+ # Set the large title of the graph displayed at the top.
94
+ attr_writer :title
100
95
 
101
- # Same as font but for the title.
102
- attr_accessor :title_font
96
+ # Same as {#font=} but for the title.
97
+ attr_writer :title_font
103
98
 
104
- # Specifies whether to draw the title bolded or not.
105
- attr_accessor :bold_title
99
+ # Specifies whether to draw the title bolded or not. Default is +true+.
100
+ attr_writer :bold_title
106
101
 
107
- attr_accessor :font_color
102
+ # Specifies the text color.
103
+ attr_writer :font_color
108
104
 
109
- # Prevent drawing of line markers.
110
- attr_accessor :hide_line_markers
105
+ # Prevent drawing of line markers. Default is +false+.
106
+ attr_writer :hide_line_markers
111
107
 
112
- # Prevent drawing of the legend.
113
- attr_accessor :hide_legend
108
+ # Prevent drawing of the legend. Default is +false+.
109
+ attr_writer :hide_legend
114
110
 
115
- # Prevent drawing of the title.
116
- attr_accessor :hide_title
111
+ # Prevent drawing of the title. Default is +false+.
112
+ attr_writer :hide_title
117
113
 
118
- # Prevent drawing of line numbers.
119
- attr_accessor :hide_line_numbers
114
+ # Prevent drawing of line numbers. Default is +false+.
115
+ attr_writer :hide_line_numbers
120
116
 
121
- # Message shown when there is no data. Fits up to 20 characters. Defaults
117
+ # Set a message shown when there is no data. Fits up to 20 characters. Defaults
122
118
  # to +"No Data."+.
123
- attr_accessor :no_data_message
119
+ attr_writer :no_data_message
124
120
 
125
- # The font size of the large title at the top of the graph.
126
- attr_accessor :title_font_size
121
+ # Set the font size of the large title at the top of the graph. Default is +36+.
122
+ attr_writer :title_font_size
127
123
 
128
124
  # Optionally set the size of the font. Based on an 800x600px graph.
129
125
  # Default is +20+.
130
126
  #
131
127
  # Will be scaled down if the graph is smaller than 800px wide.
132
- attr_accessor :legend_font_size
128
+ attr_writer :legend_font_size
133
129
 
134
- # Display the legend under the graph.
135
- attr_accessor :legend_at_bottom
130
+ # Display the legend under the graph. Default is +false+.
131
+ attr_writer :legend_at_bottom
136
132
 
137
- # The font size of the labels around the graph.
138
- attr_accessor :marker_font_size
133
+ # The font size of the labels around the graph. Default is +21+.
134
+ attr_writer :marker_font_size
139
135
 
140
- # The color of the auxiliary lines.
141
- attr_accessor :marker_color
142
- attr_accessor :marker_shadow_color
136
+ # Set the color of the auxiliary lines.
137
+ attr_writer :marker_color
143
138
 
144
- # The number of horizontal lines shown for reference.
145
- attr_accessor :marker_count
139
+ # Set the shadow color of the auxiliary lines.
140
+ attr_writer :marker_shadow_color
146
141
 
147
- # Set to true if you want the data sets sorted with largest avg values drawn
148
- # first.
149
- attr_accessor :sort
142
+ # Set the number of horizontal lines shown for reference.
143
+ attr_writer :marker_count
150
144
 
151
- # Set to true if you want the data sets drawn with largest avg values drawn
152
- # first. This does not affect the legend.
153
- attr_accessor :sorted_drawing
145
+ # Set to +true+ if you want the data sets sorted with largest avg values drawn
146
+ # first. Default is +false+.
147
+ attr_writer :sort
154
148
 
155
- # Experimental
156
- attr_accessor :additional_line_values
149
+ # Set to +true+ if you want the data sets drawn with largest avg values drawn
150
+ # first. This does not affect the legend. Default is +false+.
151
+ attr_writer :sorted_drawing
157
152
 
158
153
  # Optionally set the size of the colored box by each item in the legend.
159
154
  # Default is +20.0+.
160
155
  #
161
156
  # Will be scaled down if graph is smaller than 800px wide.
162
- attr_accessor :legend_box_size
157
+ attr_writer :legend_box_size
163
158
 
164
159
  # With Side Bars use the data label for the marker value to the left of the bar.
165
160
  # Default is +false+.
166
- attr_accessor :use_data_label
161
+ attr_writer :use_data_label
167
162
 
168
163
  # If one numerical argument is given, the graph is drawn at 4/3 ratio
169
- # according to the given width (800 results in 800x600, 400 gives 400x300,
164
+ # according to the given width (+800+ results in 800x600, +400+ gives 400x300,
170
165
  # etc.).
171
166
  #
172
- # Or, send a geometry string for other ratios ('800x400', '400x225').
167
+ # Or, send a geometry string for other ratios ( +'800x400'+, +'400x225'+).
168
+ #
169
+ # @param target_width [Numeric, String] The graph image width.
170
+ #
173
171
  def initialize(target_width = DEFAULT_TARGET_WIDTH)
174
172
  if target_width.is_a?(String)
175
- geometric_width, geometric_height = target_width.split('x')
176
- @columns = geometric_width.to_f
177
- @rows = geometric_height.to_f
173
+ @columns, @rows = target_width.split('x').map(&:to_f)
178
174
  else
179
175
  @columns = target_width.to_f
180
176
  @rows = target_width.to_f * 0.75
@@ -182,36 +178,44 @@ module Gruff
182
178
  @columns.freeze
183
179
  @rows.freeze
184
180
 
181
+ initialize_graph_scale
185
182
  initialize_ivars
183
+ initialize_store
186
184
 
187
185
  self.theme = Themes::KEYNOTE
188
186
  end
189
187
 
190
- # Set instance variables for this object.
188
+ def initialize_graph_scale
189
+ @raw_columns = DEFAULT_TARGET_WIDTH
190
+ @raw_rows = DEFAULT_TARGET_WIDTH * (@rows / @columns)
191
+ @raw_columns.freeze
192
+ @raw_rows.freeze
193
+
194
+ @scale = @columns / @raw_columns
195
+ @scale.freeze
196
+ end
197
+ protected :initialize_graph_scale
198
+
199
+ def initialize_store
200
+ @store = Gruff::Store.new(Gruff::Store::BasicData)
201
+ end
202
+ protected :initialize_store
203
+
204
+ # Initialize instance variable of attributes
191
205
  #
192
206
  # Subclasses can override this, call super, then set values separately.
193
207
  #
194
208
  # This makes it possible to set defaults in a subclass but still allow
195
209
  # developers to change this values in their program.
196
210
  def initialize_ivars
197
- # Internal for calculations
198
- @raw_columns = DEFAULT_TARGET_WIDTH
199
- @raw_rows = DEFAULT_TARGET_WIDTH * (@rows / @columns)
200
- @raw_columns.freeze
201
- @raw_rows.freeze
202
-
203
211
  @marker_count = nil
204
212
  @maximum_value = @minimum_value = nil
205
- @increment = nil
206
213
  @labels = {}
207
- @labels_seen = {}
208
214
  @sort = false
209
215
  @sorted_drawing = false
210
216
  @title = nil
211
217
  @title_font = nil
212
218
 
213
- @scale = @columns / @raw_columns
214
-
215
219
  @font = nil
216
220
  @bold_title = true
217
221
 
@@ -234,25 +238,25 @@ module Gruff
234
238
  @label_max_size = 0
235
239
  @label_truncation_style = :absolute
236
240
 
237
- @additional_line_values = []
238
- @additional_line_colors = []
239
- @theme_options = {}
240
-
241
241
  @use_data_label = false
242
242
  @x_axis_increment = nil
243
243
  @x_axis_label = @y_axis_label = nil
244
244
  @y_axis_increment = nil
245
-
246
- @store = Gruff::Store.new(Gruff::Store::BaseData)
247
245
  end
248
246
  protected :initialize_ivars
249
247
 
250
248
  # Sets the top, bottom, left and right margins to +margin+.
249
+ #
250
+ # @param margin [Numeric] The margin size.
251
+ #
251
252
  def margins=(margin)
252
253
  @top_margin = @left_margin = @right_margin = @bottom_margin = margin
253
254
  end
254
255
 
255
256
  # Sets the font for graph text to the font at +font_path+.
257
+ #
258
+ # @param font_path [String] The path to font.
259
+ #
256
260
  def font=(font_path)
257
261
  @font = font_path
258
262
  Gruff::Renderer.font = @font
@@ -260,6 +264,8 @@ module Gruff
260
264
 
261
265
  # Add a color to the list of available colors for lines.
262
266
  #
267
+ # @param colorname [String] The color.
268
+ #
263
269
  # @example
264
270
  # add_color('#c0e9d3')
265
271
  def add_color(colorname)
@@ -277,6 +283,8 @@ module Gruff
277
283
  # {#data} method made prior to this call will use whatever color scheme
278
284
  # was in place at the time data was called.
279
285
  #
286
+ # @param color_list [Array] The array of colors.
287
+ #
280
288
  # @example
281
289
  # replace_colors ['#cc99cc', '#d9e043', '#34d8a2']
282
290
  def replace_colors(color_list = [])
@@ -289,19 +297,29 @@ module Gruff
289
297
  # graph.theme = {
290
298
  # colors: %w(orange purple green white red),
291
299
  # marker_color: 'blue',
292
- # background_colors: ['black', 'grey', :top_bottom]
300
+ # background_colors: ['black', 'grey'],
301
+ # background_direction: :top_bottom
293
302
  # }
294
303
  #
295
304
  # +background_image: 'squirrel.png'+ is also possible.
296
305
  #
306
+ # +background_direction+ accepts one of following parameters.
307
+ # - +:top_bottom+
308
+ # - +:bottom_top+
309
+ # - +:left_right+
310
+ # - +:right_left+
311
+ # - +:topleft_bottomright+
312
+ # - +:topright_bottomleft+
313
+ #
297
314
  # (Or hopefully something better looking than that.)
298
315
  #
316
+ # @param options [Hash] The optional setting for theme
317
+ #
299
318
  def theme=(options)
300
319
  reset_themes
301
320
 
302
321
  defaults = {
303
322
  colors: %w[black white],
304
- additional_line_colors: [],
305
323
  marker_color: 'white',
306
324
  marker_shadow_color: nil,
307
325
  font_color: 'black',
@@ -314,35 +332,42 @@ module Gruff
314
332
  @marker_color = @theme_options[:marker_color]
315
333
  @marker_shadow_color = @theme_options[:marker_shadow_color]
316
334
  @font_color = @theme_options[:font_color] || @marker_color
317
- @additional_line_colors = @theme_options[:additional_line_colors]
318
335
 
319
336
  Gruff::Renderer.setup(@columns, @rows, @font, @scale, @theme_options)
320
337
  end
321
338
 
339
+ # Apply Apple's keynote theme.
322
340
  def theme_keynote
323
341
  self.theme = Themes::KEYNOTE
324
342
  end
325
343
 
344
+ # Apply 37signals theme.
326
345
  def theme_37signals
327
346
  self.theme = Themes::THIRTYSEVEN_SIGNALS
328
347
  end
329
348
 
349
+ # Apply Rails theme.
330
350
  def theme_rails_keynote
331
351
  self.theme = Themes::RAILS_KEYNOTE
332
352
  end
333
353
 
354
+ # Apply Odeo theme.
334
355
  def theme_odeo
335
356
  self.theme = Themes::ODEO
336
357
  end
337
358
 
359
+ # Apply pastel theme.
338
360
  def theme_pastel
339
361
  self.theme = Themes::PASTEL
340
362
  end
341
363
 
364
+ # Apply greyscale theme.
342
365
  def theme_greyscale
343
366
  self.theme = Themes::GREYSCALE
344
367
  end
345
368
 
369
+ # Input the data in the graph.
370
+ #
346
371
  # Parameters are an array where the first element is the name of the dataset
347
372
  # and the value is an array of values to plot.
348
373
  #
@@ -352,6 +377,10 @@ module Gruff
352
377
  # If the color argument is nil, the next color from the default theme will
353
378
  # be used.
354
379
  #
380
+ # @param name [String, Symbol] The name of the dataset.
381
+ # @param data_points [Array] The array of dataset.
382
+ # @param color [String] The color for drawing graph of dataset.
383
+ #
355
384
  # @note
356
385
  # If you want to use a preset theme, you must set it before calling {#data}.
357
386
  #
@@ -382,17 +411,45 @@ module Gruff
382
411
 
383
412
  # Writes the graph to a file. Defaults to +'graph.png'+
384
413
  #
414
+ # @param file_name [String] The file name of output image.
415
+ #
385
416
  # @example
386
417
  # write('graphs/my_pretty_graph.png')
387
418
  def write(file_name = 'graph.png')
388
- draw
389
- Gruff::Renderer.write(file_name)
419
+ to_image.write(file_name)
420
+ end
421
+
422
+ # Return a rendered graph image.
423
+ # This can use RMagick's methods to adjust the image before saving.
424
+ #
425
+ # @return [Magick::Image] The rendered image.
426
+ #
427
+ # @example
428
+ # g = Gruff::Line.new
429
+ # g.data :Jimmy, [25, 36, 86, 39, 25, 31, 79, 88]
430
+ # g.data :Charles, [80, 54, 67, 54, 68, 70, 90, 95]
431
+ # image = g.to_image
432
+ # image = image.resize(400, 300).quantize(128, Magick::RGBColorspace)
433
+ # image.write('test.png')
434
+ #
435
+ def to_image
436
+ @to_image ||= begin
437
+ draw
438
+ Gruff::Renderer.finish
439
+ Gruff::Renderer.instance.image
440
+ end
390
441
  end
391
442
 
392
443
  # Return the graph as a rendered binary blob.
393
- def to_blob(file_format = 'PNG')
394
- draw
395
- Gruff::Renderer.to_blob(file_format)
444
+ #
445
+ # @param image_format [String] The image format of binary blob.
446
+ #
447
+ # @deprecated Please use +to_image.to_blob+ instead.
448
+ def to_blob(image_format = 'PNG')
449
+ warn '#to_blob is deprecated. Please use `to_image.to_blob` instead'
450
+ to_image.to_blob do
451
+ self.format = image_format
452
+ end
396
453
  end
397
454
 
398
455
  protected
@@ -455,6 +512,18 @@ module Gruff
455
512
  store.columns
456
513
  end
457
514
 
515
+ def marker_count
516
+ @marker_count ||= begin
517
+ count = nil
518
+ (3..7).each do |lines|
519
+ if @spread.to_f % lines == 0.0
520
+ count = lines and break
521
+ end
522
+ end
523
+ count || 4
524
+ end
525
+ end
526
+
458
527
  # Make copy of data with values scaled between 0-100
459
528
  def normalize
460
529
  store.normalize(minimum: minimum_value, spread: @spread)
@@ -465,61 +534,37 @@ module Gruff
465
534
  @spread = @spread > 0 ? @spread : 1
466
535
  end
467
536
 
468
- ##
469
- # Calculates size of drawable area, general font dimensions, etc.
470
-
471
- def setup_graph_measurements
472
- @marker_caps_height = @hide_line_markers ? 0 : calculate_caps_height(@marker_font_size)
473
- @title_caps_height = (@hide_title || @title.nil?) ? 0 : calculate_caps_height(@title_font_size) * @title.lines.to_a.size
474
- @legend_caps_height = @hide_legend ? 0 : calculate_caps_height(@legend_font_size)
475
-
476
- if @hide_line_markers
477
- @graph_left = @left_margin
478
- @graph_right_margin = @right_margin
479
- @graph_bottom_margin = @bottom_margin
480
- else
481
- if @has_left_labels
482
- longest_left_label_width = calculate_width(@marker_font_size,
483
- labels.values.reduce('') { |value, memo| (value.to_s.length > memo.to_s.length) ? value : memo }) * 1.25
484
- else
485
- longest_left_label_width = calculate_width(@marker_font_size,
486
- label(maximum_value.to_f, @increment))
487
- end
537
+ def hide_title?
538
+ @hide_title || @title.nil? || @title.empty?
539
+ end
488
540
 
489
- # Shift graph if left line numbers are hidden
490
- line_number_width = @hide_line_numbers && !@has_left_labels ? 0.0 : (longest_left_label_width + LABEL_MARGIN * 2)
541
+ def hide_labels?
542
+ @hide_line_markers
543
+ end
491
544
 
492
- @graph_left = @left_margin + line_number_width + (@y_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN * 2)
545
+ def hide_left_label_area?
546
+ @hide_line_markers
547
+ end
493
548
 
494
- # Make space for half the width of the rightmost column label.
495
- # Might be greater than the number of columns if between-style bar markers are used.
496
- last_label = @labels.keys.max.to_i
497
- extra_room_for_long_label = begin
498
- (last_label >= (column_count - 1) && @center_labels_over_point) ? calculate_width(@marker_font_size, @labels[last_label]) / 2.0 : 0
499
- end
500
- @graph_right_margin = @right_margin + extra_room_for_long_label
549
+ def hide_bottom_label_area?
550
+ @hide_line_markers
551
+ end
501
552
 
502
- @graph_bottom_margin = @bottom_margin + @marker_caps_height + LABEL_MARGIN
503
- end
553
+ ##
554
+ # Calculates size of drawable area, general font dimensions, etc.
504
555
 
505
- @graph_right = @raw_columns - @graph_right_margin
506
- @graph_width = @raw_columns - @graph_left - @graph_right_margin
556
+ def setup_graph_measurements
557
+ @marker_caps_height = setup_marker_caps_height
558
+ @title_caps_height = setup_title_caps_height
559
+ @legend_caps_height = setup_legend_caps_height
507
560
 
508
- # When @hide title, leave a title_margin space for aesthetics.
509
- # Same with @hide_legend
510
- @graph_top = begin
511
- if @legend_at_bottom
512
- @top_margin
513
- else
514
- @top_margin +
515
- (@hide_title ? title_margin : @title_caps_height + title_margin) +
516
- (@hide_legend ? legend_margin : @legend_caps_height + legend_margin)
517
- end
518
- end
561
+ margin_on_right = graph_right_margin
562
+ @graph_right = @raw_columns - margin_on_right
563
+ @graph_left = setup_left_margin
564
+ @graph_top = setup_top_margin
565
+ @graph_bottom = setup_bottom_margin
519
566
 
520
- x_axis_label_height = @x_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN
521
- # FIXME: Consider chart types other than bar
522
- @graph_bottom = @raw_rows - @graph_bottom_margin - x_axis_label_height - @label_stagger_height
567
+ @graph_width = @raw_columns - @graph_left - margin_on_right
523
568
  @graph_height = @graph_bottom - @graph_top
524
569
  end
525
570
 
@@ -529,17 +574,17 @@ module Gruff
529
574
  # X Axis
530
575
  # Centered vertically and horizontally by setting the
531
576
  # height to 1.0 and the width to the width of the graph.
532
- x_axis_label_y_coordinate = @graph_bottom + LABEL_MARGIN * 2 + @marker_caps_height
577
+ x_axis_label_y_coordinate = @graph_bottom + LABEL_MARGIN + @marker_caps_height
533
578
 
534
579
  # TODO: Center between graph area
535
580
  text_renderer = Gruff::Renderer::Text.new(@x_axis_label, font: @font, size: @marker_font_size, color: @font_color)
536
- text_renderer.render(@raw_columns, 1.0, 0.0, x_axis_label_y_coordinate)
581
+ text_renderer.add_to_render_queue(@raw_columns, 1.0, 0.0, x_axis_label_y_coordinate)
537
582
  end
538
583
 
539
584
  if @y_axis_label
540
585
  # Y Axis, rotated vertically
541
586
  text_renderer = Gruff::Renderer::Text.new(@y_axis_label, font: @font, size: @marker_font_size, color: @font_color, rotation: -90)
542
- text_renderer.render(1.0, @raw_rows, @left_margin + @marker_caps_height / 2.0, 0.0, Magick::CenterGravity)
587
+ text_renderer.add_to_render_queue(1.0, @raw_rows, @left_margin + @marker_caps_height / 2.0, 0.0, Magick::CenterGravity)
543
588
  end
544
589
  end
545
590
 
@@ -550,32 +595,21 @@ module Gruff
550
595
  increment_scaled = @graph_height.to_f / (@spread / @increment)
551
596
 
552
597
  # Draw horizontal line markers and annotate with numbers
553
- (0..@marker_count).each do |index|
598
+ (0..marker_count).each do |index|
554
599
  y = @graph_top + @graph_height - index.to_f * increment_scaled
555
600
 
556
- Gruff::Renderer::Line.new(color: @marker_color).render(@graph_left, y, @graph_right, y)
557
- #If the user specified a marker shadow color, draw a shadow just below it
558
- if @marker_shadow_color
559
- Gruff::Renderer::Line.new(color: @marker_shadow_color).render(@graph_left, y + 1, @graph_right, y + 1)
560
- end
561
-
562
- marker_label = BigDecimal(index.to_s) * BigDecimal(@increment.to_s) + BigDecimal(minimum_value.to_s)
601
+ line_renderer = Gruff::Renderer::Line.new(color: @marker_color, shadow_color: @marker_shadow_color)
602
+ line_renderer.render(@graph_left, y, @graph_right, y)
563
603
 
564
604
  unless @hide_line_numbers
605
+ marker_label = BigDecimal(index.to_s) * BigDecimal(@increment.to_s) + BigDecimal(minimum_value.to_s)
565
606
  label = label(marker_label, @increment)
566
607
  text_renderer = Gruff::Renderer::Text.new(label, font: @font, size: @marker_font_size, color: @font_color)
567
- text_renderer.render(@graph_left - LABEL_MARGIN, 1.0, 0.0, y, Magick::EastGravity)
608
+ text_renderer.add_to_render_queue(@graph_left - LABEL_MARGIN, 1.0, 0.0, y, Magick::EastGravity)
568
609
  end
569
610
  end
570
611
  end
571
612
 
572
- # Return the sum of values in an array.
573
- #
574
- # Duplicated to not conflict with active_support in Rails.
575
- def sum(arr)
576
- arr.reduce(0) { |i, m| m + i }
577
- end
578
-
579
613
  # Return a calculation of center
580
614
  def center(size)
581
615
  (@raw_columns - size) / 2
@@ -587,34 +621,24 @@ module Gruff
587
621
  return if @hide_legend
588
622
 
589
623
  legend_labels = store.data.map(&:label)
590
-
591
624
  legend_square_width = @legend_box_size # small square with color of this item
625
+ label_widths = calculate_legend_label_widths_for_each_line(legend_labels, legend_square_width)
592
626
 
593
- # May fix legend drawing problem at small sizes
594
- label_widths = [[]] # Used to calculate line wrap
595
- legend_labels.each do |label|
596
- metrics = Renderer::Text.metrics(label, @legend_font_size)
597
- label_width = metrics.width + legend_square_width * 2.7
598
- label_widths.last.push label_width
599
-
600
- if sum(label_widths.last) > (@raw_columns * 0.9)
601
- label_widths.push [label_widths.last.pop]
602
- end
603
- end
604
-
605
- current_x_offset = center(sum(label_widths.first))
627
+ current_x_offset = center(label_widths.first.sum)
606
628
  current_y_offset = begin
607
629
  if @legend_at_bottom
608
- @graph_height + title_margin
630
+ @graph_height + @title_margin
609
631
  else
610
- @hide_title ? @top_margin + title_margin : @top_margin + title_margin + @title_caps_height
632
+ hide_title? ? @top_margin + @title_margin : @top_margin + @title_margin + @title_caps_height
611
633
  end
612
634
  end
613
635
 
614
636
  legend_labels.each_with_index do |legend_label, index|
637
+ next if legend_label.empty?
638
+
615
639
  # Draw label
616
640
  text_renderer = Gruff::Renderer::Text.new(legend_label, font: @font, size: @legend_font_size, color: @font_color)
617
- text_renderer.render(@raw_columns, 1.0, current_x_offset + (legend_square_width * 1.7), current_y_offset, Magick::WestGravity)
641
+ text_renderer.add_to_render_queue(@raw_columns, 1.0, current_x_offset + (legend_square_width * 1.7), current_y_offset, Magick::WestGravity)
618
642
 
619
643
  # Now draw box with color of this dataset
620
644
  rect_renderer = Gruff::Renderer::Rectangle.new(color: store.data[index].color)
@@ -623,32 +647,30 @@ module Gruff
623
647
  current_x_offset + legend_square_width,
624
648
  current_y_offset + legend_square_width / 2.0)
625
649
 
626
- metrics = Renderer::Text.metrics(legend_label, legend_font_size)
627
- current_string_offset = metrics.width + (legend_square_width * 2.7)
650
+ width = calculate_width(@legend_font_size, legend_label)
651
+ current_x_offset += width + (legend_square_width * 2.7)
652
+ label_widths.first.shift
628
653
 
629
654
  # Handle wrapping
630
- label_widths.first.shift
631
655
  if label_widths.first.empty?
632
656
  label_widths.shift
633
- current_x_offset = center(sum(label_widths.first)) unless label_widths.empty?
634
- line_height = [@legend_caps_height, legend_square_width].max + legend_margin
657
+ current_x_offset = center(label_widths.first.sum) unless label_widths.empty?
658
+ line_height = [@legend_caps_height, legend_square_width].max + @legend_margin
635
659
  unless label_widths.empty?
636
660
  # Wrap to next line and shrink available graph dimensions
637
661
  current_y_offset += line_height
638
662
  @graph_top += line_height
639
663
  @graph_height = @graph_bottom - @graph_top
640
664
  end
641
- else
642
- current_x_offset += current_string_offset
643
665
  end
644
666
  end
645
667
  end
646
668
 
647
669
  # Draws a title on the graph.
648
670
  def draw_title
649
- return if @hide_title || @title.nil?
671
+ return if hide_title?
650
672
 
651
- font = (@title_font || @font) if @title_font || @font
673
+ font = @title_font || @font
652
674
  font_weight = @bold_title ? Magick::BoldWeight : Magick::NormalWeight
653
675
  font_size = @title_font_size
654
676
 
@@ -657,7 +679,7 @@ module Gruff
657
679
  font_size = font_size * (@raw_columns / metrics.width) * 0.95
658
680
  end
659
681
  text_renderer = Gruff::Renderer::Text.new(@title, font: font, size: font_size, color: @font_color, weight: font_weight)
660
- text_renderer.render(@raw_columns, 1.0, 0, @top_margin)
682
+ text_renderer.add_to_render_queue(@raw_columns, 1.0, 0, @top_margin)
661
683
  end
662
684
 
663
685
  # Draws column labels below graph, centered over x_offset
@@ -672,31 +694,19 @@ module Gruff
672
694
  # TODO: See if index.odd? is the best stragegy
673
695
  y_offset += @label_stagger_height if index.odd?
674
696
 
675
- label_text = labels[index].to_s
676
-
677
- # TESTME
678
- # FIXME: Consider chart types other than bar
679
- if label_text.size > @label_max_size
680
- if @label_truncation_style == :trailing_dots
681
- if @label_max_size > 3
682
- # 4 because '...' takes up 3 chars
683
- label_text = "#{label_text[0..(@label_max_size - 4)]}..."
684
- end
685
- else # @label_truncation_style is :absolute (default)
686
- label_text = label_text[0..(@label_max_size - 1)]
687
- end
688
- end
697
+ label_text = truncate_label_text(@labels[index].to_s)
689
698
 
690
699
  if x_offset >= @graph_left && x_offset <= @graph_right
691
700
  text_renderer = Gruff::Renderer::Text.new(label_text, font: @font, size: @marker_font_size, color: @font_color)
692
- text_renderer.render(1.0, 1.0, x_offset, y_offset, gravity)
701
+ text_renderer.add_to_render_queue(1.0, 1.0, x_offset, y_offset, gravity)
693
702
  end
694
703
  end
695
704
  end
696
705
 
697
706
  def draw_unique_label(index)
698
- return if @hide_line_markers
707
+ return if hide_labels?
699
708
 
709
+ @labels_seen ||= {}
700
710
  if !@labels[index].nil? && @labels_seen[index].nil?
701
711
  yield
702
712
  @labels_seen[index] = 1
@@ -708,18 +718,17 @@ module Gruff
708
718
  return if @hide_line_markers && !bar_value
709
719
 
710
720
  text_renderer = Gruff::Renderer::Text.new(data_point, font: @font, size: @marker_font_size, color: @font_color)
711
- text_renderer.render(1.0, 1.0, x_offset, y_offset)
721
+ text_renderer.add_to_render_queue(1.0, 1.0, x_offset, y_offset)
712
722
  end
713
723
 
714
724
  # Shows an error message because you have no data.
715
725
  def draw_no_data
716
726
  text_renderer = Gruff::Renderer::Text.new(@no_data_message, font: @font, size: 80, color: @font_color)
717
- text_renderer.render(@raw_columns, @raw_rows / 2.0, 0, 10, Magick::CenterGravity)
727
+ text_renderer.render(@raw_columns, @raw_rows, 0, 0, Magick::CenterGravity)
718
728
  end
719
729
 
720
730
  # Resets everything to defaults (except data).
721
731
  def reset_themes
722
- @labels_seen = {}
723
732
  @theme_options = {}
724
733
  end
725
734
 
@@ -768,7 +777,7 @@ module Gruff
768
777
 
769
778
  # Set the color for each data set unless it was given in the data(...) call.
770
779
  def set_colors
771
- store.set_colors!(@colors)
780
+ store.change_colors(@colors)
772
781
  end
773
782
 
774
783
  # Sort with largest overall summed value at front of array so it shows up
@@ -779,6 +788,78 @@ module Gruff
779
788
 
780
789
  private
781
790
 
791
+ def setup_marker_caps_height
792
+ hide_bottom_label_area? ? 0 : calculate_caps_height(@marker_font_size)
793
+ end
794
+
795
+ def setup_title_caps_height
796
+ hide_title? ? 0 : calculate_caps_height(@title_font_size) * @title.lines.to_a.size
797
+ end
798
+
799
+ def setup_legend_caps_height
800
+ @hide_legend ? 0 : calculate_caps_height(@legend_font_size)
801
+ end
802
+
803
+ def graph_right_margin
804
+ @hide_line_markers ? @right_margin : @right_margin + extra_room_for_long_label
805
+ end
806
+
807
+ def extra_room_for_long_label
808
+ # Make space for half the width of the rightmost column label.
809
+ # Might be greater than the number of columns if between-style bar markers are used.
810
+ last_label = @labels.keys.max.to_i
811
+ (last_label >= (column_count - 1) && @center_labels_over_point) ? calculate_width(@marker_font_size, @labels[last_label]) / 2.0 : 0
812
+ end
813
+
814
+ def setup_left_margin
815
+ return @left_margin if hide_left_label_area?
816
+
817
+ text = begin
818
+ if @has_left_labels
819
+ @labels.values.reduce('') { |value, memo| (value.to_s.length > memo.to_s.length) ? value : memo }
820
+ else
821
+ label(maximum_value.to_f, @increment)
822
+ end
823
+ end
824
+ longest_left_label_width = calculate_width(@marker_font_size, text)
825
+ longest_left_label_width *= 1.25 if @has_left_labels
826
+
827
+ # Shift graph if left line numbers are hidden
828
+ line_number_width = @hide_line_numbers && !@has_left_labels ? 0.0 : (longest_left_label_width + LABEL_MARGIN * 2)
829
+
830
+ @left_margin + line_number_width + (@y_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN * 2)
831
+ end
832
+
833
+ def setup_top_margin
834
+ return @top_margin if @legend_at_bottom
835
+
836
+ # When @hide title, leave a title_margin space for aesthetics.
837
+ # Same with @hide_legend
838
+ @top_margin +
839
+ (hide_title? ? @title_margin : @title_caps_height + @title_margin) +
840
+ (@hide_legend ? @legend_margin : @legend_caps_height + @legend_margin)
841
+ end
842
+
843
+ def setup_bottom_margin
844
+ graph_bottom_margin = hide_bottom_label_area? ? @bottom_margin : @bottom_margin + @marker_caps_height + LABEL_MARGIN
845
+
846
+ x_axis_label_height = @x_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN
847
+ # FIXME: Consider chart types other than bar
848
+ @raw_rows - graph_bottom_margin - x_axis_label_height - @label_stagger_height
849
+ end
850
+
851
+ def truncate_label_text(text)
852
+ return text if text.size <= @label_max_size
853
+
854
+ if @label_truncation_style == :trailing_dots
855
+ # 4 because '...' takes up 3 chars
856
+ text = "#{text[0..(@label_max_size - 4)]}..." if @label_max_size > 3
857
+ else
858
+ text = text[0..(@label_max_size - 1)]
859
+ end
860
+ text
861
+ end
862
+
782
863
  # Return a formatted string representing a number value that should be
783
864
  # printed as a label.
784
865
  def label(value, increment)
@@ -796,7 +877,7 @@ module Gruff
796
877
  else
797
878
  value.to_s
798
879
  end
799
- elsif (@spread.to_f % (@marker_count.to_f == 0 ? 1 : @marker_count.to_f) == 0) || !@y_axis_increment.nil?
880
+ elsif (@spread.to_f % (marker_count.to_f == 0 ? 1 : marker_count.to_f) == 0) || !@y_axis_increment.nil?
800
881
  value.to_i.to_s
801
882
  elsif @spread > 10.0
802
883
  sprintf('%0i', value)
@@ -807,10 +888,26 @@ module Gruff
807
888
  end
808
889
 
809
890
  parts = label.split('.')
810
- parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{THOUSAND_SEPARATOR}")
891
+ parts[0] = parts[0].commify
811
892
  parts.join('.')
812
893
  end
813
894
 
895
+ def calculate_legend_label_widths_for_each_line(legend_labels, legend_square_width)
896
+ # May fix legend drawing problem at small sizes
897
+ label_widths = [[]] # Used to calculate line wrap
898
+ legend_labels.each do |label|
899
+ width = calculate_width(@legend_font_size, label)
900
+ label_width = width + legend_square_width * 2.7
901
+ label_widths.last.push label_width
902
+
903
+ if label_widths.last.sum > (@raw_columns * 0.9)
904
+ label_widths.push [label_widths.last.pop]
905
+ end
906
+ end
907
+
908
+ label_widths
909
+ end
910
+
814
911
  # Returns the height of the capital letter 'X' for the current font and
815
912
  # size.
816
913
  #
@@ -821,12 +918,13 @@ module Gruff
821
918
  metrics.height
822
919
  end
823
920
 
824
- # Returns the width of a string at this pointsize.
921
+ # Returns the width of a string at this point size.
825
922
  #
826
923
  # Not scaled since it deals with dimensions that the regular
827
924
  # scaling will handle.
828
925
  def calculate_width(font_size, text)
829
- return 0 if text.nil?
926
+ text = text.to_s
927
+ return 0 if text.empty?
830
928
 
831
929
  metrics = Renderer::Text.metrics(text, font_size)
832
930
  metrics.width
@@ -837,19 +935,10 @@ module Gruff
837
935
  # Try to use a number of horizontal lines that will come out even.
838
936
  #
839
937
  # TODO Do the same for larger numbers...100, 75, 50, 25
840
- if @marker_count.nil?
841
- (3..7).each do |lines|
842
- if @spread % lines == 0.0
843
- @marker_count = lines
844
- break
845
- end
846
- end
847
- @marker_count ||= 4
848
- end
849
- @increment = (@spread > 0 && @marker_count > 0) ? significant(@spread / @marker_count) : 1
938
+ @increment = (@spread > 0 && marker_count > 0) ? significant(@spread / marker_count) : 1
850
939
  else
851
940
  # TODO: Make this work for negative values
852
- @marker_count = (@spread / @y_axis_increment).to_i
941
+ self.marker_count = (@spread / @y_axis_increment).to_i
853
942
  @increment = @y_axis_increment
854
943
  end
855
944
  end