gruff 0.17.0 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f16153da348397448dc35f4d6435860b53040b14b0a7cbc3ca84bcaf9dd68b90
4
- data.tar.gz: 68efd965f5b00403281ff46cc377fae9503b3b4290f49b66e6ceb424d24b4d27
3
+ metadata.gz: 1b7a28fa80f8c598a927ce29242c2014a38cc21b1fc1fc43a80285239b448176
4
+ data.tar.gz: 13a94cca6581eebccafd48de9d48daa1acd4c085989cd996a6054fd63bfa8f8a
5
5
  SHA512:
6
- metadata.gz: c2436acee944766653a6497854eb89493fc67f940d846e7299bdf92e2a31c8f7e267f508dad3b8593d596d31a277702983a58b7a2282b00395c33c152c657407
7
- data.tar.gz: 7d75accebb94e9ae9362ae487265de84b7bbd6b6b90087c3ce5bd0f0e573d51d270f74bd04f3451d64aedba189fc09d5ef69b3a8c14785cb1b7d2c24b8581cc5
6
+ metadata.gz: 165988fc75b87fcd15f789ee9b178cbbe4ddc32cd0090f62cdcd36041806223b65c59406cd855038e0881ffb0b260df146aec74de7caff5ee0fc32df01447268
7
+ data.tar.gz: c5dcff59b2f8ab733fc99bafee1472ab0c014fbb106bec26fca167880b585cc9e61a6cc00b4e08aa02d39a2fe92d2291a7363a13ed16673a06898edcd15fb081
@@ -37,7 +37,7 @@ jobs:
37
37
  matrix:
38
38
  ruby-version: ['2.5', '2.6', '2.7', '3.0', '3.1']
39
39
  imagemagick-version:
40
- - { full: 7.1.0-35, major-minor: '7.0' }
40
+ - { full: 7.1.0-39, major-minor: '7.0' }
41
41
  name: Ruby ${{ matrix.ruby-version }}
42
42
  steps:
43
43
  - uses: actions/checkout@v3
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.18.0
4
+ - Add Gruff::Bubble (#604)
5
+ - Rename Gruff::BoxPlot to Gruff::Box (#603)
6
+ - Mark Gruff::Scatter#disable_significant_rounding_x_axis= as deprecated (#602)
7
+ - Mark Gruff::Scatter#x_label_margin= as deprecated (#601)
8
+ - Mark Gruff::Scatter#use_vertical_x_labels= as deprecated (#600)
9
+
3
10
  ## 0.17.0
4
11
  - Add Gruff::Base#label_rotation= method to rotate bottom label (#599)
5
12
  - Mark #label_stagger_height= as deprecated (#598)
data/README.md CHANGED
@@ -126,14 +126,18 @@ In progress!
126
126
 
127
127
  ![Histogram chart](https://raw.github.com/topfunky/gruff/master/test/expected/histogram.png)
128
128
 
129
- ### Box plot
129
+ ### Box chart
130
130
 
131
- ![Box plot](https://raw.github.com/topfunky/gruff/master/test/expected/box_plot.png)
131
+ ![Box chart](https://raw.github.com/topfunky/gruff/master/test/expected/box.png)
132
132
 
133
133
  ### Candlestick
134
134
 
135
135
  ![Candlestick](https://raw.github.com/topfunky/gruff/master/test/expected/candlestick.png)
136
136
 
137
+ ### Bubble chart
138
+
139
+ ![Bubble chart](https://raw.github.com/topfunky/gruff/master/test/expected/bubble.png)
140
+
137
141
  ## Documentation
138
142
 
139
143
  http://www.rubydoc.info/github/topfunky/gruff/frames
data/lib/gruff/area.rb CHANGED
@@ -30,7 +30,7 @@ private
30
30
  end
31
31
 
32
32
  def draw_graph
33
- x_increment = @graph_width / (column_count - 1)
33
+ x_increment = (@graph_width / (column_count - 1)).to_f
34
34
 
35
35
  store.norm_data.each do |data_row|
36
36
  next if data_row.points.empty?
data/lib/gruff/bar.rb CHANGED
@@ -114,7 +114,6 @@ private
114
114
  minimum_value: minimum_value, maximum_value: maximum_value, spread: @spread
115
115
  )
116
116
 
117
- group_spacing = @group_spacing * @scale
118
117
  group_left_x = @graph_left
119
118
 
120
119
  normalized_group_bars.each_with_index do |group_bars, group_index|
@@ -140,7 +139,7 @@ private
140
139
  label_center = group_left_x + ((right_x - group_left_x) / 2.0)
141
140
  draw_label(label_center, group_index)
142
141
 
143
- group_left_x = right_x + padding + group_spacing
142
+ group_left_x = right_x + padding + @group_spacing
144
143
  end
145
144
 
146
145
  # Draw the last label if requested
@@ -148,7 +147,7 @@ private
148
147
  end
149
148
 
150
149
  def calculate_spacing
151
- @scale * @group_spacing * (column_count - 1)
150
+ @group_spacing * (column_count - 1)
152
151
  end
153
152
 
154
153
  def proc_text_metrics
data/lib/gruff/base.rb CHANGED
@@ -607,8 +607,8 @@ module Gruff
607
607
  end
608
608
 
609
609
  def calculate_spread
610
- @spread = maximum_value - minimum_value
611
- @spread = @spread > 0 ? @spread : 1
610
+ @spread = maximum_value.to_f - minimum_value.to_f
611
+ @spread = @spread > 0 ? @spread : 1.0
612
612
  end
613
613
 
614
614
  def hide_title?
@@ -663,7 +663,7 @@ module Gruff
663
663
  def draw_line_markers
664
664
  return if @hide_line_markers
665
665
 
666
- increment_scaled = @graph_height / (@spread / @increment)
666
+ increment_scaled = (@graph_height / (@spread / @increment)).to_f
667
667
 
668
668
  # Draw horizontal line markers and annotate with numbers
669
669
  (0..marker_count).each do |index|
@@ -766,25 +766,14 @@ module Gruff
766
766
  text_renderer.add_to_render_queue(@raw_columns, 1.0, 0, @top_margin)
767
767
  end
768
768
 
769
- # Draws column labels below graph, centered over x_offset
770
- def draw_label(x_offset, index, gravity = Magick::NorthGravity, &block)
769
+ # Draws column labels below graph, centered over x
770
+ def draw_label(x, index, gravity = Magick::NorthGravity, &block)
771
771
  draw_unique_label(index) do
772
- y_offset = @graph_bottom
773
-
774
- if x_offset >= @graph_left && x_offset <= @graph_right
775
- width = calculate_width(@marker_font, @labels[index], rotation: @label_rotation)
776
- height = calculate_height(@marker_font, @labels[index], rotation: @label_rotation)
777
- case @label_rotation
778
- when 0
779
- x_offset
780
- when 0..45
781
- x_offset += (width / 2.0)
782
- when -45..0
783
- x_offset -= (width / 2.0)
784
- end
785
- y_offset += (height / 2.0) > LABEL_MARGIN ? (height / 2.0) : LABEL_MARGIN
772
+ if x >= @graph_left && x <= @graph_right
773
+ y = @graph_bottom
774
+ x_offset, y_offset = calculate_label_offset(@marker_font, @labels[index], LABEL_MARGIN, @label_rotation)
786
775
 
787
- draw_label_at(1.0, 1.0, x_offset, y_offset, @labels[index], gravity: gravity, rotation: @label_rotation)
776
+ draw_label_at(1.0, 1.0, x + x_offset, y + y_offset, @labels[index], gravity: gravity, rotation: @label_rotation)
788
777
  yield if block
789
778
  end
790
779
  end
@@ -831,10 +820,6 @@ module Gruff
831
820
  @theme_options = {}
832
821
  end
833
822
 
834
- def scale(value)
835
- value * @scale
836
- end
837
-
838
823
  def clip_value_if_greater_than(value, max_value)
839
824
  value > max_value ? max_value : value
840
825
  end
@@ -1123,14 +1108,32 @@ module Gruff
1123
1108
  # Try to use a number of horizontal lines that will come out even.
1124
1109
  #
1125
1110
  # TODO Do the same for larger numbers...100, 75, 50, 25
1126
- @increment = @spread > 0 && marker_count > 0 ? significant(@spread / marker_count) : 1
1111
+ @increment = @spread > 0 && marker_count > 0 ? significant(@spread / marker_count) : 1.0
1127
1112
  else
1128
1113
  # TODO: Make this work for negative values
1129
1114
  self.marker_count = (@spread / @y_axis_increment).to_i
1130
- @increment = @y_axis_increment
1115
+ @increment = @y_axis_increment.to_f
1131
1116
  end
1132
1117
  end
1133
1118
 
1119
+ def calculate_label_offset(font, label, margin, rotation)
1120
+ width = calculate_width(font, label, rotation: rotation)
1121
+ height = calculate_height(font, label, rotation: rotation)
1122
+ x_offset = begin
1123
+ case rotation
1124
+ when 0
1125
+ 0
1126
+ when 0..45
1127
+ width / 2.0
1128
+ when -45..0
1129
+ -(width / 2.0)
1130
+ end
1131
+ end
1132
+ y_offset = (height / 2.0) > margin ? (height / 2.0) : margin
1133
+
1134
+ [x_offset, y_offset]
1135
+ end
1136
+
1134
1137
  # Used for degree <=> radian conversions
1135
1138
  def deg2rad(angle)
1136
1139
  (angle * Math::PI) / 180.0
data/lib/gruff/bezier.rb CHANGED
@@ -22,7 +22,7 @@ class Gruff::Bezier < Gruff::Base
22
22
  private
23
23
 
24
24
  def draw_graph
25
- x_increment = @graph_width / (column_count - 1)
25
+ x_increment = (@graph_width / (column_count - 1)).to_f
26
26
 
27
27
  store.norm_data.each do |data_row|
28
28
  next if data_row[1].empty?
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #
4
- # Here's how to set up a Gruff::BoxPlot.
4
+ # Here's how to set up a Gruff::Box.
5
5
  #
6
- # g = Gruff::BoxPlot.new
6
+ # g = Gruff::Box.new
7
7
  # g.data "A", [2, 3, 5, 6, 8, 10, 11, 15, 17, 20, 28, 29, 33, 34, 45, 46, 49, 61]
8
8
  # g.data "B", [3, 4, 34, 35, 38, 39, 45, 60, 61, 69, 80, 130]
9
9
  # g.data "C", [4, 40, 41, 46, 57, 64, 77, 76, 79, 78, 99, 153]
10
10
  # g.write("box_plot.png")
11
11
  #
12
- class Gruff::BoxPlot < Gruff::Base
12
+ class Gruff::Box < Gruff::Base
13
13
  # Specifies the filling opacity in area graph. Default is +0.2+.
14
14
  attr_writer :fill_opacity
15
15
 
@@ -90,7 +90,7 @@ private
90
90
  end
91
91
 
92
92
  def normalized_boxes
93
- @normalized_boxes ||= store.norm_data.map { |data| Gruff::BoxPlot::BoxData.new(data.label, data.points, data.color) }
93
+ @normalized_boxes ||= store.norm_data.map { |data| Gruff::Box::BoxData.new(data.label, data.points, data.color) }
94
94
  end
95
95
 
96
96
  def column_count
@@ -98,7 +98,7 @@ private
98
98
  end
99
99
 
100
100
  def calculate_spacing
101
- @scale * (column_count - 1)
101
+ column_count - 1
102
102
  end
103
103
 
104
104
  # @private
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Here's how to set up a Gruff::Bubble.
5
+ #
6
+ # g = Gruff::Bubble.new
7
+ # g.title = 'Bubble plot'
8
+ # g.write('bubble.png')
9
+ #
10
+ class Gruff::Bubble < Gruff::Scatter
11
+ # Specifies the filling opacity in area graph. Default is +0.6+.
12
+ attr_writer :fill_opacity
13
+
14
+ # Specifies the stroke width in line. Default is +1.0+.
15
+ attr_writer :stroke_width
16
+
17
+ # The first parameter is the name of the dataset. The next two are the
18
+ # x and y axis data points contain in their own array in that respective
19
+ # order. The 4th argument represents sizes of points.
20
+ # The final parameter is the color.
21
+ #
22
+ # Can be called multiple times with different datasets for a multi-valued
23
+ # graph.
24
+ #
25
+ # If the color argument is nil, the next color from the default theme will
26
+ # be used.
27
+ #
28
+ # @note If you want to use a preset theme, you must set it before calling {#data}.
29
+ #
30
+ # @param name [String, Symbol] containing the name of the dataset.
31
+ # @param x_data_points [Array] An Array of x-axis data points.
32
+ # @param y_data_points [Array] An Array of y-axis data points.
33
+ # @param point_sizes [Array] An Array of sizes for points.
34
+ # @param color [String] The hex string for the color of the dataset. Defaults to nil.
35
+ #
36
+ # @raise [ArgumentError] Data points contain nil values.
37
+ # This error will get raised if either the x or y axis data points array
38
+ # contains a +nil+ value. The graph will not make an assumption
39
+ # as how to graph +nil+.
40
+ # @raise [ArgumentError] +x_data_points+ is empty.
41
+ # This error is raised when the array for the x-axis points are empty
42
+ # @raise [ArgumentError] +y_data_points+ is empty.
43
+ # This error is raised when the array for the y-axis points are empty.
44
+ # @raise [ArgumentError] +point_sizes+ is empty.
45
+ # This error is raised when the array for the point_sizes are empty
46
+ # @raise [ArgumentError] +x_data_points.length != y_data_points.length+.
47
+ # Error means that the x and y axis point arrays do not match in length.
48
+ # @raise [ArgumentError] +x_data_points.length != point_sizes.length+.
49
+ # Error means that the x and point_sizes arrays do not match in length.
50
+ #
51
+ # @example
52
+ # g = Gruff::Bubble.new
53
+ # g.title = "Bubble Graph"
54
+ # g.data :A, [-1, 19, -4, -23], [-35, 21, 23, -4], [4.5, 1.0, 2.1, 0.9]
55
+ #
56
+ def data(name, x_data_points = [], y_data_points = [], point_sizes = [], color = nil)
57
+ # make sure it's an array
58
+ x_data_points = Array(x_data_points)
59
+ y_data_points = Array(y_data_points)
60
+ point_sizes = Array(point_sizes)
61
+
62
+ raise ArgumentError, 'Data Points contain nil Value!' if x_data_points.include?(nil) || y_data_points.include?(nil)
63
+ raise ArgumentError, 'x_data_points is empty!' if x_data_points.empty?
64
+ raise ArgumentError, 'y_data_points is empty!' if y_data_points.empty?
65
+ raise ArgumentError, 'point_sizes is empty!' if point_sizes.empty?
66
+ raise ArgumentError, 'x_data_points.length != y_data_points.length!' if x_data_points.length != y_data_points.length
67
+ raise ArgumentError, 'x_data_points.length != point_sizes.length!' if x_data_points.length != point_sizes.length
68
+
69
+ store.add(name, x_data_points, y_data_points, point_sizes, color)
70
+ end
71
+
72
+ private
73
+
74
+ def initialize_store
75
+ @store = Gruff::Store.new(Gruff::Store::XYPointsizeData)
76
+ end
77
+
78
+ def initialize_attributes
79
+ super
80
+
81
+ @fill_opacity = 0.6
82
+ @stroke_width = 1.0
83
+ end
84
+
85
+ def draw_graph
86
+ store.norm_data.each do |data_row|
87
+ data_row.coordinate_and_pointsizes.each do |x_value, y_value, point_size|
88
+ next if y_value.nil? || x_value.nil?
89
+
90
+ new_x = @graph_left + (x_value * @graph_width)
91
+ new_y = @graph_bottom - (y_value * @graph_height)
92
+ diameter = @graph_width / (@marker_count * x_increment) * point_size.to_f
93
+
94
+ Gruff::Renderer::Circle.new(renderer, color: data_row.color, width: @stroke_width, opacity: @fill_opacity)
95
+ .render(new_x, new_y, new_x - (diameter / 2.0), new_y)
96
+ end
97
+ end
98
+ end
99
+ end
@@ -107,7 +107,7 @@ private
107
107
  end
108
108
 
109
109
  def calculate_spacing
110
- @scale * (column_count - 1)
110
+ column_count - 1
111
111
  end
112
112
 
113
113
  def show_marker_vertical_line?
@@ -40,7 +40,6 @@ private
40
40
  @minimum_bin = nil
41
41
  @maximum_bin = nil
42
42
  end
43
- private :initialize_attributes
44
43
 
45
44
  def setup_data
46
45
  @data.each do |(name, data_points, color)|
data/lib/gruff/line.rb CHANGED
@@ -81,6 +81,30 @@ class Gruff::Line < Gruff::Base
81
81
  @reference_lines[:baseline][:color] = new_value
82
82
  end
83
83
 
84
+ # Input the data in the graph.
85
+ #
86
+ # Parameters are an array where the first element is the name of the dataset
87
+ # and the value is an array of values to plot.
88
+ #
89
+ # Can be called multiple times with different datasets for a multi-valued
90
+ # graph.
91
+ #
92
+ # If the color argument is nil, the next color from the default theme will
93
+ # be used.
94
+ #
95
+ # @param name [String, Symbol] The name of the dataset.
96
+ # @param data_points [Array] The array of dataset.
97
+ # @param color [String] The color for drawing graph of dataset.
98
+ #
99
+ # @note
100
+ # If you want to use a preset theme, you must set it before calling {#data}.
101
+ #
102
+ # @example
103
+ # data("Bart S.", [95, 45, 78, 89, 88, 76], '#ffcc00')
104
+ def data(name, data_points = [], color = nil)
105
+ store.add(name, nil, data_points, color)
106
+ end
107
+
84
108
  # This method allows one to plot a dataset with both X and Y data.
85
109
  #
86
110
  # @overload dataxy(name, x_data_points = [], y_data_points = [], color = nil)
@@ -131,7 +155,7 @@ class Gruff::Line < Gruff::Base
131
155
  raise ArgumentError, 'x_data_points.length != y_data_points.length!' if x_data_points.length != y_data_points.length
132
156
 
133
157
  # call the existing data routine for the x/y data.
134
- store.add(name, y_data_points, color, x_data_points)
158
+ store.add(name, x_data_points, y_data_points, color)
135
159
  end
136
160
 
137
161
  private
@@ -177,6 +201,7 @@ private
177
201
  def draw_graph
178
202
  # Check to see if more than one datapoint was given. NaN can result otherwise.
179
203
  @x_increment = column_count > 1 ? @graph_width / (column_count - 1) : @graph_width
204
+ @x_increment = @x_increment.to_f
180
205
 
181
206
  @reference_lines.each_value do |curr_reference_line|
182
207
  draw_horizontal_reference_line(curr_reference_line) if curr_reference_line.key?(:norm_value)
@@ -194,7 +219,7 @@ private
194
219
  # use the old method: equally spaced points along the x-axis
195
220
  @graph_left + (@x_increment * index)
196
221
  else
197
- get_x_coord(x_data, @graph_width, @graph_left)
222
+ @graph_left + (x_data * @graph_width)
198
223
  end
199
224
  end
200
225
  draw_label_for_x_data(x_data, new_x, index)
@@ -287,10 +312,6 @@ private
287
312
  end
288
313
  end
289
314
 
290
- def get_x_coord(x_data_point, width, offset)
291
- (x_data_point * width) + offset
292
- end
293
-
294
315
  def contains_one_point_only?(data_row)
295
316
  data_row.y_points.compact.count == 1
296
317
  end
@@ -101,6 +101,10 @@ module Gruff
101
101
  end
102
102
  truncated_label + (truncated_label.length < label.to_s.length ? '...' : '')
103
103
  end
104
+
105
+ def scale(value)
106
+ value * @scale
107
+ end
104
108
  end
105
109
  end
106
110
  end
data/lib/gruff/pie.rb CHANGED
@@ -38,7 +38,7 @@ class Gruff::Pie < Gruff::Base
38
38
 
39
39
  # Can be used to make the pie start cutting slices at the top (-90.0)
40
40
  # or at another angle. Default is +-90.0+, which starts at 3 o'clock.
41
- # @deprecated Please use +start_degree+ attribute instead.
41
+ # @deprecated Please use {#start_degree=} instead.
42
42
  def zero_degree=(value)
43
43
  warn '#zero_degree= is deprecated. Please use `start_degree` attribute instead'
44
44
  @start_degree = value
@@ -3,15 +3,17 @@
3
3
  module Gruff
4
4
  # @private
5
5
  class Renderer::Circle
6
- def initialize(renderer, color:, width: 1.0)
6
+ def initialize(renderer, color:, width: 1.0, opacity: 1.0)
7
7
  @renderer = renderer
8
8
  @color = color
9
9
  @width = width
10
+ @opacity = opacity
10
11
  end
11
12
 
12
13
  def render(origin_x, origin_y, perim_x, perim_y)
13
14
  @renderer.draw.push
14
15
  @renderer.draw.fill(@color)
16
+ @renderer.draw.fill_opacity(@opacity)
15
17
  @renderer.draw.stroke(@color)
16
18
  @renderer.draw.stroke_width(@width)
17
19
  @renderer.draw.circle(origin_x, origin_y, perim_x, perim_y)
data/lib/gruff/scatter.rb CHANGED
@@ -24,24 +24,35 @@ class Gruff::Scatter < Gruff::Base
24
24
  attr_writer :circle_radius
25
25
  attr_writer :stroke_width
26
26
 
27
- # Allow disabling the significant rounding when labeling the X axis.
28
- # This is useful when working with a small range of high values (for example, a date range of months, while seconds as units).
29
- attr_writer :disable_significant_rounding_x_axis
30
-
31
27
  # Allow for vertical marker lines.
32
28
  attr_writer :show_vertical_markers
33
29
 
34
- # Allow using vertical labels in the X axis (and setting the label margin).
35
- attr_writer :x_label_margin
36
- attr_writer :use_vertical_x_labels
37
-
38
30
  # Allow enabling vertical lines. When you have a lot of data, they can work great.
39
- # @deprecated Please use +show_vertical_markers+ attribute instead.
31
+ # @deprecated Please use {#show_vertical_markers=} instead.
40
32
  def enable_vertical_line_markers=(value)
41
33
  warn '#enable_vertical_line_markers= is deprecated. Please use `show_vertical_markers` attribute instead'
42
34
  @show_vertical_markers = value
43
35
  end
44
36
 
37
+ # Allow using vertical labels in the X axis.
38
+ # @deprecated Please use {Gruff::Base#label_rotation=} instead.
39
+ def use_vertical_x_labels=(_value)
40
+ warn '#use_vertical_x_labels= is deprecated. It is no longer effective. Please use `#label_rotation=` instead'
41
+ end
42
+
43
+ # Allow using vertical labels in the X axis (and setting the label margin).
44
+ # @deprecated
45
+ def x_label_margin=(_value)
46
+ warn '#x_label_margin= is deprecated. It is no longer effective.'
47
+ end
48
+
49
+ # Allow disabling the significant rounding when labeling the X axis.
50
+ # This is useful when working with a small range of high values (for example, a date range of months, while seconds as units).
51
+ # @deprecated
52
+ def disable_significant_rounding_x_axis=(_value)
53
+ warn '#disable_significant_rounding_x_axis= is deprecated. It is no longer effective.'
54
+ end
55
+
45
56
  # The first parameter is the name of the dataset. The next two are the
46
57
  # x and y axis data points contain in their own array in that respective
47
58
  # order. The final parameter is the color.
@@ -55,11 +66,10 @@ class Gruff::Scatter < Gruff::Base
55
66
  # @note If you want to use a preset theme, you must set it before calling {#data}.
56
67
  #
57
68
  # @param name [String, Symbol] containing the name of the dataset.
58
- # @param x_data_points [Array] An Array of of x-axis data points.
59
- # @param y_data_points [Array] An Array of of y-axis data points.
69
+ # @param x_data_points [Array] An Array of x-axis data points.
70
+ # @param y_data_points [Array] An Array of y-axis data points.
60
71
  # @param color [String] The hex string for the color of the dataset. Defaults to nil.
61
72
  #
62
- #
63
73
  # @raise [ArgumentError] Data points contain nil values.
64
74
  # This error will get raised if either the x or y axis data points array
65
75
  # contains a +nil+ value. The graph will not make an assumption
@@ -88,7 +98,7 @@ class Gruff::Scatter < Gruff::Base
88
98
  raise ArgumentError, 'x_data_points.length != y_data_points.length!' if x_data_points.length != y_data_points.length
89
99
 
90
100
  # Call the existing data routine for the x/y axis data
91
- store.add(name, y_data_points, color, x_data_points)
101
+ store.add(name, x_data_points, y_data_points, color)
92
102
  end
93
103
 
94
104
  alias dataxy data
@@ -102,16 +112,11 @@ private
102
112
  def initialize_attributes
103
113
  super
104
114
 
105
- @baseline_x_color = @baseline_y_color = 'red'
106
- @baseline_x_value = @baseline_y_value = nil
107
115
  @circle_radius = nil
108
- @disable_significant_rounding_x_axis = false
109
116
  @show_vertical_markers = false
110
117
  @marker_x_count = nil
111
118
  @maximum_x_value = @minimum_x_value = nil
112
119
  @stroke_width = nil
113
- @use_vertical_x_labels = false
114
- @x_label_margin = nil
115
120
  end
116
121
 
117
122
  def setup_drawing
@@ -141,11 +146,11 @@ private
141
146
  data_row.coordinates.each do |x_value, y_value|
142
147
  next if y_value.nil? || x_value.nil?
143
148
 
144
- new_x = get_x_coord(x_value, @graph_width, @graph_left)
145
- new_y = @graph_top + (@graph_height - (y_value * @graph_height))
149
+ new_x = @graph_left + (x_value * @graph_width)
150
+ new_y = @graph_bottom - (y_value * @graph_height)
146
151
 
147
152
  # Reset each time to avoid thin-line errors
148
- stroke_width = @stroke_width || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 4), 5.0)
153
+ stroke_width = @stroke_width || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 4.0), 5.0)
149
154
  circle_radius = @circle_radius || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 2.5), 5.0)
