gruff 0.16.0 → 0.17.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +5 -2
- data/.gitignore +1 -0
- data/.rubocop.yml +0 -6
- data/CHANGELOG.md +19 -0
- data/gruff.gemspec +2 -3
- data/lib/gruff/area.rb +2 -0
- data/lib/gruff/bar.rb +26 -23
- data/lib/gruff/base.rb +198 -81
- data/lib/gruff/bezier.rb +2 -0
- data/lib/gruff/box_plot.rb +7 -1
- data/lib/gruff/candlestick.rb +21 -13
- data/lib/gruff/dot.rb +4 -5
- 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 -4
- data/lib/gruff/line.rb +2 -5
- data/lib/gruff/mini/legend.rb +9 -9
- data/lib/gruff/net.rb +16 -11
- data/lib/gruff/pie.rb +6 -1
- data/lib/gruff/renderer/dot.rb +25 -14
- data/lib/gruff/renderer/renderer.rb +0 -4
- data/lib/gruff/renderer/text.rb +7 -1
- data/lib/gruff/scatter.rb +20 -18
- data/lib/gruff/side_bar.rb +28 -23
- data/lib/gruff/side_stacked_bar.rb +36 -41
- data/lib/gruff/spider.rb +7 -2
- data/lib/gruff/stacked_area.rb +7 -2
- data/lib/gruff/stacked_bar.rb +46 -38
- data/lib/gruff/version.rb +1 -1
- data/lib/gruff.rb +0 -3
- metadata +10 -9
@@ -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
@@ -44,11 +44,15 @@ private
|
|
44
44
|
|
45
45
|
def setup_data
|
46
46
|
@data.each do |(name, data_points, color)|
|
47
|
-
|
48
|
-
|
49
|
-
|
47
|
+
if data_points.empty?
|
48
|
+
store.add(name, [], color)
|
49
|
+
else
|
50
|
+
bins, freqs = HistogramArray.new(data_points).histogram(bin_width: @bin_width, min: @minimum_bin, max: @maximum_bin)
|
51
|
+
bins.each_with_index do |bin, index|
|
52
|
+
@labels[index] = bin
|
53
|
+
end
|
54
|
+
store.add(name, freqs, color)
|
50
55
|
end
|
51
|
-
store.add(name, freqs, color)
|
52
56
|
end
|
53
57
|
|
54
58
|
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.
|
@@ -273,10 +273,7 @@ private
|
|
273
273
|
return unless @show_vertical_markers
|
274
274
|
|
275
275
|
(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
|
276
|
+
draw_marker_vertical_line(@graph_left + @graph_width - (index * @graph_width / @marker_x_count))
|
280
277
|
end
|
281
278
|
end
|
282
279
|
|
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,13 +90,13 @@ 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 ? '...' : '')
|
data/lib/gruff/net.rb
CHANGED
@@ -43,6 +43,21 @@ 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|
|
48
63
|
data_row.points.each_with_index do |data_point, index|
|
@@ -70,16 +85,6 @@ private
|
|
70
85
|
end
|
71
86
|
end
|
72
87
|
|
73
|
-
def setup_drawing
|
74
|
-
super
|
75
|
-
|
76
|
-
@radius = @graph_height / 2.0
|
77
|
-
@circle_radius = @dot_radius || clip_value_if_greater_than(@columns / (store.norm_data.first.points.size * 2.5), 5.0)
|
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
|
81
|
-
end
|
82
|
-
|
83
88
|
# the lines connecting in the center, with the first line vertical
|
84
89
|
def draw_line_markers
|
85
90
|
return if @hide_line_markers
|
@@ -102,6 +107,6 @@ private
|
|
102
107
|
x = x_offset + ((radius + LABEL_MARGIN) * Math.sin(deg2rad(angle)))
|
103
108
|
y = y_offset - ((radius + LABEL_MARGIN) * Math.cos(deg2rad(angle)))
|
104
109
|
|
105
|
-
draw_label_at(1.0, 1.0, x, y, amount, Magick::CenterGravity)
|
110
|
+
draw_label_at(1.0, 1.0, x, y, amount, gravity: Magick::CenterGravity)
|
106
111
|
end
|
107
112
|
end
|
data/lib/gruff/pie.rb
CHANGED
@@ -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
|
|
data/lib/gruff/renderer/dot.rb
CHANGED
@@ -11,31 +11,42 @@ module Gruff
|
|
11
11
|
@opacity = opacity
|
12
12
|
end
|
13
13
|
|
14
|
-
def render(new_x, new_y,
|
15
|
-
|
14
|
+
def render(new_x, new_y, radius)
|
15
|
+
@renderer.draw.push
|
16
16
|
@renderer.draw.stroke_width(@width)
|
17
17
|
@renderer.draw.stroke(@color)
|
18
18
|
@renderer.draw.fill(@color)
|
19
19
|
@renderer.draw.fill_opacity(@opacity)
|
20
|
-
|
21
|
-
|
20
|
+
case @style.to_sym
|
21
|
+
when :square
|
22
|
+
square(new_x, new_y, radius)
|
23
|
+
when :diamond
|
24
|
+
diamond(new_x, new_y, radius)
|
22
25
|
else
|
23
|
-
circle(new_x, new_y,
|
26
|
+
circle(new_x, new_y, radius)
|
24
27
|
end
|
25
|
-
|
28
|
+
@renderer.draw.pop
|
26
29
|
end
|
27
30
|
|
28
|
-
def circle(new_x, new_y,
|
29
|
-
@renderer.draw.circle(new_x, new_y, new_x -
|
31
|
+
def circle(new_x, new_y, radius)
|
32
|
+
@renderer.draw.circle(new_x, new_y, new_x - radius, new_y)
|
30
33
|
end
|
31
34
|
|
32
|
-
def square(new_x, new_y,
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
corner4 = new_y + offset
|
35
|
+
def square(new_x, new_y, radius)
|
36
|
+
corner1 = new_x - radius
|
37
|
+
corner2 = new_y - radius
|
38
|
+
corner3 = new_x + radius
|
39
|
+
corner4 = new_y + radius
|
38
40
|
@renderer.draw.rectangle(corner1, corner2, corner3, corner4)
|
39
41
|
end
|
42
|
+
|
43
|
+
def diamond(new_x, new_y, radius)
|
44
|
+
polygon = []
|
45
|
+
polygon += [new_x - radius, new_y]
|
46
|
+
polygon += [new_x, new_y + radius]
|
47
|
+
polygon += [new_x + radius, new_y]
|
48
|
+
polygon += [new_x, new_y - radius]
|
49
|
+
@renderer.draw.polygon(*polygon)
|
50
|
+
end
|
40
51
|
end
|
41
52
|
end
|
data/lib/gruff/renderer/text.rb
CHANGED
@@ -25,6 +25,7 @@ module Gruff
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def render(width, height, x, y, gravity = Magick::NorthGravity)
|
28
|
+
@renderer.draw.push
|
28
29
|
@renderer.draw.rotation = @rotation if @rotation
|
29
30
|
@renderer.draw.fill = @font.color
|
30
31
|
@renderer.draw.stroke = 'transparent'
|
@@ -37,9 +38,11 @@ module Gruff
|
|
37
38
|
x, y,
|
38
39
|
@text, @renderer.scale)
|
39
40
|
@renderer.draw.rotation = -@rotation if @rotation
|
41
|
+
@renderer.draw.pop
|
40
42
|
end
|
41
43
|
|
42
44
|
def metrics
|
45
|
+
@renderer.draw.push
|
43
46
|
@renderer.draw.font = @font.file_path
|
44
47
|
@renderer.draw.font_weight = @font.weight
|
45
48
|
@renderer.draw.pointsize = @font.size
|
@@ -50,7 +53,10 @@ module Gruff
|
|
50
53
|
# So, in here, it just escape % in order to avoid SEGV.
|
51
54
|
text = @text.to_s.gsub(/(%+)/) { ('%' * Regexp.last_match(1).size * 2).to_s }
|
52
55
|
|
53
|
-
@renderer.draw.get_type_metrics(@renderer.image, text)
|
56
|
+
metrics = @renderer.draw.get_type_metrics(@renderer.image, text)
|
57
|
+
@renderer.draw.pop
|
58
|
+
|
59
|
+
metrics
|
54
60
|
end
|
55
61
|
end
|
56
62
|
end
|
data/lib/gruff/scatter.rb
CHANGED
@@ -114,20 +114,9 @@ private
|
|
114
114
|
@x_label_margin = nil
|
115
115
|
end
|
116
116
|
|
117
|
-
def
|
118
|
-
|
119
|
-
|
120
|
-
next if y_value.nil? || x_value.nil?
|
121
|
-
|
122
|
-
new_x = get_x_coord(x_value, @graph_width, @graph_left)
|
123
|
-
new_y = @graph_top + (@graph_height - (y_value * @graph_height))
|
124
|
-
|
125
|
-
# Reset each time to avoid thin-line errors
|
126
|
-
stroke_width = @stroke_width || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 4), 5.0)
|
127
|
-
circle_radius = @circle_radius || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 2.5), 5.0)
|
128
|
-
Gruff::Renderer::Circle.new(renderer, color: data_row.color, width: stroke_width).render(new_x, new_y, new_x - circle_radius, new_y)
|
129
|
-
end
|
130
|
-
end
|
117
|
+
def setup_drawing
|
118
|
+
@center_labels_over_point = false
|
119
|
+
super
|
131
120
|
end
|
132
121
|
|
133
122
|
def setup_data
|
@@ -147,6 +136,22 @@ private
|
|
147
136
|
super
|
148
137
|
end
|
149
138
|
|
139
|
+
def draw_graph
|
140
|
+
store.norm_data.each do |data_row|
|
141
|
+
data_row.coordinates.each do |x_value, y_value|
|
142
|
+
next if y_value.nil? || x_value.nil?
|
143
|
+
|
144
|
+
new_x = get_x_coord(x_value, @graph_width, @graph_left)
|
145
|
+
new_y = @graph_top + (@graph_height - (y_value * @graph_height))
|
146
|
+
|
147
|
+
# 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)
|
149
|
+
circle_radius = @circle_radius || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 2.5), 5.0)
|
150
|
+
Gruff::Renderer::Circle.new(renderer, color: data_row.color, width: stroke_width).render(new_x, new_y, new_x - circle_radius, new_y)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
150
155
|
def calculate_spread
|
151
156
|
super
|
152
157
|
@x_spread = @maximum_x_value.to_f - @minimum_x_value.to_f
|
@@ -170,10 +175,7 @@ private
|
|
170
175
|
(0..marker_x_count).each do |index|
|
171
176
|
# TODO: Fix the vertical lines, and enable them by default. Not pretty when they don't match up with top y-axis line
|
172
177
|
if @show_vertical_markers
|
173
|
-
|
174
|
-
|
175
|
-
Gruff::Renderer::Line.new(renderer, color: @marker_color).render(x, @graph_top, x, @graph_bottom)
|
176
|
-
Gruff::Renderer::Line.new(renderer, color: @marker_shadow_color).render(x, @graph_top + 1, x, @graph_bottom + 1) if @marker_shadow_color
|
178
|
+
draw_marker_vertical_line(@graph_left + @graph_width - (index * increment_x_scaled))
|
177
179
|
end
|
178
180
|
|
179
181
|
unless @hide_line_numbers
|
data/lib/gruff/side_bar.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'helper/bar_mixin'
|
4
|
+
|
3
5
|
# Graph with individual horizontal bars instead of vertical bars.
|
4
6
|
#
|
5
7
|
# Here's how to set up a Gruff::SideBar.
|
@@ -19,6 +21,8 @@
|
|
19
21
|
# g.write('sidebar.png')
|
20
22
|
#
|
21
23
|
class Gruff::SideBar < Gruff::Base
|
24
|
+
include BarMixin
|
25
|
+
|
22
26
|
# Spacing factor applied between bars.
|
23
27
|
attr_writer :bar_spacing
|
24
28
|
|
@@ -79,8 +83,6 @@ private
|
|
79
83
|
return if @hide_line_markers
|
80
84
|
|
81
85
|
if @show_labels_for_bar_values
|
82
|
-
proc_text_metrics = ->(text) { text_metrics(@marker_font, text) }
|
83
|
-
|
84
86
|
if maximum_value >= 0
|
85
87
|
_, metrics = Gruff::BarValueLabel.metrics(maximum_value, @label_formatting, proc_text_metrics)
|
86
88
|
@graph_right -= metrics.width
|
@@ -109,32 +111,33 @@ private
|
|
109
111
|
minimum_value: minimum_value, maximum_value: maximum_value, spread: @spread
|
110
112
|
)
|
111
113
|
|
112
|
-
|
114
|
+
group_spacing = @group_spacing * @scale
|
115
|
+
group_left_y = @graph_top
|
113
116
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
left_y = @graph_top + (bars_width * point_index) + (bar_width * row_index) + padding + group_spacing
|
117
|
+
normalized_group_bars.each_with_index do |group_bars, group_index|
|
118
|
+
right_y = 0
|
119
|
+
group_bars.each_with_index do |bar, index|
|
120
|
+
left_y = group_left_y + (bar_width * index) + padding
|
119
121
|
right_y = left_y + (bar_width * @bar_spacing)
|
120
122
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
# Calculate center based on bar_width and current row
|
127
|
-
label_center = left_y + (bars_width / 2.0)
|
123
|
+
bottom_x, top_x = conversion.get_top_bottom_scaled(bar.point).sort
|
124
|
+
if bar.point != 0
|
125
|
+
rect_renderer = Gruff::Renderer::Rectangle.new(renderer, color: bar.color)
|
126
|
+
rect_renderer.render(bottom_x + AXIS_MARGIN, left_y, top_x, right_y)
|
127
|
+
end
|
128
128
|
|
129
|
-
|
130
|
-
|
131
|
-
if @show_labels_for_bar_values
|
132
|
-
bar_value_label = Gruff::BarValueLabel::SideBar.new([left_x, left_y, right_x, right_y], store.data[row_index].points[point_index])
|
129
|
+
if @show_labels_for_bar_values && bar.value
|
130
|
+
bar_value_label = Gruff::BarValueLabel::SideBar.new([bottom_x, left_y, top_x, right_y], bar.value)
|
133
131
|
bar_value_label.prepare_rendering(@label_formatting, proc_text_metrics) do |x, y, text, text_width, _text_height|
|
134
132
|
draw_value_label(text_width, bar_width * @bar_spacing, x, y, text)
|
135
133
|
end
|
136
134
|
end
|
137
135
|
end
|
136
|
+
|
137
|
+
label_center = group_left_y + (bars_width / 2.0)
|
138
|
+
draw_label(label_center, group_index)
|
139
|
+
|
140
|
+
group_left_y = right_y + padding + group_spacing
|
138
141
|
end
|
139
142
|
end
|
140
143
|
|
@@ -151,9 +154,7 @@ private
|
|
151
154
|
(0..number_of_lines).each do |index|
|
152
155
|
line_diff = (@graph_right - @graph_left) / number_of_lines
|
153
156
|
x = @graph_right - (line_diff * index) - 1
|
154
|
-
|
155
|
-
Gruff::Renderer::Line.new(renderer, color: @marker_color).render(x, @graph_bottom, x, @graph_top)
|
156
|
-
Gruff::Renderer::Line.new(renderer, color: @marker_shadow_color).render(x, @graph_bottom + 1, x, @graph_top + 1) if @marker_shadow_color
|
157
|
+
draw_marker_vertical_line(x)
|
157
158
|
|
158
159
|
unless @hide_line_numbers
|
159
160
|
diff = index - number_of_lines
|
@@ -170,11 +171,15 @@ private
|
|
170
171
|
|
171
172
|
def draw_label(y_offset, index)
|
172
173
|
draw_unique_label(index) do
|
173
|
-
draw_label_at(@graph_left - LABEL_MARGIN, 1.0, 0.0, y_offset, @labels[index], Magick::EastGravity)
|
174
|
+
draw_label_at(@graph_left - LABEL_MARGIN, 1.0, 0.0, y_offset, @labels[index], gravity: Magick::EastGravity)
|
174
175
|
end
|
175
176
|
end
|
176
177
|
|
177
178
|
def calculate_spacing
|
178
179
|
@scale * @group_spacing * (column_count - 1)
|
179
180
|
end
|
181
|
+
|
182
|
+
def proc_text_metrics
|
183
|
+
->(text) { text_metrics(@marker_font, text) }
|
184
|
+
end
|
180
185
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'helper/stacked_mixin'
|
4
|
+
|
3
5
|
#
|
4
6
|
# New gruff graph type added to enable sideways stacking bar charts
|
5
7
|
# (basically looks like a x/y flip of a standard stacking bar chart)
|
@@ -66,50 +68,43 @@ private
|
|
66
68
|
#
|
67
69
|
# Columns sit stacked.
|
68
70
|
bar_width = @graph_height / column_count
|
69
|
-
height = Array.new(column_count, 0)
|
70
|
-
length = Array.new(column_count, @graph_left)
|
71
71
|
padding = (bar_width * (1 - @bar_spacing)) / 2
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
rect_renderer = Gruff::Renderer::Rectangle.new(renderer, color: data_row.color)
|
99
|
-
rect_renderer.render(left_x, left_y, right_x, right_y)
|
100
|
-
# Calculate center based on bar_width and current row
|
101
|
-
end
|
102
|
-
# we still need to draw the labels
|
103
|
-
# Calculate center based on bar_width and current row
|
104
|
-
label_center = left_y + (bar_width / 2.0)
|
105
|
-
draw_label(label_center, point_index)
|
72
|
+
|
73
|
+
# Setup the BarConversion Object
|
74
|
+
conversion = Gruff::BarConversion.new(
|
75
|
+
top: @graph_right, bottom: @graph_left,
|
76
|
+
minimum_value: minimum_value, maximum_value: maximum_value, spread: @spread
|
77
|
+
)
|
78
|
+
|
79
|
+
proc_text_metrics = ->(text) { text_metrics(@marker_font, text) }
|
80
|
+
|
81
|
+
normalized_stacked_bars.each_with_index do |stacked_bars, stacked_index|
|
82
|
+
total = 0
|
83
|
+
left_y = @graph_top + (bar_width * stacked_index) + padding
|
84
|
+
right_y = left_y + (bar_width * @bar_spacing)
|
85
|
+
|
86
|
+
top_x = 0
|
87
|
+
stacked_bars.each do |bar|
|
88
|
+
next if bar.point == 0
|
89
|
+
|
90
|
+
bottom_x, = conversion.get_top_bottom_scaled(total)
|
91
|
+
bottom_x += @segment_spacing
|
92
|
+
top_x, = conversion.get_top_bottom_scaled(total + bar.point)
|
93
|
+
|
94
|
+
rect_renderer = Gruff::Renderer::Rectangle.new(renderer, color: bar.color)
|
95
|
+
rect_renderer.render(bottom_x, left_y, top_x, right_y)
|
96
|
+
|
97
|
+
total += bar.point
|
106
98
|
end
|
107
|
-
end
|
108
99
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
100
|
+
label_center = left_y + (bar_width / 2.0)
|
101
|
+
draw_label(label_center, stacked_index)
|
102
|
+
|
103
|
+
if @show_labels_for_bar_values
|
104
|
+
bar_value_label = Gruff::BarValueLabel::SideBar.new([@graph_left, left_y, top_x, right_y], stacked_bars.sum(&:value))
|
105
|
+
bar_value_label.prepare_rendering(@label_formatting, proc_text_metrics) do |x, y, text, text_width, _text_height|
|
106
|
+
draw_value_label(text_width, bar_width * @bar_spacing, x, y, text)
|
107
|
+
end
|
113
108
|
end
|
114
109
|
end
|
115
110
|
end
|
data/lib/gruff/spider.rb
CHANGED
@@ -46,6 +46,11 @@ private
|
|
46
46
|
@hide_line_markers.freeze
|
47
47
|
end
|
48
48
|
|
49
|
+
def setup_drawing
|
50
|
+
@center_labels_over_point = false
|
51
|
+
super
|
52
|
+
end
|
53
|
+
|
49
54
|
def setup_graph_measurements
|
50
55
|
super
|
51
56
|
|
@@ -82,7 +87,7 @@ private
|
|
82
87
|
end
|
83
88
|
|
84
89
|
def normalize_points(value)
|
85
|
-
value * @unit_length
|
90
|
+
value.to_f * @unit_length
|
86
91
|
end
|
87
92
|
|
88
93
|
def draw_label(center_x, center_y, angle, radius, amount)
|
@@ -107,7 +112,7 @@ private
|
|
107
112
|
x = x_offset + ((radius + r_offset) * Math.cos(angle))
|
108
113
|
y = y_offset + ((radius + r_offset) * Math.sin(angle))
|
109
114
|
|
110
|
-
draw_label_at(metrics.width, metrics.height, x, y, amount, Magick::CenterGravity)
|
115
|
+
draw_label_at(metrics.width, metrics.height, x, y, amount, gravity: Magick::CenterGravity)
|
111
116
|
end
|
112
117
|
|
113
118
|
def draw_axes(center_x, center_y, radius, additive_angle, line_color = nil)
|
data/lib/gruff/stacked_area.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'helper/stacked_mixin'
|
4
|
+
|
3
5
|
#
|
4
6
|
# Here's how to set up a Gruff::StackedArea.
|
5
7
|
#
|
@@ -35,9 +37,10 @@ private
|
|
35
37
|
|
36
38
|
height = Array.new(column_count, 0)
|
37
39
|
|
38
|
-
|
40
|
+
prev_data_points = nil
|
39
41
|
store.norm_data.each do |data_row|
|
40
|
-
|
42
|
+
next if data_row.points.empty?
|
43
|
+
|
41
44
|
data_points = []
|
42
45
|
|
43
46
|
data_row.points.each_with_index do |data_point, index|
|
@@ -69,6 +72,8 @@ private
|
|
69
72
|
poly_points << data_points[1]
|
70
73
|
|
71
74
|
Gruff::Renderer::Polygon.new(renderer, color: data_row.color).render(poly_points)
|
75
|
+
|
76
|
+
prev_data_points = data_points
|
72
77
|
end
|
73
78
|
end
|
74
79
|
end
|