gruff 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -17,9 +17,7 @@ require 'gruff/themes'
17
17
  class Gruff::Bullet < Gruff::Base
18
18
  def initialize(target_width = '400x40')
19
19
  if target_width.is_a?(String)
20
- geometric_width, geometric_height = target_width.split('x')
21
- @columns = geometric_width.to_f
22
- @rows = geometric_height.to_f
20
+ @columns, @rows = target_width.split('x').map(&:to_f)
23
21
  else
24
22
  @columns = target_width.to_f
25
23
  @rows = target_width.to_f / 5.0
@@ -27,12 +25,19 @@ class Gruff::Bullet < Gruff::Base
27
25
  @columns.freeze
28
26
  @rows.freeze
29
27
 
28
+ initialize_graph_scale
30
29
  initialize_ivars
30
+ initialize_store
31
31
 
32
- reset_themes
33
32
  self.theme = Gruff::Themes::GREYSCALE
33
+ end
34
+
35
+ def initialize_ivars
36
+ super
37
+
34
38
  @title_font_size = 20
35
39
  end
40
+ private :initialize_ivars
36
41
 
37
42
  def data(value, maximum_value, options = {})
38
43
  @value = value.to_f
@@ -55,7 +60,7 @@ class Gruff::Bullet < Gruff::Base
55
60
  margin = 30.0
56
61
  thickness = @raw_rows / 6.0
57
62
  right_margin = margin
58
- graph_left = (@title && (title_width * 1.3)) || margin
63
+ graph_left = [title_width * 1.3, margin].max
59
64
  graph_width = @raw_columns - graph_left - right_margin
60
65
  graph_height = thickness * 3.0
61
66
 
@@ -90,11 +95,11 @@ class Gruff::Bullet < Gruff::Base
90
95
  private
91
96
 
92
97
  def draw_title
93
- return unless @title
98
+ return if hide_title?
94
99
 
95
100
  font_height = calculate_caps_height(scale_fontsize(@title_font_size))
96
101
 
97
102
  text_renderer = Gruff::Renderer::Text.new(@title, font: @font, size: @title_font_size, color: @font_color)
98
- text_renderer.render(1.0, 1.0, font_height / 2, font_height / 2, Magick::NorthWestGravity)
103
+ text_renderer.add_to_render_queue(1.0, 1.0, font_height / 2, font_height / 2, Magick::NorthWestGravity)
99
104
  end
100
105
  end
@@ -54,37 +54,17 @@ protected
54
54
  def draw_line_markers
55
55
  return if @hide_line_markers
56
56
 
57
- # Draw horizontal line markers and annotate with numbers
58
- if @y_axis_increment
59
- increment = @y_axis_increment
60
- number_of_lines = (@spread / @y_axis_increment).to_i
61
- else
62
- # Try to use a number of horizontal lines that will come out even.
63
- #
64
- # TODO Do the same for larger numbers...100, 75, 50, 25
65
- if @marker_count.nil?
66
- (3..7).each do |lines|
67
- if @spread % lines == 0.0
68
- @marker_count = lines
69
- break
70
- end
71
- end
72
- @marker_count ||= 5
73
- end
74
- # TODO: Round maximum marker value to a round number like 100, 0.1, 0.5, etc.
75
- increment = (@spread > 0 && @marker_count > 0) ? significant(@spread / @marker_count) : 1
76
- number_of_lines = @marker_count
77
- end
78
-
79
- (0..number_of_lines).each do |index|
80
- marker_label = minimum_value + index * increment
57
+ (0..@marker_count).each do |index|
58
+ marker_label = minimum_value + index * @increment
81
59
  x = @graph_left + (marker_label - minimum_value) * @graph_width / @spread
82
- Gruff::Renderer::Line.new(color: @marker_color).render(x, @graph_bottom, x, @graph_bottom + 0.5 * LABEL_MARGIN)
60
+
61
+ line_renderer = Gruff::Renderer::Line.new(color: @marker_color, shadow_color: @marker_shadow_color)
62
+ line_renderer.render(x, @graph_bottom, x, @graph_bottom + 5)
83
63
 
84
64
  unless @hide_line_numbers
85
- label = label(marker_label, increment)
65
+ label = label(marker_label, @increment)
86
66
  text_renderer = Gruff::Renderer::Text.new(label, font: @font, size: @marker_font_size, color: @font_color)
87
- text_renderer.render(0, 0, x, @graph_bottom + (LABEL_MARGIN * 2.0), Magick::CenterGravity)
67
+ text_renderer.add_to_render_queue(0, 0, x, @graph_bottom + (LABEL_MARGIN * 1.5), Magick::CenterGravity)
88
68
  end