150
155
  Gruff::Renderer::Circle.new(renderer, color: data_row.color, width: stroke_width).render(new_x, new_y, new_x - circle_radius, new_y)
151
156
  end
@@ -155,7 +160,7 @@ private
155
160
  def calculate_spread
156
161
  super
157
162
  @x_spread = @maximum_x_value.to_f - @minimum_x_value.to_f
158
- @x_spread = @x_spread > 0 ? @x_spread : 1
163
+ @x_spread = @x_spread > 0 ? @x_spread : 1.0
159
164
  end
160
165
 
161
166
  def normalize
@@ -169,32 +174,27 @@ private
169
174
  super
170
175
  return if @hide_line_markers
171
176
 
172
- increment_x_scaled = @graph_width / (@x_spread / x_increment)
177
+ increment_x_scaled = (@graph_width / (@x_spread / x_increment)).to_f
173
178
 
174
179
  # Draw vertical line markers and annotate with numbers
175
180
  (0..marker_x_count).each do |index|
176
181
  # TODO: Fix the vertical lines, and enable them by default. Not pretty when they don't match up with top y-axis line
177
182
  if @show_vertical_markers
178
- draw_marker_vertical_line(@graph_left + @graph_width - (index * increment_x_scaled))
183
+ draw_marker_vertical_line(@graph_left + (index * increment_x_scaled))
179
184
  end
