gruff 0.16.0-java → 0.19.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.devcontainer/devcontainer.json +26 -0
- data/.github/workflows/ci.yml +9 -6
- data/.gitignore +1 -0
- data/.rubocop.yml +0 -6
- data/CHANGELOG.md +32 -0
- data/README.md +7 -3
- data/gruff.gemspec +2 -4
- data/lib/gruff/area.rb +3 -1
- data/lib/gruff/bar.rb +26 -24
- data/lib/gruff/base.rb +214 -93
- data/lib/gruff/bezier.rb +7 -8
- data/lib/gruff/{box_plot.rb → box.rb} +12 -6
- data/lib/gruff/bubble.rb +99 -0
- data/lib/gruff/candlestick.rb +22 -14
- data/lib/gruff/dot.rb +5 -6
- data/lib/gruff/helper/bar_conversion.rb +1 -5
- data/lib/gruff/helper/bar_mixin.rb +25 -0
- data/lib/gruff/helper/bar_value_label.rb +0 -22
- data/lib/gruff/helper/stacked_mixin.rb +16 -0
- data/lib/gruff/histogram.rb +8 -5
- data/lib/gruff/line.rb +47 -27
- data/lib/gruff/mini/bar.rb +1 -1
- data/lib/gruff/mini/legend.rb +13 -9
- data/lib/gruff/mini/pie.rb +2 -2
- data/lib/gruff/net.rb +26 -13
- data/lib/gruff/pie.rb +7 -2
- data/lib/gruff/renderer/bezier.rb +1 -1
- data/lib/gruff/renderer/circle.rb +5 -3
- data/lib/gruff/renderer/dash_line.rb +1 -1
- data/lib/gruff/renderer/dot.rb +26 -15
- data/lib/gruff/renderer/line.rb +1 -1
- data/lib/gruff/renderer/polygon.rb +1 -1
- data/lib/gruff/renderer/polyline.rb +4 -2
- data/lib/gruff/renderer/renderer.rb +0 -4
- data/lib/gruff/renderer/text.rb +7 -1
- data/lib/gruff/scatter.rb +52 -55
- data/lib/gruff/side_bar.rb +28 -24
- data/lib/gruff/side_stacked_bar.rb +36 -41
- data/lib/gruff/spider.rb +7 -2
- data/lib/gruff/stacked_area.rb +8 -3
- data/lib/gruff/stacked_bar.rb +48 -40
- data/lib/gruff/store/xy_data.rb +8 -9
- data/lib/gruff/store/xy_pointsizes_data.rb +60 -0
- data/lib/gruff/version.rb +1 -1
- data/lib/gruff.rb +3 -4
- metadata +9 -5
data/lib/gruff/bubble.rb
ADDED
@@ -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
|
data/lib/gruff/candlestick.rb
CHANGED
@@ -38,6 +38,16 @@ class Gruff::Candlestick < Gruff::Base
|
|
38
38
|
@spacing_factor = (1 - space_percent)
|
39
39
|
end
|
40
40
|
|
41
|
+
# The sort feature is not supported in this graph.
|
42
|
+
def sort=(_value)
|
43
|
+
raise 'Not support #sort= in Gruff::Candlestick'
|
44
|
+
end
|
45
|
+
|
46
|
+
# The sort feature is not supported in this graph.
|
47
|
+
def sorted_drawing=(_value)
|
48
|
+
raise 'Not support #sorted_drawing= in Gruff::Candlestick'
|
49
|
+
end
|
50
|
+
|
41
51
|
def data(low:, high:, open:, close:)
|
42
52
|
super('', [low, high, open, close])
|
43
53
|
end
|
@@ -53,7 +63,6 @@ private
|
|
53
63
|
@up_color = '#579773'
|
54
64
|
@down_color = '#eb5242'
|
55
65
|
|
56
|
-
@sort = false
|
57
66
|
@hide_legend = true
|
58
67
|
end
|
59
68
|
|
@@ -64,7 +73,7 @@ private
|
|
64
73
|
minimum_value: minimum_value, maximum_value: maximum_value, spread: @spread
|
65
74
|
)
|
66
75
|
|
67
|
-
width = (@graph_width - calculate_spacing) /
|
76
|
+
width = (@graph_width - calculate_spacing) / column_count
|
68
77
|
bar_width = width * @spacing_factor
|
69
78
|
padding = width - bar_width
|
70
79
|
|
@@ -74,16 +83,7 @@ private
|
|
74
83
|
center_x = (left_x + right_x) / 2.0
|
75
84
|
color = candlestick.close >= candlestick.open ? @up_color : @down_color
|
76
85
|
|
77
|
-
draw_label(center_x, index)
|
78
|
-
break if @hide_line_markers
|
79
|
-
break unless @show_vertical_markers
|
80
|
-
|
81
|
-
Gruff::Renderer::Line.new(renderer, color: @marker_color).render(center_x, @graph_bottom, center_x, @graph_top)
|
82
|
-
if @marker_shadow_color
|
83
|
-
Gruff::Renderer::Line.new(renderer, color: @marker_shadow_color)
|
84
|
-
.render(center_x + 1, @graph_bottom, center_x + 1, @graph_top)
|
85
|
-
end
|
86
|
-
end
|
86
|
+
draw_label(center_x, index) { draw_marker_vertical_line(center_x) if show_marker_vertical_line? }
|
87
87
|
|
88
88
|
open_y, = conversion.get_top_bottom_scaled(candlestick.open)
|
89
89
|
close_y, = conversion.get_top_bottom_scaled(candlestick.close)
|
@@ -99,11 +99,19 @@ private
|
|
99
99
|
end
|
100
100
|
|
101
101
|
def normalized_candlesticks
|
102
|
-
@
|
102
|
+
@normalized_candlesticks ||= store.norm_data.map { |data| Gruff::Candlestick::CandlestickData.new(*data.points) }
|
103
|
+
end
|
104
|
+
|
105
|
+
def column_count
|
106
|
+
normalized_candlesticks.size
|
103
107
|
end
|
104
108
|
|
105
109
|
def calculate_spacing
|
106
|
-
|
110
|
+
column_count - 1
|
111
|
+
end
|
112
|
+
|
113
|
+
def show_marker_vertical_line?
|
114
|
+
!@hide_line_markers && @show_vertical_markers
|
107
115
|
end
|
108
116
|
|
109
117
|
# @private
|
data/lib/gruff/dot.rb
CHANGED
@@ -17,6 +17,7 @@ class Gruff::Dot < Gruff::Base
|
|
17
17
|
def initialize(*)
|
18
18
|
super
|
19
19
|
@has_left_labels = true
|
20
|
+
@dot_style = 'circle'
|
20
21
|
end
|
21
22
|
|
22
23
|
private
|
@@ -28,7 +29,7 @@ private
|
|
28
29
|
|
29
30
|
items_width = @graph_height / column_count
|
30
31
|
item_width = items_width * spacing_factor / store.length
|
31
|
-
padding = (items_width * (1 - spacing_factor)) / 2
|
32
|
+
padding = (items_width * (1 - spacing_factor)) / 2.0
|
32
33
|
|
33
34
|
store.norm_data.each_with_index do |data_row, row_index|
|
34
35
|
data_row.points.each_with_index do |data_point, point_index|
|
@@ -39,7 +40,7 @@ private
|
|
39
40
|
Gruff::Renderer::Line.new(renderer, color: @marker_color).render(@graph_left, y_pos, @graph_left + @graph_width, y_pos)
|
40
41
|
end
|
41
42
|
|
42
|
-
Gruff::Renderer::
|
43
|
+
Gruff::Renderer::Dot.new(renderer, @dot_style, color: data_row.color).render(x_pos, y_pos, item_width / 3.0)
|
43
44
|
|
44
45
|
draw_label(y_pos, point_index)
|
45
46
|
end
|
@@ -53,9 +54,7 @@ private
|
|
53
54
|
(0..marker_count).each do |index|
|
54
55
|
marker_label = (BigDecimal(index.to_s) * BigDecimal(@increment.to_s)) + BigDecimal(minimum_value.to_s)
|
55
56
|
x = @graph_left + ((marker_label - minimum_value) * @graph_width / @spread)
|
56
|
-
|
57
|
-
Gruff::Renderer::Line.new(renderer, color: @marker_color).render(x, @graph_bottom, x, @graph_bottom + 5)
|
58
|
-
Gruff::Renderer::Line.new(renderer, color: @marker_shadow_color).render(x, @graph_bottom + 1, x, @graph_bottom + 6) if @marker_shadow_color
|
57
|
+
draw_marker_vertical_line(x, tick_mark_mode: true)
|
59
58
|
|
60
59
|
unless @hide_line_numbers
|
61
60
|
label = y_axis_label(marker_label, @increment)
|
@@ -70,7 +69,7 @@ private
|
|
70
69
|
|
71
70
|
def draw_label(y_offset, index)
|
72
71
|
draw_unique_label(index) do
|
73
|
-
draw_label_at(@graph_left - LABEL_MARGIN, 1.0, 0.0, y_offset, @labels[index], Magick::EastGravity)
|
72
|
+
draw_label_at(@graph_left - LABEL_MARGIN, 1.0, 0.0, y_offset, @labels[index], gravity: Magick::EastGravity)
|
74
73
|
end
|
75
74
|
end
|
76
75
|
end
|
@@ -13,8 +13,6 @@
|
|
13
13
|
#
|
14
14
|
# @private
|
15
15
|
class Gruff::BarConversion
|
16
|
-
attr_writer :mode
|
17
|
-
|
18
16
|
def initialize(top:, bottom:, minimum_value:, maximum_value:, spread:)
|
19
17
|
@graph_top = top
|
20
18
|
@graph_height = bottom - top
|
@@ -36,6 +34,7 @@ class Gruff::BarConversion
|
|
36
34
|
end
|
37
35
|
|
38
36
|
def get_top_bottom_scaled(data_point)
|
37
|
+
data_point = data_point.to_f
|
39
38
|
result = []
|
40
39
|
|
41
40
|
case @mode
|
@@ -52,9 +51,6 @@ class Gruff::BarConversion
|
|
52
51
|
val = data_point - (@minimum_value / @spread)
|
53
52
|
result[0] = @graph_top + (@graph_height * (1 - (val - @zero)))
|
54
53
|
result[1] = @graph_top + (@graph_height * (1 - @zero))
|
55
|
-
else
|
56
|
-
result[0] = 0.0
|
57
|
-
result[1] = 0.0
|
58
54
|
end
|
59
55
|
|
60
56
|
result
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @private
|
4
|
+
module Gruff::Base::BarMixin
|
5
|
+
def normalized_group_bars
|
6
|
+
@normalized_group_bars ||= begin
|
7
|
+
group_bars = Array.new(column_count) { [] }
|
8
|
+
store.norm_data.each_with_index do |data_row, row_index|
|
9
|
+
data_row.points.each_with_index do |data_point, point_index|
|
10
|
+
group_bars[point_index] << BarData.new(data_point, store.data[row_index].points[point_index], data_row.color)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Adjust the number of each group with empty bar
|
14
|
+
(data_row.points.size..(column_count - 1)).each do |index|
|
15
|
+
group_bars[index] << BarData.new(0, nil, data_row.color)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
group_bars
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# @private
|
23
|
+
class BarData < Struct.new(:point, :value, :color)
|
24
|
+
end
|
25
|
+
end
|
@@ -49,26 +49,4 @@ module Gruff::BarValueLabel
|
|
49
49
|
yield x, left_y, val, metrics.width, metrics.height
|
50
50
|
end
|
51
51
|
end
|
52
|
-
|
53
|
-
# @private
|
54
|
-
class StackedBar
|
55
|
-
def initialize
|
56
|
-
@bars = []
|
57
|
-
end
|
58
|
-
|
59
|
-
def add(bar, index)
|
60
|
-
bars = @bars[index] || []
|
61
|
-
bars << bar
|
62
|
-
@bars[index] = bars
|
63
|
-
end
|
64
|
-
|
65
|
-
def prepare_rendering(format, proc_text_metrics, &block)
|
66
|
-
@bars.each do |bars|
|
67
|
-
value = bars.sum(&:value)
|
68
|
-
bar = bars.last
|
69
|
-
bar_value_label = bar.class.new(bar.coordinate, value)
|
70
|
-
bar_value_label.prepare_rendering(format, proc_text_metrics, &block)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
52
|
end
|
@@ -21,4 +21,20 @@ module Gruff::Base::StackedMixin
|
|
21
21
|
|
22
22
|
raise "Can't handle negative values in stacked graph" if minimum_value < 0
|
23
23
|
end
|
24
|
+
|
25
|
+
def normalized_stacked_bars
|
26
|
+
@normalized_stacked_bars ||= begin
|
27
|
+
stacked_bars = Array.new(column_count) { [] }
|
28
|
+
store.norm_data.each_with_index do |data_row, row_index|
|
29
|
+
data_row.points.each_with_index do |data_point, point_index|
|
30
|
+
stacked_bars[point_index] << BarData.new(data_point, store.data[row_index].points[point_index], data_row.color)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
stacked_bars
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# @private
|
38
|
+
class BarData < Struct.new(:point, :value, :color)
|
39
|
+
end
|
24
40
|
end
|
data/lib/gruff/histogram.rb
CHANGED
@@ -40,15 +40,18 @@ 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)|
|
47
|
-
|
48
|
-
|
49
|
-
|
46
|
+
if data_points.empty?
|
47
|
+
store.add(name, [], color)
|
48
|
+
else
|
49
|
+
bins, freqs = HistogramArray.new(data_points).histogram(bin_width: @bin_width, min: @minimum_bin, max: @maximum_bin)
|
50
|
+
bins.each_with_index do |bin, index|
|
51
|
+
@labels[index] = bin
|
52
|
+
end
|
53
|
+
store.add(name, freqs, color)
|
50
54
|
end
|
51
|
-
store.add(name, freqs, color)
|
52
55
|
end
|
53
56
|
|
54
57
|
super
|
data/lib/gruff/line.rb
CHANGED
@@ -25,7 +25,7 @@ class Gruff::Line < Gruff::Base
|
|
25
25
|
attr_writer :line_width
|
26
26
|
attr_writer :dot_radius
|
27
27
|
|
28
|
-
# default is +'circle'+, other options include square
|
28
|
+
# default is +'circle'+, other options include +square+ and +diamond+.
|
29
29
|
attr_writer :dot_style
|
30
30
|
|
31
31
|
# Hide parts of the graph to fit more data points, or for a different appearance.
|
@@ -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
|
158
|
+
store.add(name, x_data_points, y_data_points, color)
|
135
159
|
end
|
136
160
|
|
137
161
|
private
|
@@ -177,50 +201,53 @@ 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)
|
183
208
|
draw_vertical_reference_line(curr_reference_line) if curr_reference_line.key?(:index)
|
184
209
|
end
|
185
210
|
|
186
|
-
store.norm_data.
|
187
|
-
|
211
|
+
stroke_width = @line_width || clip_value_if_greater_than(@columns / (store.norm_data.first.y_points.size * 4.0), 5.0)
|
212
|
+
circle_radius = @dot_radius || clip_value_if_greater_than(@columns / (store.norm_data.first.y_points.size * 2.5), 5.0)
|
188
213
|
|
189
|
-
|
214
|
+
store.norm_data.each do |data_row|
|
215
|
+
poly_points_group = [[]]
|
190
216
|
|
191
217
|
data_row.coordinates.each_with_index do |(x_data, y_data), index|
|
218
|
+
poly_points = poly_points_group.last
|
219
|
+
|
192
220
|
new_x = begin
|
193
221
|
if x_data.nil?
|
194
222
|
# use the old method: equally spaced points along the x-axis
|
195
223
|
@graph_left + (@x_increment * index)
|
196
224
|
else
|
197
|
-
|
225
|
+
@graph_left + (x_data * @graph_width)
|
198
226
|
end
|
199
227
|
end
|
200
228
|
draw_label_for_x_data(x_data, new_x, index)
|
201
229
|
|
202
|
-
unless y_data
|
203
|
-
|
230
|
+
unless y_data
|
231
|
+
# we can't draw a line for a null data point, we can still label the axis though.
|
232
|
+
# Split the polygonal line into separate groups of points for polyline.
|
233
|
+
poly_points_group << []
|
204
234
|
next
|
205
235
|
end
|
206
236
|
|
207
237
|
new_y = @graph_top + (@graph_height - (y_data * @graph_height))
|
208
238
|
|
209
|
-
|
210
|
-
|
211
|
-
circle_radius = @dot_radius || clip_value_if_greater_than(@columns / (store.norm_data.first.y_points.size * 2.5), 5.0)
|
212
|
-
|
213
|
-
if !@hide_lines && prev_x && prev_y
|
214
|
-
Gruff::Renderer::Line.new(renderer, color: data_row.color, width: stroke_width)
|
215
|
-
.render(prev_x, prev_y, new_x, new_y)
|
216
|
-
end
|
239
|
+
poly_points << new_x
|
240
|
+
poly_points << new_y
|
217
241
|
|
218
|
-
if
|
242
|
+
if contains_one_point_only?(data_row) || !@hide_dots
|
219
243
|
Gruff::Renderer::Dot.new(renderer, @dot_style, color: data_row.color, width: stroke_width).render(new_x, new_y, circle_radius)
|
220
244
|
end
|
245
|
+
end
|
221
246
|
|
222
|
-
|
223
|
-
|
247
|
+
unless @hide_lines
|
248
|
+
poly_points_group.each do |poly_points|
|
249
|
+
Gruff::Renderer::Polyline.new(renderer, color: data_row.color, width: stroke_width).render(poly_points) unless poly_points.empty?
|
250
|
+
end
|
224
251
|
end
|
225
252
|
end
|
226
253
|
end
|
@@ -273,10 +300,7 @@ private
|
|
273
300
|
return unless @show_vertical_markers
|
274
301
|
|
275
302
|
(0..@marker_x_count).each do |index|
|
276
|
-
|
277
|
-
|
278
|
-
Gruff::Renderer::Line.new(renderer, color: @marker_color).render(x, @graph_bottom, x, @graph_top)
|
279
|
-
Gruff::Renderer::Line.new(renderer, color: @marker_shadow_color).render(x + 1, @graph_bottom, x + 1, @graph_top) if @marker_shadow_color
|
303
|
+
draw_marker_vertical_line(@graph_left + @graph_width - (index * @graph_width / @marker_x_count))
|
280
304
|
end
|
281
305
|
end
|
282
306
|
|
@@ -290,10 +314,6 @@ private
|
|
290
314
|
end
|
291
315
|
end
|
292
316
|
|
293
|
-
def get_x_coord(x_data_point, width, offset)
|
294
|
-
(x_data_point * width) + offset
|
295
|
-
end
|
296
|
-
|
297
317
|
def contains_one_point_only?(data_row)
|
298
318
|
data_row.y_points.compact.count == 1
|
299
319
|
end
|
data/lib/gruff/mini/bar.rb
CHANGED
data/lib/gruff/mini/legend.rb
CHANGED
@@ -21,7 +21,7 @@ module Gruff
|
|
21
21
|
|
22
22
|
@legend_labels = store.data.map(&:label)
|
23
23
|
|
24
|
-
legend_height =
|
24
|
+
legend_height = scale((store.length * calculate_line_height) + @top_margin + @bottom_margin)
|
25
25
|
|
26
26
|
@original_rows = @raw_rows
|
27
27
|
@original_columns = @raw_columns
|
@@ -32,7 +32,7 @@ module Gruff
|
|
32
32
|
@columns += calculate_legend_width + @left_margin
|
33
33
|
else
|
34
34
|
font = @legend_font.dup
|
35
|
-
font.size =
|
35
|
+
font.size = scale(font.size)
|
36
36
|
@rows += store.length * calculate_caps_height(font) * 1.7
|
37
37
|
end
|
38
38
|
|
@@ -45,7 +45,7 @@ module Gruff
|
|
45
45
|
|
46
46
|
def calculate_legend_width
|
47
47
|
width = @legend_labels.map { |label| calculate_width(@legend_font, label) }.max
|
48
|
-
|
48
|
+
scale(width + (40 * 1.7))
|
49
49
|
end
|
50
50
|
|
51
51
|
##
|
@@ -69,9 +69,9 @@ module Gruff
|
|
69
69
|
|
70
70
|
@legend_labels.each_with_index do |legend_label, index|
|
71
71
|
# Draw label
|
72
|
-
label = truncate_legend_label(legend_label)
|
73
|
-
text_renderer = Gruff::Renderer::Text.new(renderer, label, font: @legend_font)
|
74
72
|
x_offset = current_x_offset + (legend_square_width * 1.7)
|
73
|
+
label = truncate_legend_label(legend_label, x_offset)
|
74
|
+
text_renderer = Gruff::Renderer::Text.new(renderer, label, font: @legend_font)
|
75
75
|
text_renderer.add_to_render_queue(@raw_columns, 1.0, x_offset, current_y_offset, Magick::WestGravity)
|
76
76
|
|
77
77
|
# Now draw box with color of this dataset
|
@@ -90,17 +90,21 @@ module Gruff
|
|
90
90
|
#
|
91
91
|
# Department of Hu...
|
92
92
|
|
93
|
-
def truncate_legend_label(label)
|
93
|
+
def truncate_legend_label(label, x_offset)
|
94
94
|
truncated_label = label.to_s
|
95
95
|
|
96
96
|
font = @legend_font.dup
|
97
|
-
font.size =
|
98
|
-
max_width = @columns -
|
99
|
-
while calculate_width(font, truncated_label) > max_width && truncated_label.length > 1
|
97
|
+
font.size = scale(font.size)
|
98
|
+
max_width = @columns - scale(x_offset) - @right_margin
|
99
|
+
while calculate_width(font, "#{truncated_label}...") > max_width && truncated_label.length > 1
|
100
100
|
truncated_label = truncated_label[0..truncated_label.length - 2]
|
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/mini/pie.rb
CHANGED
data/lib/gruff/net.rb
CHANGED
@@ -43,8 +43,25 @@ private
|
|
43
43
|
@marker_font.bold = true
|
44
44
|
end
|
45
45
|
|
46
|
+
def setup_drawing
|
47
|
+
@center_labels_over_point = false
|
48
|
+
super
|
49
|
+
end
|
50
|
+
|
51
|
+
def setup_graph_measurements
|
52
|
+
super
|
53
|
+
|
54
|
+
@radius = @graph_height / 2.0
|
55
|
+
@circle_radius = @dot_radius || clip_value_if_greater_than(@columns / (store.norm_data.first.points.size * 2.5), 5.0)
|
56
|
+
@stroke_width = @line_width || clip_value_if_greater_than(@columns / (store.norm_data.first.points.size * 4.0), 5.0)
|
57
|
+
@center_x = @graph_left + (@graph_width / 2.0)
|
58
|
+
@center_y = @graph_top + (@graph_height / 2.0) + 10
|
59
|
+
end
|
60
|
+
|
46
61
|
def draw_graph
|
47
62
|
store.norm_data.each do |data_row|
|
63
|
+
poly_points = []
|
64
|
+
|
48
65
|
data_row.points.each_with_index do |data_point, index|
|
49
66
|
next if data_point.nil?
|
50
67
|
|
@@ -52,6 +69,10 @@ private
|
|
52
69
|
point_distance = data_point * @radius
|
53
70
|
start_x = @center_x + (Math.sin(rad_pos) * point_distance)
|
54
71
|
start_y = @center_y - (Math.cos(rad_pos) * point_distance)
|
72
|
+
if poly_points.empty?
|
73
|
+
poly_points << start_x
|
74
|
+
poly_points << start_y
|
75
|
+
end
|
55
76
|
|
56
77
|
next_index = index + 1 < data_row.points.length ? index + 1 : 0
|
57
78
|
|
@@ -59,25 +80,17 @@ private
|
|
59
80
|
next_point_distance = data_row.points[next_index] * @radius
|
60
81
|
end_x = @center_x + (Math.sin(next_rad_pos) * next_point_distance)
|
61
82
|
end_y = @center_y - (Math.cos(next_rad_pos) * next_point_distance)
|
62
|
-
|
63
|
-
|
83
|
+
poly_points << end_x
|
84
|
+
poly_points << end_y
|
64
85
|
|
65
86
|
unless @hide_dots
|
66
87
|
circle_renderer = Gruff::Renderer::Circle.new(renderer, color: data_row.color, width: @stroke_width)
|
67
88
|
circle_renderer.render(start_x, start_y, start_x - @circle_radius, start_y)
|
68
89
|
end
|
69
90
|
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def setup_drawing
|
74
|
-
super
|
75
91
|
|
76
|
-
|
77
|
-
|
78
|
-
@stroke_width = @line_width || clip_value_if_greater_than(@columns / (store.norm_data.first.points.size * 4), 5.0)
|
79
|
-
@center_x = @graph_left + (@graph_width / 2.0)
|
80
|
-
@center_y = @graph_top + (@graph_height / 2.0) + 10
|
92
|
+
Gruff::Renderer::Polyline.new(renderer, color: data_row.color, width: @stroke_width).render(poly_points) unless poly_points.empty?
|
93
|
+
end
|
81
94
|
end
|
82
95
|
|
83
96
|
# the lines connecting in the center, with the first line vertical
|
@@ -102,6 +115,6 @@ private
|
|
102
115
|
x = x_offset + ((radius + LABEL_MARGIN) * Math.sin(deg2rad(angle)))
|
103
116
|
y = y_offset - ((radius + LABEL_MARGIN) * Math.cos(deg2rad(angle)))
|
104
117
|
|
105
|
-
draw_label_at(1.0, 1.0, x, y, amount, Magick::CenterGravity)
|
118
|
+
draw_label_at(1.0, 1.0, x, y, amount, gravity: Magick::CenterGravity)
|
106
119
|
end
|
107
120
|
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
|
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
|
@@ -61,6 +61,11 @@ private
|
|
61
61
|
@label_formatting = ->(value, percentage) { @show_values_as_labels ? value.to_s : "#{percentage}%" }
|
62
62
|
end
|
63
63
|
|
64
|
+
def setup_drawing
|
65
|
+
@center_labels_over_point = false
|
66
|
+
super
|
67
|
+
end
|
68
|
+
|
64
69
|
def draw_graph
|
65
70
|
slices.each do |slice|
|
66
71
|
if slice.value > 0
|
@@ -136,7 +141,7 @@ private
|
|
136
141
|
if slice.percentage >= @hide_labels_less_than
|
137
142
|
x, y = label_coordinates_for slice
|
138
143
|
label = @label_formatting.call(slice.value, slice.percentage)
|
139
|
-
draw_label_at(1.0, 1.0, x, y, label, Magick::CenterGravity)
|
144
|
+
draw_label_at(1.0, 1.0, x, y, label, gravity: Magick::CenterGravity)
|
140
145
|
end
|
141
146
|
end
|
142
147
|
|