89
69
  end
90
70
  end
@@ -95,7 +75,7 @@ protected
95
75
  def draw_label(y_offset, index)
96
76
  draw_unique_label(index) do
97
77
  text_renderer = Gruff::Renderer::Text.new(@labels[index], font: @font, size: @marker_font_size, color: @font_color)
98
- text_renderer.render(@graph_left - LABEL_MARGIN * 2, 1.0, 0.0, y_offset, Magick::EastGravity)
78
+ text_renderer.add_to_render_queue(@graph_left - LABEL_MARGIN, 1.0, 0.0, y_offset, Magick::EastGravity)
99
79
  end
100
80
  end
101
81
  end
@@ -24,16 +24,16 @@ class Gruff::BarConversion
24
24
  result = []
25
25
 
26
26
  case @mode
27
- when 1 then # Case one
28
- # minimum value >= 0 ( only positive values )
27
+ when 1
28
+ # minimum value >= 0 ( only positive values )
29
29
  result[0] = @graph_top + @graph_height * (1 - data_point) + 1
30
30
  result[1] = @graph_top + @graph_height - 1
31
- when 2 then # Case two
32
- # only negative values
31
+ when 2
32
+ # only negative values
33
33
  result[0] = @graph_top + 1
34
34
  result[1] = @graph_top + @graph_height * (1 - data_point) - 1
35
- when 3 then # Case three
36
- # positive and negative values
35
+ when 3
36
+ # positive and negative values
37
37
  val = data_point - @minimum_value / @spread
38
38
  result[0] = @graph_top + @graph_height * (1 - (val - @zero)) + 1
39
39
  result[1] = @graph_top + @graph_height * (1 - @zero) - 1
@@ -15,6 +15,20 @@ require 'gruff/base'
15
15
  # g.write('histogram.png')
16
16
  #
17
17
  class Gruff::Histogram < Gruff::Bar
18
+ # Specifies interpolation between the min and max of the set. Default is +10+.
19
+ attr_writer :bin_width
20
+
21
+ # Specifies minimum value for bin.
22
+ attr_writer :minimum_bin
23
+
24
+ # Specifies maximum value for bin.
25
+ attr_writer :maximum_bin
26
+
27
+ def initialize(*)
28
+ super
29
+ @data = []
30
+ end
31
+
18
32
  def initialize_ivars
19
33
  super
20
34
  @bin_width = 10
@@ -23,33 +37,20 @@ class Gruff::Histogram < Gruff::Bar
23
37
  end
24
38
  private :initialize_ivars
25
39
 
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
40
+ def data(name, data_points = [], color = nil)
41
+ @data << [name, data_points, color]
45
42
  end
46
43
 
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
44
+ def draw
45
+ @data.each do |(name, data_points, color)|
46
+ bins, freqs = HistogramArray.new(data_points).histogram(bin_width: @bin_width, min: @minimum_bin, max: @maximum_bin)
47
+ bins.each_with_index do |bin, index|
48
+ @labels[index] = bin
49
+ end
50
+ store.add(name, freqs, color)
51
51
  end
52
- store.add(name, freqs, color)
52
+
53
+ super
53
54
  end
54
55
 
55
56
  # @private
@@ -12,32 +12,32 @@ require 'gruff/base'
12
12
  # g.write("line.png")
13
13
  #
14
14
  # There are also other options described below, such as {#baseline_value}, {#baseline_color},
15
- # {#hide_dots}, and {#hide_lines}.
15
+ # {#hide_dots=}, and {#hide_lines=}.
16
16
  #
17
17
  class Gruff::Line < Gruff::Base
18
18
  # Allow for reference lines ( which are like baseline ... just allowing for more & on both axes ).
19
19
  attr_accessor :reference_lines
20
- attr_accessor :reference_line_default_color
21
- attr_accessor :reference_line_default_width
20
+ attr_writer :reference_line_default_color
21
+ attr_writer :reference_line_default_width
22
22
 
23
23
  # Allow for vertical marker lines.
24
- attr_accessor :show_vertical_markers
24
+ attr_writer :show_vertical_markers
25
25
 
26
26
  # Dimensions of lines and dots; calculated based on dataset size if left unspecified.
27
- attr_accessor :line_width
28
- attr_accessor :dot_radius
27
+ attr_writer :line_width
28
+ attr_writer :dot_radius
29
29
 
30
30
  # default is +'circle'+, other options include square.