180
185
 
181
186
  unless @hide_line_numbers
182
187
  marker_label = (BigDecimal(index.to_s) * BigDecimal(x_increment.to_s)) + BigDecimal(@minimum_x_value.to_s)
183
- y_offset = @graph_bottom + (@x_label_margin || LABEL_MARGIN)
184
- x_offset = get_x_coord(index, increment_x_scaled, @graph_left)
185
-
186
188
  label = x_axis_label(marker_label, x_increment)
187
- rotation = -90.0 if @use_vertical_x_labels
188
- text_renderer = Gruff::Renderer::Text.new(renderer, label, font: @marker_font, rotation: rotation)
189
- text_renderer.add_to_render_queue(1.0, 1.0, x_offset, y_offset)
189
+ x = @graph_left + (increment_x_scaled * index)
190
+ y = @graph_bottom
191
+ x_offset, y_offset = calculate_label_offset(@marker_font, label, LABEL_MARGIN, @label_rotation)
192
+
193
+ draw_label_at(1.0, 1.0, x + x_offset, y + y_offset, label, rotation: @label_rotation)
190
194
  end
191
195
  end
192
196
  end
193
197
 
194
- def get_x_coord(x_data_point, width, offset)
195
- (x_data_point * width) + offset
196
- end
197
-
198
198
  def marker_x_count
