gruff 0.15.0-java → 0.16.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/.github/workflows/ci.yml +17 -4
- data/.rubocop.yml +0 -6
- data/CHANGELOG.md +26 -0
- data/README.md +10 -3
- data/gruff.gemspec +1 -1
- data/lib/gruff/accumulator_bar.rb +1 -1
- data/lib/gruff/area.rb +4 -4
- data/lib/gruff/bar.rb +28 -9
- data/lib/gruff/base.rb +109 -118
- data/lib/gruff/bezier.rb +2 -2
- data/lib/gruff/box_plot.rb +174 -0
- data/lib/gruff/bullet.rb +5 -5
- data/lib/gruff/candlestick.rb +112 -0
- data/lib/gruff/dot.rb +10 -10
- data/lib/gruff/font.rb +3 -0
- data/lib/gruff/helper/bar_conversion.rb +5 -5
- data/lib/gruff/helper/bar_value_label.rb +27 -24
- data/lib/gruff/helper/stacked_mixin.rb +3 -1
- data/lib/gruff/histogram.rb +1 -1
- data/lib/gruff/line.rb +48 -42
- data/lib/gruff/mini/legend.rb +4 -4
- data/lib/gruff/net.rb +7 -7
- data/lib/gruff/patch/string.rb +1 -0
- data/lib/gruff/pie.rb +20 -11
- data/lib/gruff/renderer/dash_line.rb +3 -2
- data/lib/gruff/renderer/dot.rb +3 -1
- data/lib/gruff/renderer/line.rb +1 -3
- data/lib/gruff/renderer/rectangle.rb +6 -2
- data/lib/gruff/scatter.rb +52 -46
- data/lib/gruff/side_bar.rb +43 -14
- data/lib/gruff/side_stacked_bar.rb +20 -27
- data/lib/gruff/spider.rb +46 -13
- data/lib/gruff/stacked_area.rb +11 -6
- data/lib/gruff/stacked_bar.rb +36 -14
- data/lib/gruff/version.rb +1 -1
- data/lib/gruff.rb +9 -9
- metadata +4 -4
- data/lib/gruff/scene.rb +0 -208
- data/lib/gruff/store/custom_data.rb +0 -36
data/lib/gruff/bullet.rb
CHANGED
@@ -67,23 +67,23 @@ class Gruff::Bullet < Gruff::Base
|
|
67
67
|
%i[high low].each_with_index do |indicator, index|
|
68
68
|
next unless @options.key?(indicator)
|
69
69
|
|
70
|
-
indicator_width_x = graph_left + graph_width * (@options[indicator] / maximum_value)
|
70
|
+
indicator_width_x = graph_left + (graph_width * (@options[indicator] / maximum_value))
|
71
71
|
|
72
72
|
rect_renderer = Gruff::Renderer::Rectangle.new(renderer, color: @colors[index + 1])
|
73
73
|
rect_renderer.render(graph_left, 0, indicator_width_x, graph_height)
|
74
74
|
end
|
75
75
|
|
76
76
|
if @options.key?(:target)
|
77
|
-
target_x = graph_left + graph_width * (@options[:target] / maximum_value)
|
77
|
+
target_x = graph_left + (graph_width * (@options[:target] / maximum_value))
|
78
78
|
half_thickness = thickness / 2.0
|
79
79
|
|
80
80
|
rect_renderer = Gruff::Renderer::Rectangle.new(renderer, color: @marker_color)
|
81
|
-
rect_renderer.render(target_x, half_thickness, target_x + half_thickness, thickness * 2 + half_thickness)
|
81
|
+
rect_renderer.render(target_x, half_thickness, target_x + half_thickness, (thickness * 2) + half_thickness)
|
82
82
|
end
|
83
83
|
|
84
84
|
# Value
|
85
85
|
rect_renderer = Gruff::Renderer::Rectangle.new(renderer, color: @marker_color)
|
86
|
-
rect_renderer.render(graph_left, thickness, graph_left + graph_width * (@value / maximum_value), thickness * 2)
|
86
|
+
rect_renderer.render(graph_left, thickness, graph_left + (graph_width * (@value / maximum_value)), thickness * 2)
|
87
87
|
end
|
88
88
|
|
89
89
|
private
|
@@ -94,6 +94,6 @@ private
|
|
94
94
|
font_height = calculate_caps_height(@title_font)
|
95
95
|
|
96
96
|
text_renderer = Gruff::Renderer::Text.new(renderer, @title, font: @title_font)
|
97
|
-
text_renderer.add_to_render_queue(1.0, 1.0, font_height / 2, font_height / 2, Magick::NorthWestGravity)
|
97
|
+
text_renderer.add_to_render_queue(1.0, 1.0, font_height / 2.0, font_height / 2.0, Magick::NorthWestGravity)
|
98
98
|
end
|
99
99
|
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Here's how to set up a Gruff::Candlestick.
|
5
|
+
#
|
6
|
+
# g = Gruff::Candlestick.new
|
7
|
+
# g.data low: 79.30, high: 93.10, open: 79.44, close: 91.20
|
8
|
+
# g.data low: 89.14, high: 106.42, open: 91.28, close: 106.26
|
9
|
+
# g.data low: 107.89, high: 131.00, open: 108.20, close: 129.04
|
10
|
+
# g.data low: 103.10, high: 137.98, open: 132.76, close: 115.81
|
11
|
+
# g.write("candlestick.png")
|
12
|
+
#
|
13
|
+
class Gruff::Candlestick < Gruff::Base
|
14
|
+
# Allow for vertical marker lines.
|
15
|
+
attr_writer :show_vertical_markers
|
16
|
+
|
17
|
+
# Specifies the filling opacity in area graph. Default is +0.4+.
|
18
|
+
attr_writer :fill_opacity
|
19
|
+
|
20
|
+
# Specifies the stroke width in line. Default is +2.0+.
|
21
|
+
attr_writer :stroke_width
|
22
|
+
|
23
|
+
# Specifies the color with up bar. Default is +'#579773'+.
|
24
|
+
attr_writer :up_color
|
25
|
+
|
26
|
+
# Specifies the color with down bar. Default is +'#eb5242'+.
|
27
|
+
attr_writer :down_color
|
28
|
+
|
29
|
+
# Can be used to adjust the spaces between the bars.
|
30
|
+
# Accepts values between 0.00 and 1.00 where 0.00 means no spacing at all
|
31
|
+
# and 1 means that each bars' width is nearly 0 (so each bar is a simple
|
32
|
+
# line with no x dimension).
|
33
|
+
#
|
34
|
+
# Default value is +0.9+.
|
35
|
+
def spacing_factor=(space_percent)
|
36
|
+
raise ArgumentError, 'spacing_factor must be between 0.00 and 1.00' unless (space_percent >= 0) && (space_percent <= 1)
|
37
|
+
|
38
|
+
@spacing_factor = (1 - space_percent)
|
39
|
+
end
|
40
|
+
|
41
|
+
def data(low:, high:, open:, close:)
|
42
|
+
super('', [low, high, open, close])
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def initialize_attributes
|
48
|
+
super
|
49
|
+
@show_vertical_markers = false
|
50
|
+
@fill_opacity = 0.4
|
51
|
+
@spacing_factor = 0.9
|
52
|
+
@stroke_width = 2.0
|
53
|
+
@up_color = '#579773'
|
54
|
+
@down_color = '#eb5242'
|
55
|
+
|
56
|
+
@sort = false
|
57
|
+
@hide_legend = true
|
58
|
+
end
|
59
|
+
|
60
|
+
def draw_graph
|
61
|
+
# Setup the BarConversion Object
|
62
|
+
conversion = Gruff::BarConversion.new(
|
63
|
+
top: @graph_top, bottom: @graph_bottom,
|
64
|
+
minimum_value: minimum_value, maximum_value: maximum_value, spread: @spread
|
65
|
+
)
|
66
|
+
|
67
|
+
width = (@graph_width - calculate_spacing) / normalized_candlesticks.size
|
68
|
+
bar_width = width * @spacing_factor
|
69
|
+
padding = width - bar_width
|
70
|
+
|
71
|
+
normalized_candlesticks.each_with_index do |candlestick, index|
|
72
|
+
left_x = @graph_left + (width * index) + (padding / 2.0)
|
73
|
+
right_x = left_x + bar_width
|
74
|
+
center_x = (left_x + right_x) / 2.0
|
75
|
+
color = candlestick.close >= candlestick.open ? @up_color : @down_color
|
76
|
+
|
77
|
+
draw_label(center_x, index) do
|
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
|
87
|
+
|
88
|
+
open_y, = conversion.get_top_bottom_scaled(candlestick.open)
|
89
|
+
close_y, = conversion.get_top_bottom_scaled(candlestick.close)
|
90
|
+
Gruff::Renderer::Rectangle.new(renderer, color: color, opacity: @fill_opacity, width: @stroke_width).render(left_x, open_y, right_x, close_y)
|
91
|
+
|
92
|
+
low_y, = conversion.get_top_bottom_scaled(candlestick.low)
|
93
|
+
y = open_y < close_y ? close_y : open_y
|
94
|
+
Gruff::Renderer::Line.new(renderer, color: color, width: @stroke_width).render(center_x, low_y, center_x, y)
|
95
|
+
high_y, = conversion.get_top_bottom_scaled(candlestick.high)
|
96
|
+
y = open_y > close_y ? close_y : open_y
|
97
|
+
Gruff::Renderer::Line.new(renderer, color: color, width: @stroke_width).render(center_x, y, center_x, high_y)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def normalized_candlesticks
|
102
|
+
@candlesticks ||= store.norm_data.map { |data| Gruff::Candlestick::CandlestickData.new(*data.points) }
|
103
|
+
end
|
104
|
+
|
105
|
+
def calculate_spacing
|
106
|
+
@scale * (column_count - 1)
|
107
|
+
end
|
108
|
+
|
109
|
+
# @private
|
110
|
+
class CandlestickData < Struct.new(:low, :high, :open, :close)
|
111
|
+
end
|
112
|
+
end
|
data/lib/gruff/dot.rb
CHANGED
@@ -14,32 +14,32 @@
|
|
14
14
|
# g.write('dot.png')
|
15
15
|
#
|
16
16
|
class Gruff::Dot < Gruff::Base
|
17
|
-
|
18
|
-
|
19
|
-
def initialize_attributes
|
17
|
+
def initialize(*)
|
20
18
|
super
|
21
19
|
@has_left_labels = true
|
22
20
|
end
|
23
21
|
|
22
|
+
private
|
23
|
+
|
24
24
|
def draw_graph
|
25
25
|
# Setup spacing.
|
26
26
|
#
|
27
27
|
spacing_factor = 1.0
|
28
28
|
|
29
|
-
items_width = @graph_height / column_count
|
29
|
+
items_width = @graph_height / column_count
|
30
30
|
item_width = items_width * spacing_factor / store.length
|
31
31
|
padding = (items_width * (1 - spacing_factor)) / 2
|
32
32
|
|
33
33
|
store.norm_data.each_with_index do |data_row, row_index|
|
34
34
|
data_row.points.each_with_index do |data_point, point_index|
|
35
35
|
x_pos = @graph_left + (data_point * @graph_width)
|
36
|
-
y_pos = @graph_top + (items_width * point_index) + padding + (items_width
|
36
|
+
y_pos = @graph_top + (items_width * point_index) + padding + (items_width / 2.0)
|
37
37
|
|
38
38
|
if row_index == 0
|
39
39
|
Gruff::Renderer::Line.new(renderer, color: @marker_color).render(@graph_left, y_pos, @graph_left + @graph_width, y_pos)
|
40
40
|
end
|
41
41
|
|
42
|
-
Gruff::Renderer::Circle.new(renderer, color: data_row.color).render(x_pos, y_pos, x_pos + (item_width
|
42
|
+
Gruff::Renderer::Circle.new(renderer, color: data_row.color).render(x_pos, y_pos, x_pos + (item_width / 3.0), y_pos)
|
43
43
|
|
44
44
|
draw_label(y_pos, point_index)
|
45
45
|
end
|
@@ -51,11 +51,11 @@ private
|
|
51
51
|
return if @hide_line_markers
|
52
52
|
|
53
53
|
(0..marker_count).each do |index|
|
54
|
-
marker_label = BigDecimal(index.to_s) * BigDecimal(@increment.to_s) + BigDecimal(minimum_value.to_s)
|
55
|
-
x = @graph_left + (marker_label - minimum_value) * @graph_width / @spread
|
54
|
+
marker_label = (BigDecimal(index.to_s) * BigDecimal(@increment.to_s)) + BigDecimal(minimum_value.to_s)
|
55
|
+
x = @graph_left + ((marker_label - minimum_value) * @graph_width / @spread)
|
56
56
|
|
57
|
-
|
58
|
-
|
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
|
59
59
|
|
60
60
|
unless @hide_line_numbers
|
61
61
|
label = y_axis_label(marker_label, @increment)
|
data/lib/gruff/font.rb
CHANGED
@@ -3,7 +3,10 @@
|
|
3
3
|
# Handle font setting to draw texts
|
4
4
|
class Gruff::Font
|
5
5
|
BOLD_PATH = File.expand_path(File.join(__FILE__, '../../../assets/fonts/Roboto-Bold.ttf')).freeze
|
6
|
+
private_constant :BOLD_PATH
|
7
|
+
|
6
8
|
REGULAR_PATH = File.expand_path(File.join(__FILE__, '../../../assets/fonts/Roboto-Regular.ttf')).freeze
|
9
|
+
private_constant :REGULAR_PATH
|
7
10
|
|
8
11
|
# Get/set font path.
|
9
12
|
attr_accessor :path
|
@@ -41,17 +41,17 @@ class Gruff::BarConversion
|
|
41
41
|
case @mode
|
42
42
|
when 1
|
43
43
|
# minimum value >= 0 ( only positive values )
|
44
|
-
result[0] = @graph_top + @graph_height * (1 - data_point)
|
44
|
+
result[0] = @graph_top + (@graph_height * (1 - data_point))
|
45
45
|
result[1] = @graph_top + @graph_height
|
46
46
|
when 2
|
47
47
|
# only negative values
|
48
48
|
result[0] = @graph_top
|
49
|
-
result[1] = @graph_top + @graph_height * (1 - data_point)
|
49
|
+
result[1] = @graph_top + (@graph_height * (1 - data_point))
|
50
50
|
when 3
|
51
51
|
# positive and negative values
|
52
|
-
val = data_point - @minimum_value / @spread
|
53
|
-
result[0] = @graph_top + @graph_height * (1 - (val - @zero))
|
54
|
-
result[1] = @graph_top + @graph_height * (1 - @zero)
|
52
|
+
val = data_point - (@minimum_value / @spread)
|
53
|
+
result[0] = @graph_top + (@graph_height * (1 - (val - @zero)))
|
54
|
+
result[1] = @graph_top + (@graph_height * (1 - @zero))
|
55
55
|
else
|
56
56
|
result[0] = 0.0
|
57
57
|
result[1] = 0.0
|
@@ -4,6 +4,20 @@
|
|
4
4
|
module Gruff::BarValueLabel
|
5
5
|
using String::GruffCommify
|
6
6
|
|
7
|
+
# @private
|
8
|
+
def self.metrics(value, format, proc_text_metrics)
|
9
|
+
val = begin
|
10
|
+
if format.is_a?(Proc)
|
11
|
+
format.call(value)
|
12
|
+
else
|
13
|
+
sprintf(format || '%.2f', value).commify
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
metrics = proc_text_metrics.call(val)
|
18
|
+
[val, metrics]
|
19
|
+
end
|
20
|
+
|
7
21
|
# @private
|
8
22
|
class Base
|
9
23
|
attr_reader :coordinate, :value
|
@@ -16,34 +30,23 @@ module Gruff::BarValueLabel
|
|
16
30
|
|
17
31
|
# @private
|
18
32
|
class Bar < Base
|
19
|
-
def prepare_rendering(format,
|
20
|
-
left_x, left_y,
|
21
|
-
val =
|
22
|
-
if format.is_a?(Proc)
|
23
|
-
format.call(@value)
|
24
|
-
else
|
25
|
-
sprintf(format || '%.2f', @value).commify
|
26
|
-
end
|
27
|
-
end
|
33
|
+
def prepare_rendering(format, proc_text_metrics)
|
34
|
+
left_x, left_y, _right_x, _right_y = @coordinate
|
35
|
+
val, metrics = Gruff::BarValueLabel.metrics(@value, format, proc_text_metrics)
|
28
36
|
|
29
|
-
y = @value >= 0 ? left_y -
|
30
|
-
yield left_x
|
37
|
+
y = @value >= 0 ? left_y - metrics.height - 5 : left_y + 5
|
38
|
+
yield left_x, y, val, metrics.width, metrics.height
|
31
39
|
end
|
32
40
|
end
|
33
41
|
|
34
42
|
# @private
|
35
43
|
class SideBar < Base
|
36
|
-
def prepare_rendering(format,
|
37
|
-
left_x,
|
38
|
-
val =
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
sprintf(format || '%.2f', @value).commify
|
43
|
-
end
|
44
|
-
end
|
45
|
-
x = @value >= 0 ? right_x + 40 : left_x - 40
|
46
|
-
yield x, right_y - bar_width / 2, val
|
44
|
+
def prepare_rendering(format, proc_text_metrics)
|
45
|
+
left_x, left_y, right_x, _right_y = @coordinate
|
46
|
+
val, metrics = Gruff::BarValueLabel.metrics(@value, format, proc_text_metrics)
|
47
|
+
|
48
|
+
x = @value >= 0 ? right_x + 10 : left_x - metrics.width - 10
|
49
|
+
yield x, left_y, val, metrics.width, metrics.height
|
47
50
|
end
|
48
51
|
end
|
49
52
|
|
@@ -59,12 +62,12 @@ module Gruff::BarValueLabel
|
|
59
62
|
@bars[index] = bars
|
60
63
|
end
|
61
64
|
|
62
|
-
def prepare_rendering(format,
|
65
|
+
def prepare_rendering(format, proc_text_metrics, &block)
|
63
66
|
@bars.each do |bars|
|
64
67
|
value = bars.sum(&:value)
|
65
68
|
bar = bars.last
|
66
69
|
bar_value_label = bar.class.new(bar.coordinate, value)
|
67
|
-
bar_value_label.prepare_rendering(format,
|
70
|
+
bar_value_label.prepare_rendering(format, proc_text_metrics, &block)
|
68
71
|
end
|
69
72
|
end
|
70
73
|
end
|
@@ -16,7 +16,9 @@ module Gruff::Base::StackedMixin
|
|
16
16
|
|
17
17
|
max_hash.each_key do |key|
|
18
18
|
self.maximum_value = max_hash[key] if max_hash[key] > maximum_value
|
19
|
+
self.minimum_value = max_hash[key] if max_hash[key] < minimum_value
|
19
20
|
end
|
20
|
-
|
21
|
+
|
22
|
+
raise "Can't handle negative values in stacked graph" if minimum_value < 0
|
21
23
|
end
|
22
24
|
end
|
data/lib/gruff/histogram.rb
CHANGED
data/lib/gruff/line.rb
CHANGED
@@ -40,6 +40,23 @@ class Gruff::Line < Gruff::Base
|
|
40
40
|
# The number of vertical lines shown.
|
41
41
|
attr_writer :marker_x_count
|
42
42
|
|
43
|
+
# Call with target pixel width of graph (+800+, +400+, +300+), and/or +false+ to omit lines (points only).
|
44
|
+
#
|
45
|
+
# g = Gruff::Line.new(400) # 400px wide with lines
|
46
|
+
# g = Gruff::Line.new(400, false) # 400px wide, no lines (for backwards compatibility)
|
47
|
+
# g = Gruff::Line.new(false) # Defaults to 800px wide, no lines (for backwards compatibility)
|
48
|
+
#
|
49
|
+
# The preferred way is to call {#hide_dots=} or {#hide_lines=} instead.
|
50
|
+
def initialize(*args)
|
51
|
+
raise ArgumentError, 'Wrong number of arguments' if args.length > 2
|
52
|
+
|
53
|
+
if args.empty? || (!args.first.is_a?(Numeric) && !args.first.is_a?(String))
|
54
|
+
super()
|
55
|
+
else
|
56
|
+
super args.shift
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
43
60
|
# Get the value if somebody has defined it.
|
44
61
|
def baseline_value
|
45
62
|
if @reference_lines.key?(:baseline)
|
@@ -64,23 +81,6 @@ class Gruff::Line < Gruff::Base
|
|
64
81
|
@reference_lines[:baseline][:color] = new_value
|
65
82
|
end
|
66
83
|
|
67
|
-
# Call with target pixel width of graph (+800+, +400+, +300+), and/or +false+ to omit lines (points only).
|
68
|
-
#
|
69
|
-
# g = Gruff::Line.new(400) # 400px wide with lines
|
70
|
-
# g = Gruff::Line.new(400, false) # 400px wide, no lines (for backwards compatibility)
|
71
|
-
# g = Gruff::Line.new(false) # Defaults to 800px wide, no lines (for backwards compatibility)
|
72
|
-
#
|
73
|
-
# The preferred way is to call {#hide_dots=} or {#hide_lines=} instead.
|
74
|
-
def initialize(*args)
|
75
|
-
raise ArgumentError, 'Wrong number of arguments' if args.length > 2
|
76
|
-
|
77
|
-
if args.empty? || (!args.first.is_a?(Numeric) && !args.first.is_a?(String))
|
78
|
-
super()
|
79
|
-
else
|
80
|
-
super args.shift
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
84
|
# This method allows one to plot a dataset with both X and Y data.
|
85
85
|
#
|
86
86
|
# @overload dataxy(name, x_data_points = [], y_data_points = [], color = nil)
|
@@ -165,7 +165,7 @@ private
|
|
165
165
|
end
|
166
166
|
|
167
167
|
def draw_horizontal_reference_line(reference_line)
|
168
|
-
level = @graph_top + (@graph_height - reference_line[:norm_value] * @graph_height)
|
168
|
+
level = @graph_top + (@graph_height - (reference_line[:norm_value] * @graph_height))
|
169
169
|
draw_reference_line(reference_line, @graph_left, @graph_left + @graph_width, level, level)
|
170
170
|
end
|
171
171
|
|
@@ -176,7 +176,7 @@ private
|
|
176
176
|
|
177
177
|
def draw_graph
|
178
178
|
# Check to see if more than one datapoint was given. NaN can result otherwise.
|
179
|
-
@x_increment = column_count > 1 ?
|
179
|
+
@x_increment = column_count > 1 ? @graph_width / (column_count - 1) : @graph_width
|
180
180
|
|
181
181
|
@reference_lines.each_value do |curr_reference_line|
|
182
182
|
draw_horizontal_reference_line(curr_reference_line) if curr_reference_line.key?(:norm_value)
|
@@ -189,22 +189,22 @@ private
|
|
189
189
|
one_point = contains_one_point_only?(data_row)
|
190
190
|
|
191
191
|
data_row.coordinates.each_with_index do |(x_data, y_data), index|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
@labels.each do |label_pos, _|
|
199
|
-
draw_label(@graph_left + ((label_pos - @minimum_x_value) * @graph_width) / (@maximum_x_value - @minimum_x_value), label_pos)
|
192
|
+
new_x = begin
|
193
|
+
if x_data.nil?
|
194
|
+
# use the old method: equally spaced points along the x-axis
|
195
|
+
@graph_left + (@x_increment * index)
|
196
|
+
else
|
197
|
+
get_x_coord(x_data, @graph_width, @graph_left)
|
200
198
|
end
|
201
199
|
end
|
200
|
+
draw_label_for_x_data(x_data, new_x, index)
|
201
|
+
|
202
202
|
unless y_data # we can't draw a line for a null data point, we can still label the axis though
|
203
203
|
prev_x = prev_y = nil
|
204
204
|
next
|
205
205
|
end
|
206
206
|
|
207
|
-
new_y = @graph_top + (@graph_height - y_data * @graph_height)
|
207
|
+
new_y = @graph_top + (@graph_height - (y_data * @graph_height))
|
208
208
|
|
209
209
|
# Reset each time to avoid thin-line errors
|
210
210
|
stroke_width = @line_width || clip_value_if_greater_than(@columns / (store.norm_data.first.y_points.size * 4), 5.0)
|
@@ -227,12 +227,12 @@ private
|
|
227
227
|
|
228
228
|
def setup_data
|
229
229
|
# Update the global min/max values for the x data
|
230
|
-
@maximum_x_value
|
231
|
-
@minimum_x_value
|
230
|
+
@maximum_x_value = (@maximum_x_value || store.max_x).to_f
|
231
|
+
@minimum_x_value = (@minimum_x_value || store.min_x).to_f
|
232
232
|
|
233
233
|
# Deal with horizontal reference line values that exceed the existing minimum & maximum values.
|
234
|
-
possible_maximums = [maximum_value
|
235
|
-
possible_minimums = [minimum_value
|
234
|
+
possible_maximums = [maximum_value]
|
235
|
+
possible_minimums = [minimum_value]
|
236
236
|
|
237
237
|
@reference_lines.each_value do |curr_reference_line|
|
238
238
|
if curr_reference_line.key?(:value)
|
@@ -255,14 +255,14 @@ private
|
|
255
255
|
def normalize
|
256
256
|
return unless data_given?
|
257
257
|
|
258
|
-
spread_x = @maximum_x_value
|
258
|
+
spread_x = @maximum_x_value - @minimum_x_value
|
259
259
|
store.normalize(minimum_x: @minimum_x_value, spread_x: spread_x, minimum_y: minimum_value, spread_y: @spread)
|
260
260
|
|
261
261
|
@reference_lines.each_value do |curr_reference_line|
|
262
262
|
# We only care about horizontal markers ... for normalization.
|
263
263
|
# Vertical markers won't have a :value, they will have an :index
|
264
264
|
|
265
|
-
curr_reference_line[:norm_value] = ((curr_reference_line[:value].to_f - minimum_value) / @spread
|
265
|
+
curr_reference_line[:norm_value] = ((curr_reference_line[:value].to_f - minimum_value) / @spread) if curr_reference_line.key?(:value)
|
266
266
|
end
|
267
267
|
end
|
268
268
|
|
@@ -270,22 +270,28 @@ private
|
|
270
270
|
# do all of the stuff for the horizontal lines on the y-axis
|
271
271
|
super
|
272
272
|
return if @hide_line_markers
|
273
|
+
return unless @show_vertical_markers
|
273
274
|
|
274
275
|
(0..@marker_x_count).each do |index|
|
275
|
-
|
276
|
-
x = @graph_left + @graph_width - index * @graph_width / @marker_x_count
|
276
|
+
x = @graph_left + @graph_width - (index * @graph_width / @marker_x_count)
|
277
277
|
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
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
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
def draw_label_for_x_data(x_data, new_x, index)
|
284
|
+
if x_data.nil?
|
285
|
+
draw_label(new_x, index)
|
286
|
+
else
|
287
|
+
@labels.each do |label_pos, _|
|
288
|
+
draw_label(@graph_left + (((label_pos - @minimum_x_value) * @graph_width) / (@maximum_x_value - @minimum_x_value)), label_pos)
|
283
289
|
end
|
284
290
|
end
|
285
291
|
end
|
286
292
|
|
287
293
|
def get_x_coord(x_data_point, width, offset)
|
288
|
-
x_data_point * width + offset
|
294
|
+
(x_data_point * width) + offset
|
289
295
|
end
|
290
296
|
|
291
297
|
def contains_one_point_only?(data_row)
|
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 = scale_fontsize(store.length * calculate_line_height + @top_margin + @bottom_margin)
|
24
|
+
legend_height = scale_fontsize((store.length * calculate_line_height) + @top_margin + @bottom_margin)
|
25
25
|
|
26
26
|
@original_rows = @raw_rows
|
27
27
|
@original_columns = @raw_columns
|
@@ -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
|
-
scale_fontsize(width + 40 * 1.7)
|
48
|
+
scale_fontsize(width + (40 * 1.7))
|
49
49
|
end
|
50
50
|
|
51
51
|
##
|
@@ -77,9 +77,9 @@ module Gruff
|
|
77
77
|
# Now draw box with color of this dataset
|
78
78
|
rect_renderer = Gruff::Renderer::Rectangle.new(renderer, color: store.data[index].color)
|
79
79
|
rect_renderer.render(current_x_offset,
|
80
|
-
current_y_offset - legend_square_width / 2.0,
|
80
|
+
current_y_offset - (legend_square_width / 2.0),
|
81
81
|
current_x_offset + legend_square_width,
|
82
|
-
current_y_offset + legend_square_width / 2.0)
|
82
|
+
current_y_offset + (legend_square_width / 2.0))
|
83
83
|
|
84
84
|
current_y_offset += calculate_line_height
|
85
85
|
end
|
data/lib/gruff/net.rb
CHANGED
@@ -50,15 +50,15 @@ private
|
|
50
50
|
|
51
51
|
rad_pos = index * Math::PI * 2 / column_count
|
52
52
|
point_distance = data_point * @radius
|
53
|
-
start_x = @center_x + Math.sin(rad_pos) * point_distance
|
54
|
-
start_y = @center_y - Math.cos(rad_pos) * point_distance
|
53
|
+
start_x = @center_x + (Math.sin(rad_pos) * point_distance)
|
54
|
+
start_y = @center_y - (Math.cos(rad_pos) * point_distance)
|
55
55
|
|
56
56
|
next_index = index + 1 < data_row.points.length ? index + 1 : 0
|
57
57
|
|
58
58
|
next_rad_pos = next_index * Math::PI * 2 / column_count
|
59
59
|
next_point_distance = data_row.points[next_index] * @radius
|
60
|
-
end_x = @center_x + Math.sin(next_rad_pos) * next_point_distance
|
61
|
-
end_y = @center_y - Math.cos(next_rad_pos) * next_point_distance
|
60
|
+
end_x = @center_x + (Math.sin(next_rad_pos) * next_point_distance)
|
61
|
+
end_y = @center_y - (Math.cos(next_rad_pos) * next_point_distance)
|
62
62
|
|
63
63
|
Gruff::Renderer::Line.new(renderer, color: data_row.color, width: @stroke_width).render(start_x, start_y, end_x, end_y)
|
64
64
|
|
@@ -89,7 +89,7 @@ private
|
|
89
89
|
rad_pos = index * Math::PI * 2 / column_count
|
90
90
|
|
91
91
|
Gruff::Renderer::Line.new(renderer, color: @marker_color)
|
92
|
-
.render(@center_x, @center_y, @center_x + Math.sin(rad_pos) * @radius, @center_y - Math.cos(rad_pos) * @radius)
|
92
|
+
.render(@center_x, @center_y, @center_x + (Math.sin(rad_pos) * @radius), @center_y - (Math.cos(rad_pos) * @radius))
|
93
93
|
|
94
94
|
marker_label = @labels[index] ? @labels[index].to_s : '000'
|
95
95
|
draw_label(@center_x, @center_y, rad_pos * 360 / (2 * Math::PI), @radius + @circle_radius, marker_label)
|
@@ -99,8 +99,8 @@ private
|
|
99
99
|
def draw_label(center_x, center_y, angle, radius, amount)
|
100
100
|
x_offset = center_x # + 15 # The label points need to be tweaked slightly
|
101
101
|
y_offset = center_y # + 0 # This one doesn't though
|
102
|
-
x = x_offset + (radius + LABEL_MARGIN) * Math.sin(deg2rad(angle))
|
103
|
-
y = y_offset - (radius + LABEL_MARGIN) * Math.cos(deg2rad(angle))
|
102
|
+
x = x_offset + ((radius + LABEL_MARGIN) * Math.sin(deg2rad(angle)))
|
103
|
+
y = y_offset - ((radius + LABEL_MARGIN) * Math.cos(deg2rad(angle)))
|
104
104
|
|
105
105
|
draw_label_at(1.0, 1.0, x, y, amount, Magick::CenterGravity)
|
106
106
|
end
|
data/lib/gruff/patch/string.rb
CHANGED
data/lib/gruff/pie.rb
CHANGED
@@ -9,14 +9,14 @@
|
|
9
9
|
# g.data 'Hamburgers', 50
|
10
10
|
# g.write("pie_keynote.png")
|
11
11
|
#
|
12
|
-
# To control where the pie chart starts creating slices, use {#
|
12
|
+
# To control where the pie chart starts creating slices, use {#start_degree=}.
|
13
13
|
#
|
14
14
|
class Gruff::Pie < Gruff::Base
|
15
|
-
DEFAULT_TEXT_OFFSET_PERCENTAGE = 0.
|
15
|
+
DEFAULT_TEXT_OFFSET_PERCENTAGE = 0.1
|
16
16
|
|
17
17
|
# Can be used to make the pie start cutting slices at the top (-90.0)
|
18
|
-
# or at another angle. Default is
|
19
|
-
attr_writer :
|
18
|
+
# or at another angle. Default is +-90.0+, which starts at 3 o'clock.
|
19
|
+
attr_writer :start_degree
|
20
20
|
|
21
21
|
# Set the number output format lambda.
|
22
22
|
attr_writer :label_formatting
|
@@ -26,25 +26,34 @@ class Gruff::Pie < Gruff::Base
|
|
26
26
|
attr_writer :hide_labels_less_than
|
27
27
|
|
28
28
|
# Affect the distance between the percentages and the pie chart.
|
29
|
-
# Defaults to +0.
|
29
|
+
# Defaults to +0.1+.
|
30
30
|
attr_writer :text_offset_percentage
|
31
31
|
|
32
32
|
## Use values instead of percentages.
|
33
33
|
attr_writer :show_values_as_labels
|
34
34
|
|
35
|
-
|
35
|
+
# Set to +true+ if you want the data sets sorted with largest avg values drawn
|
36
|
+
# first. Default is +true+.
|
37
|
+
attr_writer :sort
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
+
# Can be used to make the pie start cutting slices at the top (-90.0)
|
40
|
+
# or at another angle. Default is +-90.0+, which starts at 3 o'clock.
|
41
|
+
# @deprecated Please use +start_degree+ attribute instead.
|
42
|
+
def zero_degree=(value)
|
43
|
+
warn '#zero_degree= is deprecated. Please use `start_degree` attribute instead'
|
44
|
+
@start_degree = value
|
39
45
|
end
|
40
46
|
|
47
|
+
private
|
48
|
+
|
41
49
|
def initialize_attributes
|
42
50
|
super
|
43
|
-
@
|
51
|
+
@start_degree = -90.0
|
44
52
|
@hide_labels_less_than = 0.0
|
45
53
|
@text_offset_percentage = DEFAULT_TEXT_OFFSET_PERCENTAGE
|
46
54
|
@show_values_as_labels = false
|
47
55
|
@marker_font.bold = true
|
56
|
+
@sort = true
|
48
57
|
|
49
58
|
@hide_line_markers = true
|
50
59
|
@hide_line_markers.freeze
|
@@ -83,7 +92,7 @@ private
|
|
83
92
|
# Spatial Value-Related Methods
|
84
93
|
|
85
94
|
def chart_degrees
|
86
|
-
@chart_degrees ||= @
|
95
|
+
@chart_degrees ||= @start_degree
|
87
96
|
end
|
88
97
|
|
89
98
|
attr_reader :graph_height
|
@@ -132,7 +141,7 @@ private
|
|
132
141
|
end
|
133
142
|
|
134
143
|
def label_coordinates_for(slice)
|
135
|
-
angle = chart_degrees + slice.degrees / 2
|
144
|
+
angle = chart_degrees + (slice.degrees / 2.0)
|
136
145
|
|
137
146
|
[x_label_coordinate(angle), y_label_coordinate(angle)]
|
138
147
|
end
|