31
- attr_accessor :dot_style
31
+ attr_writer :dot_style
32
32
 
33
33
  # Hide parts of the graph to fit more datapoints, or for a different appearance.
34
- attr_accessor :hide_dots, :hide_lines
34
+ attr_writer :hide_dots, :hide_lines
35
35
 
36
36
  # accessors for support of xy data.
37
- attr_accessor :minimum_x_value
37
+ attr_writer :minimum_x_value
38
38
 
39
39
  # accessors for support of xy data.
40
- attr_accessor :maximum_x_value
40
+ attr_writer :maximum_x_value
41
41
 
42
42
  # Get the value if somebody has defined it.
43
43
  def baseline_value
@@ -69,7 +69,7 @@ class Gruff::Line < Gruff::Base
69
69
  # g = Gruff::Line.new(400, false) # 400px wide, no lines (for backwards compatibility)
70
70
  # g = Gruff::Line.new(false) # Defaults to 800px wide, no lines (for backwards compatibility)
71
71
  #
72
- # 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.
73
73
  def initialize(*args)
74
74
  raise ArgumentError, 'Wrong number of arguments' if args.length > 2
75
75
 
@@ -78,7 +78,15 @@ class Gruff::Line < Gruff::Base
78
78
  else
79
79
  super args.shift
80
80
  end
81
+ end
82
+
83
+ def initialize_store
84
+ @store = Gruff::Store.new(Gruff::Store::XYData)
85
+ end
86
+ private :initialize_store
81
87
 
88
+ def initialize_ivars
89
+ super
82
90
  @reference_lines = {}
83
91
  @reference_line_default_color = 'red'
84
92
  @reference_line_default_width = 5
@@ -87,12 +95,13 @@ class Gruff::Line < Gruff::Base
87
95
  @maximum_x_value = nil
88
96
  @minimum_x_value = nil
89
97
 
98
+ @line_width = nil
99
+ @dot_radius = nil
90
100
  @dot_style = 'circle'
91
101
 
92
102
  @show_vertical_markers = false
93
-
94
- @store = Gruff::Store.new(Gruff::Store::XYData)
95
103
  end
104
+ private :initialize_ivars
96
105
 
97
106
  # This method allows one to plot a dataset with both X and Y data.
98
107
  #
@@ -212,8 +221,8 @@ class Gruff::Line < Gruff::Base
212
221
  new_y = @graph_top + (@graph_height - y_data * @graph_height)
213
222
 
214
223
  # Reset each time to avoid thin-line errors
215
- stroke_width = line_width || clip_value_if_greater_than(@columns / (store.norm_data.first.y_points.size * 4), 5.0)
216
- circle_radius = dot_radius || clip_value_if_greater_than(@columns / (store.norm_data.first.y_points.size * 2.5), 5.0)
224
+ stroke_width = @line_width || clip_value_if_greater_than(@columns / (store.norm_data.first.y_points.size * 4), 5.0)
225
+ circle_radius = @dot_radius || clip_value_if_greater_than(@columns / (store.norm_data.first.y_points.size * 2.5), 5.0)
217
226
 
218
227
  if !@hide_lines && prev_x && prev_y
219
228
  Gruff::Renderer::Line.new(color: data_row.color, width: stroke_width)
@@ -67,7 +67,7 @@ module Gruff
67
67
  # Draw label
68
68
  label = truncate_legend_label(legend_label)
69
69
  text_renderer = Gruff::Renderer::Text.new(label, font: @font, size: @legend_font_size, color: @font_color)
70
- text_renderer.render(@raw_columns, 1.0, current_x_offset + (legend_square_width * 1.7), current_y_offset, Magick::WestGravity)
70
+ text_renderer.add_to_render_queue(@raw_columns, 1.0, current_x_offset + (legend_square_width * 1.7), current_y_offset, Magick::WestGravity)
71
71
 
72
72
  # Now draw box with color of this dataset
73
73
  rect_renderer = Gruff::Renderer::Rectangle.new(color: store.data[index].color)
@@ -26,16 +26,18 @@ require 'gruff/base'
26
26
  #
27
27
  class Gruff::Net < Gruff::Base
28
28
  # Hide parts of the graph to fit more datapoints, or for a different appearance.
29
- attr_accessor :hide_dots
29
+ attr_writer :hide_dots
30
30
 
31
31
  # Dimensions of lines and dots; calculated based on dataset size if left unspecified.
32
- attr_accessor :line_width
33
- attr_accessor :dot_radius
32
+ attr_writer :line_width
33
+ attr_writer :dot_radius
34
34
 