199
199
  # TODO: Do the same for larger numbers...100, 75, 50, 25
200
200
  @marker_x_count ||= begin
@@ -215,15 +215,10 @@ private
215
215
  def x_increment
216
216
  @x_increment ||= begin
217
217
  if @x_axis_increment.nil?
218
- increment = @x_spread > 0 ? (@x_spread / marker_x_count) : 1
219
- unless @disable_significant_rounding_x_axis
220
- increment = significant(increment)
221
- end
218
+ @x_spread > 0 ? significant(@x_spread / marker_x_count) : 1.0
222
219
  else
223
- increment = @x_axis_increment
220
+ @x_axis_increment.to_f
224
221
  end
225
-
226
- increment
227
222
  end
228
223
  end
229
224
  end
@@ -111,7 +111,6 @@ private
111
111
  minimum_value: minimum_value, maximum_value: maximum_value, spread: @spread
112
112
  )
113
113
 
114
- group_spacing = @group_spacing * @scale
115
114
  group_left_y = @graph_top
116
115
 
117
116
  normalized_group_bars.each_with_index do |group_bars, group_index|
@@ -137,7 +136,7 @@ private
137
136
  label_center = group_left_y + (bars_width / 2.0)
138
137
  draw_label(label_center, group_index)
139
138
 
