gruff 0.15.0-java → 0.16.0-java
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 +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
|