35
35
  def initialize_ivars
36
36
  super
37
37
 
38
38
  @hide_dots = false
39
+ @line_width = nil
40
+ @dot_radius = nil
39
41
  @hide_line_numbers = true
40
42
  @sorted_drawing = true
41
43
  end
@@ -46,9 +48,6 @@ class Gruff::Net < Gruff::Base
46
48
 
47
49
  return unless data_given?
48
50
 
49
- stroke_width = line_width || clip_value_if_greater_than(@columns / (store.norm_data.first.points.size * 4), 5.0)
50
- circle_radius = dot_radius || clip_value_if_greater_than(@columns / (store.norm_data.first.points.size * 2.5), 5.0)
51
-
52
51
  store.norm_data.each do |data_row|
53
52
  data_row.points.each_with_index do |data_point, index|
54
53
  next if data_point.nil?
@@ -65,9 +64,9 @@ class Gruff::Net < Gruff::Base
65
64
  end_x = @center_x + Math.sin(next_rad_pos) * next_point_distance
66
65
  end_y = @center_y - Math.cos(next_rad_pos) * next_point_distance
67
66
 
68
- Gruff::Renderer::Line.new(color: data_row.color, width: stroke_width).render(start_x, start_y, end_x, end_y)
67
+ Gruff::Renderer::Line.new(color: data_row.color, width: @stroke_width).render(start_x, start_y, end_x, end_y)
69
68
 
70
- Gruff::Renderer::Circle.new(color: data_row.color, width: stroke_width).render(start_x, start_y, start_x - circle_radius, start_y) unless @hide_dots
69
+ Gruff::Renderer::Circle.new(color: data_row.color, width: @stroke_width).render(start_x, start_y, start_x - @circle_radius, start_y) unless @hide_dots
71
70
  end
72
71
  end
73
72
 
@@ -80,8 +79,10 @@ private
80
79
  super
81
80
 
82
81
  @radius = @graph_height / 2.0
82
+ @circle_radius = @dot_radius || clip_value_if_greater_than(@columns / (store.norm_data.first.points.size * 2.5), 5.0)
83
+ @stroke_width = @line_width || clip_value_if_greater_than(@columns / (store.norm_data.first.points.size * 4), 5.0)
83
84
  @center_x = @graph_left + (@graph_width / 2.0)
84
- @center_y = @graph_top + (@graph_height / 2.0) - 10 # Move graph up a bit
85
+ @center_y = @graph_top + (@graph_height / 2.0) + 10
85
86
  end
86
87
 
87
88
  # the lines connecting in the center, with the first line vertical
@@ -95,20 +96,19 @@ private
95
96
  Gruff::Renderer::Line.new(color: @marker_color)
96
97
  .render(@center_x, @center_y, @center_x + Math.sin(rad_pos) * @radius, @center_y - Math.cos(rad_pos) * @radius)
97
98
 
98
- marker_label = labels[index] ? labels[index].to_s : '000'
99
- draw_label(@center_x, @center_y, rad_pos * 360 / (2 * Math::PI), @radius, marker_label)
99
+ marker_label = @labels[index] ? @labels[index].to_s : '000'
100
+ draw_label(@center_x, @center_y, rad_pos * 360 / (2 * Math::PI), @radius + @circle_radius, marker_label)
100
101
  end
101
102
  end
102
103
 
103
104
  def draw_label(center_x, center_y, angle, radius, amount)
104
- r_offset = 1.1
105
105
  x_offset = center_x # + 15 # The label points need to be tweaked slightly
106
106
  y_offset = center_y # + 0 # This one doesn't though
107
- x = x_offset + (radius * r_offset * Math.sin(deg2rad(angle)))
108
- y = y_offset - (radius * r_offset * Math.cos(deg2rad(angle)))
107
+ x = x_offset + (radius + LABEL_MARGIN) * Math.sin(deg2rad(angle))
108
+ y = y_offset - (radius + LABEL_MARGIN) * Math.cos(deg2rad(angle))
109
109
 
110
110
  # Draw label
111
111
  text_renderer = Gruff::Renderer::Text.new(amount, font: @font, size: 20, color: @marker_color, weight: Magick::BoldWeight)
112
- text_renderer.render(0, 0, x, y, Magick::CenterGravity)
112
+ text_renderer.add_to_render_queue(0, 0, x, y, Magick::CenterGravity)
113
113
  end
114
114
  end
@@ -7,22 +7,22 @@ require 'gruff/base'
7
7
  # Doesn't work yet.
8
8
  #
9
9
  class Gruff::PhotoBar < Gruff::Base