140
- group_left_y = right_y + padding + group_spacing
139
+ group_left_y = right_y + padding + @group_spacing
141
140
  end
142
141
  end
143
142
 
@@ -176,7 +175,7 @@ private
176
175
  end
177
176
 
178
177
  def calculate_spacing
179
- @scale * @group_spacing * (column_count - 1)
178
+ @group_spacing * (column_count - 1)
180
179
  end
181
180
 
182
181
  def proc_text_metrics
@@ -33,7 +33,7 @@ private
33
33
  end
34
34
 
35
35
  def draw_graph
36
- x_increment = @graph_width / (column_count - 1)
36
+ x_increment = (@graph_width / (column_count - 1)).to_f
37
37
 
38
38
  height = Array.new(column_count, 0)
39
39
 
@@ -3,18 +3,17 @@
3
3
  module Gruff
4
4
  class Store
5
5
  # @private
6
- class XYData < Struct.new(:label, :y_points, :color, :x_points)
7
- def initialize(label, y_points, color, x_points = nil)
8
- x_points = Array(x_points) if x_points
9
- super(label.to_s, Array(y_points), color, x_points)
6
+ class XYData < Struct.new(:label, :x_points, :y_points, :color)
7
+ def initialize(label, x_points, y_points, color)
8
+ y_points = Array(y_points)
9
+ x_points = x_points ? Array(x_points) : Array.new(y_points.length)
10
+ raise ArgumentError, 'x_points.length != y_points.length!' if x_points.length != y_points.length
11
+
12
+ super(label.to_s, x_points, y_points, color)
10
13
  end