10
- # TODO
11
- #
12
- # define base and cap in yml
13
- # allow for image directory to be located elsewhere
14
- # more exact measurements for bar heights (go all the way to the bottom of the graph)
15
- # option to tile images instead of use a single image
16
- # drop base label a few px lower so photo bar graphs can have a base dropping over the lower marker line
17
- #
10
+ # TODO
11
+ #
12
+ # define base and cap in yml
13
+ # allow for image directory to be located elsewhere
14
+ # more exact measurements for bar heights (go all the way to the bottom of the graph)
15
+ # option to tile images instead of use a single image
16
+ # drop base label a few px lower so photo bar graphs can have a base dropping over the lower marker line
17
+ #
18
18
 
19
19
  # The name of a pre-packaged photo-based theme.
20
20
  attr_reader :theme
21
21
 
22
- # def initialize(target_width=800)
23
- # super
24
- # init_photo_bar_graphics()
25
- # end
22
+ # def initialize(target_width=800)
23
+ # super
24
+ # init_photo_bar_graphics()
25
+ # end
26
26
 
27
27
  def draw
28
28
  super
@@ -29,35 +29,28 @@ class Gruff::Pie < Gruff::Base
29
29
  attr_writer :text_offset_percentage
30
30
 
31
31
  ## Use values instead of percentages.
32
- attr_accessor :show_values_as_labels
32
+ attr_writer :show_values_as_labels
33
+
34
+ def initialize_store
35
+ @store = Gruff::Store.new(Gruff::Store::CustomData)
36
+ end
37
+ private :initialize_store
33
38
 
34
39
  def initialize_ivars
35
40
  super
36
-
41
+ @zero_degree = 0.0
42
+ @hide_labels_less_than = 0.0
43
+ @text_offset_percentage = DEFAULT_TEXT_OFFSET_PERCENTAGE
37
44
  @show_values_as_labels = false
38
-
39
- @store = Gruff::Store.new(Gruff::Store::CustomData)
40
45
  end
41
46
  private :initialize_ivars
42
47
 
43
- def zero_degree
44
- @zero_degree ||= 0.0
45
- end
46
-
47
- def hide_labels_less_than
48
- @hide_labels_less_than ||= 0.0
49
- end
50
-
51
- def text_offset_percentage
52
- @text_offset_percentage ||= DEFAULT_TEXT_OFFSET_PERCENTAGE
53
- end
54
-
55
48
  def options
56
49
  {
57
- zero_degree: zero_degree,
58
- hide_labels_less_than: hide_labels_less_than,
59
- text_offset_percentage: text_offset_percentage,
60
- show_values_as_labels: show_values_as_labels
50
+ zero_degree: @zero_degree,
51
+ hide_labels_less_than: @hide_labels_less_than,
52
+ text_offset_percentage: @text_offset_percentage,
53
+ show_values_as_labels: @show_values_as_labels
61
54
  }
62
55
  end
63
56
 
@@ -110,7 +103,7 @@ private
110
103
  # Spatial Value-Related Methods
111
104
 
112
105
  def chart_degrees
113
- @chart_degrees ||= zero_degree
106
+ @chart_degrees ||= @zero_degree
114
107
  end
115
108
 
116
109
  attr_reader :graph_height
@@ -146,17 +139,17 @@ private
146
139
  end
147
140
 
148
141
  def radius_offset
149
- radius + (radius * text_offset_percentage) + distance_from_center
142
+ radius + (radius * @text_offset_percentage) + distance_from_center
150
143
  end
151
144
 
152
145
  def ellipse_factor
153
- radius_offset * text_offset_percentage
146
+ radius_offset * @text_offset_percentage
154
147
  end
155
148
 
156
149
  # Label-Related Methods
157
150
 
158
151
  def process_label_for(slice)
159
- if slice.percentage >= hide_labels_less_than
152
+ if slice.percentage >= @hide_labels_less_than
160
153
  x, y = label_coordinates_for slice
161
154
 
162
155
  draw_label(x, y, slice.label)
@@ -181,7 +174,7 @@ private
181
174
 
182
175
  def draw_label(x, y, value)
183
176
  text_renderer = Gruff::Renderer::Text.new(value, font: @font, size: @marker_font_size, color: @font_color, weight: Magick::BoldWeight)
184
- text_renderer.render(0, 0, x, y, Magick::CenterGravity)
177
+ text_renderer.add_to_render_queue(0, 0, x, y, Magick::CenterGravity)
185
178
  end
186
179
 
187
180
  # Helper Classes