11
14
 
12
15
  alias points y_points
13
16
 
14
- def x_points
15
- self[:x_points] || Array.new(y_points.length)
16
- end
17
-
18
17
  def coordinates
19
18
  x_points.zip(y_points)
20
19
  end
@@ -53,7 +52,7 @@ module Gruff
53
52
  y.nil? ? nil : (y.to_f - minimum_y.to_f) / spread_y
54
53
  end
55
54
 
56
- self.class.new(label, norm_y_points, color, norm_x_points)
55
+ self.class.new(label, norm_x_points, norm_y_points, color)
57
56
  end
58
57
  end
59
58
  end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gruff
4
+ class Store
5
+ # @private
6
+ class XYPointsizeData < Struct.new(:label, :x_points, :y_points, :point_sizes, :color)
7
+ def initialize(label, x_points, y_points, point_sizes, color)
8
+ y_points = Array(y_points)
9
+ x_points = x_points ? Array(x_points) : Array.new(y_points.length)
10
+ raise ArgumentError, 'x_points.length != y_points.length!' if x_points.length != y_points.length
11
+ raise ArgumentError, 'x_points.length != point_sizes.length!' if x_points.length != point_sizes.length
12
+
13
+ super(label.to_s, x_points, y_points, point_sizes, color)
14
+ end
15
+
16
+ alias points y_points
17
+
18
+ def coordinate_and_pointsizes
19
+ x_points.zip(y_points, point_sizes)
20
+ end
21
+
22
+ def empty?
23
+ y_points.empty?
24
+ end
25
+
26
+ def columns
27
+ y_points.length
28
+ end
29
+
30
+ def min
31
+ y_points.compact.min
32
+ end
33
+ alias min_y min
34
+
35
+ def max
36
+ y_points.compact.max
37
+ end
38
+ alias max_y max
39
+
40
+ def min_x
41
+ x_points.compact.min
42
+ end
43
+
44
+ def max_x
45
+ x_points.compact.max
46
+ end
47
+
48
+ def normalize(minimum_x:, minimum_y:, spread_x:, spread_y:)
49
+ norm_x_points = x_points.map do |x|
50
+ x.nil? ? nil : (x.to_f - minimum_x.to_f) / spread_x
51
+ end
52
+ norm_y_points = y_points.map do |y|
53
+ y.nil? ? nil : (y.to_f - minimum_y.to_f) / spread_y
54
+ end
55
+
56
+ self.class.new(label, norm_x_points, norm_y_points, point_sizes, color)
57
+ end
58
+ end
59
+ end
60
+ end
data/lib/gruff/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Gruff
4
- VERSION = '0.17.0'
4
+ VERSION = '0.18.0'
5
5
  end
data/lib/gruff.rb CHANGED
@@ -26,7 +26,8 @@ module Gruff
26
26
  autoload :Area, Gruff.libpath('area')
27
27
  autoload :Bar, Gruff.libpath('bar')
28
28
  autoload :Bezier, Gruff.libpath('bezier')
29
- autoload :BoxPlot, Gruff.libpath('box_plot')
29
+ autoload :Box, Gruff.libpath('box')
30
+ autoload :Bubble, Gruff.libpath('bubble')
30
31
  autoload :Bullet, Gruff.libpath('bullet')
31
32
  autoload :Candlestick, Gruff.libpath('candlestick')
32
33
  autoload :Dot, Gruff.libpath('dot')
@@ -60,6 +61,7 @@ module Gruff
60
61
  class Store
61
62
  autoload :BasicData, Gruff.libpath('store/basic_data')
62
63
  autoload :XYData, Gruff.libpath('store/xy_data')
64
+ autoload :XYPointsizeData, Gruff.libpath('store/xy_pointsizes_data')
63
65
  end
64
66
 
65
67
  module Mini
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gruff
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.0
4
+ version: 0.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Geoffrey Grosenbach
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-06-12 00:00:00.000000000 Z
12
+ date: 2022-06-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rmagick
@@ -165,7 +165,8 @@ files:
165
165
  - lib/gruff/bar.rb
166
166
  - lib/gruff/base.rb
167
167
  - lib/gruff/bezier.rb
168
- - lib/gruff/box_plot.rb
168
+ - lib/gruff/box.rb
169
+ - lib/gruff/bubble.rb
169
170
  - lib/gruff/bullet.rb
170
171
  - lib/gruff/candlestick.rb
171
172
  - lib/gruff/dot.rb
@@ -204,6 +205,7 @@ files:
204
205
  - lib/gruff/store/basic_data.rb
205
206
  - lib/gruff/store/store.rb
206
207
  - lib/gruff/store/xy_data.rb
208
+ - lib/gruff/store/xy_pointsizes_data.rb
207
209
  - lib/gruff/themes.rb
208
210
  - lib/gruff/version.rb
209
211
  - rails_generators/gruff/gruff_generator.rb