gruff 0.3.6 → 0.3.7
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/.rvmrc +5 -0
- data/.travis.yml +8 -0
- data/Gemfile +16 -0
- data/Gemfile.lock +20 -0
- data/LICENSE.txt +22 -0
- data/README.md +49 -0
- data/README.txt +3 -0
- data/Rakefile +17 -34
- data/gruff.gemspec +33 -0
- data/lib/gruff.rb +3 -0
- data/lib/gruff/base.rb +17 -14
- data/lib/gruff/line.rb +104 -11
- data/lib/gruff/mini/legend.rb +50 -23
- data/lib/gruff/pie.rb +8 -6
- data/lib/gruff/scatter.rb +268 -0
- data/lib/gruff/scene.rb +1 -1
- data/lib/gruff/side_bar.rb +13 -7
- data/lib/gruff/side_stacked_bar.rb +9 -6
- data/lib/gruff/stacked_bar.rb +3 -0
- data/lib/gruff/version.rb +3 -0
- data/test/gruff_test_case.rb +2 -0
- data/test/test_bar.rb +16 -1
- data/test/test_line.rb +102 -64
- data/test/test_mini_bar.rb +1 -1
- data/test/test_mini_pie.rb +7 -2
- data/test/test_mini_side_bar.rb +1 -2
- data/test/test_scatter.rb +233 -0
- data/test/test_scene.rb +1 -1
- data/test/test_side_bar.rb +31 -0
- metadata +41 -27
data/lib/gruff/mini/legend.rb
CHANGED
@@ -1,28 +1,49 @@
|
|
1
1
|
module Gruff
|
2
2
|
module Mini
|
3
3
|
module Legend
|
4
|
-
|
5
|
-
attr_accessor :hide_mini_legend
|
6
|
-
|
4
|
+
|
5
|
+
attr_accessor :hide_mini_legend, :legend_position
|
6
|
+
|
7
7
|
##
|
8
8
|
# The canvas needs to be bigger so we can put the legend beneath it.
|
9
9
|
|
10
10
|
def expand_canvas_for_vertical_legend
|
11
11
|
return if @hide_mini_legend
|
12
|
-
|
12
|
+
|
13
|
+
@legend_labels = @data.collect {|item| item[Gruff::Base::DATA_LABEL_INDEX] }
|
14
|
+
|
15
|
+
legend_height = scale_fontsize(
|
16
|
+
@data.length * calculate_line_height +
|
17
|
+
@top_margin + @bottom_margin)
|
18
|
+
|
13
19
|
@original_rows = @raw_rows
|
14
|
-
@
|
20
|
+
@original_columns = @raw_columns
|
21
|
+
|
22
|
+
case @legend_position
|
23
|
+
when :right then
|
24
|
+
@rows = [@rows, legend_height].max
|
25
|
+
@columns += calculate_legend_width + @left_margin
|
26
|
+
else
|
27
|
+
@rows += @data.length * calculate_caps_height(scale_fontsize(@legend_font_size)) * 1.7
|
28
|
+
end
|
15
29
|
render_background
|
16
30
|
end
|
17
|
-
|
31
|
+
|
32
|
+
def calculate_line_height
|
33
|
+
calculate_caps_height(@legend_font_size) * 1.7
|
34
|
+
end
|
35
|
+
|
36
|
+
def calculate_legend_width
|
37
|
+
width = @legend_labels.map { |label| calculate_width(@legend_font_size, label) }.max
|
38
|
+
scale_fontsize(width + 40*1.7)
|
39
|
+
end
|
40
|
+
|
18
41
|
##
|
19
42
|
# Draw the legend beneath the existing graph.
|
20
43
|
|
21
44
|
def draw_vertical_legend
|
22
45
|
return if @hide_mini_legend
|
23
|
-
|
24
|
-
@legend_labels = @data.collect {|item| item[Gruff::Base::DATA_LABEL_INDEX] }
|
25
|
-
|
46
|
+
|
26
47
|
legend_square_width = 40.0 # small square with color of this item
|
27
48
|
legend_square_margin = 10.0
|
28
49
|
@legend_left_margin = 100.0
|
@@ -32,12 +53,18 @@ module Gruff
|
|
32
53
|
@d.font = @font if @font
|
33
54
|
@d.pointsize = @legend_font_size
|
34
55
|
|
35
|
-
|
36
|
-
|
56
|
+
case @legend_position
|
57
|
+
when :right then
|
58
|
+
current_x_offset = @original_columns + @left_margin
|
59
|
+
current_y_offset = @top_margin + legend_top_margin
|
60
|
+
else
|
61
|
+
current_x_offset = @legend_left_margin
|
62
|
+
current_y_offset = @original_rows + legend_top_margin
|
63
|
+
end
|
37
64
|
|
38
65
|
debug { @d.line 0.0, current_y_offset, @raw_columns, current_y_offset }
|
39
66
|
|
40
|
-
@legend_labels.each_with_index do |legend_label, index|
|
67
|
+
@legend_labels.each_with_index do |legend_label, index|
|
41
68
|
|
42
69
|
# Draw label
|
43
70
|
@d.fill = @font_color
|
@@ -46,20 +73,20 @@ module Gruff
|
|
46
73
|
@d.stroke = 'transparent'
|
47
74
|
@d.font_weight = Magick::NormalWeight
|
48
75
|
@d.gravity = Magick::WestGravity
|
49
|
-
@d = @d.annotate_scaled( @base_image,
|
50
|
-
|
51
|
-
|
52
|
-
|
76
|
+
@d = @d.annotate_scaled( @base_image,
|
77
|
+
@raw_columns, 1.0,
|
78
|
+
current_x_offset + (legend_square_width * 1.7), current_y_offset,
|
79
|
+
truncate_legend_label(legend_label), @scale)
|
53
80
|
|
54
81
|
# Now draw box with color of this dataset
|
55
82
|
@d = @d.stroke 'transparent'
|
56
83
|
@d = @d.fill @data[index][Gruff::Base::DATA_COLOR_INDEX]
|
57
|
-
@d = @d.rectangle(current_x_offset,
|
58
|
-
current_y_offset - legend_square_width / 2.0,
|
59
|
-
current_x_offset + legend_square_width,
|
84
|
+
@d = @d.rectangle(current_x_offset,
|
85
|
+
current_y_offset - legend_square_width / 2.0,
|
86
|
+
current_x_offset + legend_square_width,
|
60
87
|
current_y_offset + legend_square_width / 2.0)
|
61
|
-
|
62
|
-
current_y_offset +=
|
88
|
+
|
89
|
+
current_y_offset += calculate_line_height
|
63
90
|
end
|
64
91
|
@color_index = 0
|
65
92
|
end
|
@@ -68,7 +95,7 @@ module Gruff
|
|
68
95
|
# Shorten long labels so they will fit on the canvas.
|
69
96
|
#
|
70
97
|
# Department of Hu...
|
71
|
-
|
98
|
+
|
72
99
|
def truncate_legend_label(label)
|
73
100
|
truncated_label = label.to_s
|
74
101
|
while calculate_width(scale_fontsize(@legend_font_size), truncated_label) > (@columns - @legend_left_margin - @right_margin) && (truncated_label.length > 1)
|
@@ -76,7 +103,7 @@ module Gruff
|
|
76
103
|
end
|
77
104
|
truncated_label + (truncated_label.length < label.to_s.length ? "..." : '')
|
78
105
|
end
|
79
|
-
|
106
|
+
|
80
107
|
end
|
81
108
|
end
|
82
109
|
end
|
data/lib/gruff/pie.rb
CHANGED
@@ -18,10 +18,14 @@ class Gruff::Pie < Gruff::Base
|
|
18
18
|
# Can be used to make the pie start cutting slices at the top (-90.0)
|
19
19
|
# or at another angle. Default is 0.0, which starts at 3 o'clock.
|
20
20
|
attr_accessor :zero_degree
|
21
|
+
# Do not show labels for slices that are less than this percent. Use 0 to always show all labels.
|
22
|
+
# Defaults to 0
|
23
|
+
attr_accessor :hide_labels_less_than
|
21
24
|
|
22
25
|
def initialize_ivars
|
23
26
|
super
|
24
27
|
@zero_degree = 0.0
|
28
|
+
@hide_labels_less_than = 0.0
|
25
29
|
end
|
26
30
|
|
27
31
|
def draw
|
@@ -58,17 +62,15 @@ class Gruff::Pie < Gruff::Base
|
|
58
62
|
|
59
63
|
half_angle = prev_degrees + ((prev_degrees + current_degrees) - prev_degrees) / 2
|
60
64
|
|
61
|
-
|
62
|
-
|
63
|
-
# unless @hide_line_markers then
|
65
|
+
label_val = ((data_row[DATA_VALUES_INDEX].first / total_sum) * 100.0).round
|
66
|
+
unless label_val < @hide_labels_less_than
|
64
67
|
# End the string with %% to escape the single %.
|
65
68
|
# RMagick must use sprintf with the string and % has special significance.
|
66
|
-
label_string =
|
67
|
-
100.0).round.to_s + '%%'
|
69
|
+
label_string = label_val.to_s + '%%'
|
68
70
|
@d = draw_label(center_x,center_y, half_angle,
|
69
71
|
radius + (radius * TEXT_OFFSET_PERCENTAGE),
|
70
72
|
label_string)
|
71
|
-
|
73
|
+
end
|
72
74
|
|
73
75
|
prev_degrees += current_degrees
|
74
76
|
end
|
@@ -0,0 +1,268 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/base'
|
2
|
+
|
3
|
+
# Here's how to set up an XY Scatter Chart
|
4
|
+
#
|
5
|
+
# g = Gruff::Scatter.new(800)
|
6
|
+
# g.data(:apples, [1,2,3,4], [4,3,2,1])
|
7
|
+
# g.data('oranges', [5,7,8], [4,1,7])
|
8
|
+
# g.write('test/output/scatter.png')
|
9
|
+
#
|
10
|
+
#
|
11
|
+
class Gruff::Scatter < Gruff::Base
|
12
|
+
|
13
|
+
# Maximum X Value. The value will get overwritten by the max in the
|
14
|
+
# datasets.
|
15
|
+
attr_accessor :maximum_x_value
|
16
|
+
|
17
|
+
# Minimum X Value. The value will get overwritten by the min in the
|
18
|
+
# datasets.
|
19
|
+
attr_accessor :minimum_x_value
|
20
|
+
|
21
|
+
# The number of vertical lines shown for reference
|
22
|
+
attr_accessor :marker_x_count
|
23
|
+
|
24
|
+
#~ # Draw a dashed horizontal line at the given y value
|
25
|
+
#~ attr_accessor :baseline_y_value
|
26
|
+
|
27
|
+
#~ # Color of the horizontal baseline
|
28
|
+
#~ attr_accessor :baseline_y_color
|
29
|
+
|
30
|
+
#~ # Draw a dashed horizontal line at the given y value
|
31
|
+
#~ attr_accessor :baseline_x_value
|
32
|
+
|
33
|
+
#~ # Color of the horizontal baseline
|
34
|
+
#~ attr_accessor :baseline_x_color
|
35
|
+
|
36
|
+
|
37
|
+
# Gruff::Scatter takes the same parameters as the Gruff::Line graph
|
38
|
+
#
|
39
|
+
# ==== Example
|
40
|
+
#
|
41
|
+
# g = Gruff::Scatter.new
|
42
|
+
#
|
43
|
+
def initialize(*args)
|
44
|
+
super(*args)
|
45
|
+
|
46
|
+
@maximum_x_value = @minimum_x_value = nil
|
47
|
+
@baseline_x_color = @baseline_y_color = 'red'
|
48
|
+
@baseline_x_value = @baseline_y_value = nil
|
49
|
+
@marker_x_count = nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def draw
|
53
|
+
calculate_spread
|
54
|
+
@sort = false
|
55
|
+
|
56
|
+
# TODO Need to get x-axis labels working. Current behavior will be to not allow.
|
57
|
+
@labels = {}
|
58
|
+
|
59
|
+
# Translate our values so that we can use the base methods for drawing
|
60
|
+
# the standard chart stuff
|
61
|
+
@column_count = @x_spread
|
62
|
+
|
63
|
+
super
|
64
|
+
return unless @has_data
|
65
|
+
|
66
|
+
# Check to see if more than one datapoint was given. NaN can result otherwise.
|
67
|
+
@x_increment = (@column_count > 1) ? (@graph_width / (@column_count - 1).to_f) : @graph_width
|
68
|
+
|
69
|
+
#~ if (defined?(@norm_y_baseline)) then
|
70
|
+
#~ level = @graph_top + (@graph_height - @norm_baseline * @graph_height)
|
71
|
+
#~ @d = @d.push
|
72
|
+
#~ @d.stroke_color @baseline_color
|
73
|
+
#~ @d.fill_opacity 0.0
|
74
|
+
#~ @d.stroke_dasharray(10, 20)
|
75
|
+
#~ @d.stroke_width 5
|
76
|
+
#~ @d.line(@graph_left, level, @graph_left + @graph_width, level)
|
77
|
+
#~ @d = @d.pop
|
78
|
+
#~ end
|
79
|
+
|
80
|
+
#~ if (defined?(@norm_x_baseline)) then
|
81
|
+
|
82
|
+
#~ end
|
83
|
+
|
84
|
+
@norm_data.each do |data_row|
|
85
|
+
prev_x = prev_y = nil
|
86
|
+
|
87
|
+
data_row[DATA_VALUES_INDEX].each_with_index do |data_point, index|
|
88
|
+
x_value = data_row[DATA_VALUES_X_INDEX][index]
|
89
|
+
next if data_point.nil? || x_value.nil?
|
90
|
+
|
91
|
+
new_x = getXCoord(x_value, @graph_width, @graph_left)
|
92
|
+
new_y = @graph_top + (@graph_height - data_point * @graph_height)
|
93
|
+
|
94
|
+
# Reset each time to avoid thin-line errors
|
95
|
+
@d = @d.stroke data_row[DATA_COLOR_INDEX]
|
96
|
+
@d = @d.fill data_row[DATA_COLOR_INDEX]
|
97
|
+
@d = @d.stroke_opacity 1.0
|
98
|
+
@d = @d.stroke_width clip_value_if_greater_than(@columns / (@norm_data.first[1].size * 4), 5.0)
|
99
|
+
|
100
|
+
circle_radius = clip_value_if_greater_than(@columns / (@norm_data.first[1].size * 2.5), 5.0)
|
101
|
+
@d = @d.circle(new_x, new_y, new_x - circle_radius, new_y)
|
102
|
+
|
103
|
+
prev_x = new_x
|
104
|
+
prev_y = new_y
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
@d.draw(@base_image)
|
109
|
+
end
|
110
|
+
|
111
|
+
# The first parameter is the name of the dataset. The next two are the
|
112
|
+
# x and y axis data points contain in their own array in that respective
|
113
|
+
# order. The final parameter is the color.
|
114
|
+
#
|
115
|
+
# Can be called multiple times with different datasets for a multi-valued
|
116
|
+
# graph.
|
117
|
+
#
|
118
|
+
# If the color argument is nil, the next color from the default theme will
|
119
|
+
# be used.
|
120
|
+
#
|
121
|
+
# NOTE: If you want to use a preset theme, you must set it before calling
|
122
|
+
# data().
|
123
|
+
#
|
124
|
+
# ==== Parameters
|
125
|
+
# name:: String or Symbol containing the name of the dataset.
|
126
|
+
# x_data_points:: An Array of of x-axis data points.
|
127
|
+
# y_data_points:: An Array of of y-axis data points.
|
128
|
+
# color:: The hex string for the color of the dataset. Defaults to nil.
|
129
|
+
#
|
130
|
+
# ==== Exceptions
|
131
|
+
# Data points contain nil values::
|
132
|
+
# This error will get raised if either the x or y axis data points array
|
133
|
+
# contains a <tt>nil</tt> value. The graph will not make an assumption
|
134
|
+
# as how to graph <tt>nil</tt>
|
135
|
+
# x_data_points is empty::
|
136
|
+
# This error is raised when the array for the x-axis points are empty
|
137
|
+
# y_data_points is empty::
|
138
|
+
# This error is raised when the array for the y-axis points are empty
|
139
|
+
# x_data_points.length != y_data_points.length::
|
140
|
+
# Error means that the x and y axis point arrays do not match in length
|
141
|
+
#
|
142
|
+
# ==== Examples
|
143
|
+
# g = Gruff::Scatter.new
|
144
|
+
# g.data(:apples, [1,2,3], [3,2,1])
|
145
|
+
# g.data('oranges', [1,1,1], [2,3,4])
|
146
|
+
# g.data('bitter_melon', [3,5,6], [6,7,8], '#000000')
|
147
|
+
#
|
148
|
+
def data(name, x_data_points=[], y_data_points=[], color=nil)
|
149
|
+
|
150
|
+
raise ArgumentError, "Data Points contain nil Value!" if x_data_points.include?(nil) || y_data_points.include?(nil)
|
151
|
+
raise ArgumentError, "x_data_points is empty!" if x_data_points.empty?
|
152
|
+
raise ArgumentError, "y_data_points is empty!" if y_data_points.empty?
|
153
|
+
raise ArgumentError, "x_data_points.length != y_data_points.length!" if x_data_points.length != y_data_points.length
|
154
|
+
|
155
|
+
# Call the existing data routine for the y axis data
|
156
|
+
super(name, y_data_points, color)
|
157
|
+
|
158
|
+
#append the x data to the last entry that was just added in the @data member
|
159
|
+
lastElem = @data.length()-1
|
160
|
+
@data[lastElem] << x_data_points
|
161
|
+
|
162
|
+
if @maximum_x_value.nil? && @minimum_x_value.nil?
|
163
|
+
@maximum_x_value = @minimum_x_value = x_data_points.first
|
164
|
+
end
|
165
|
+
|
166
|
+
@maximum_x_value = x_data_points.max > @maximum_x_value ?
|
167
|
+
x_data_points.max : @maximum_x_value
|
168
|
+
@minimum_x_value = x_data_points.min < @minimum_x_value ?
|
169
|
+
x_data_points.min : @minimum_x_value
|
170
|
+
end
|
171
|
+
|
172
|
+
protected
|
173
|
+
|
174
|
+
def calculate_spread #:nodoc:
|
175
|
+
super
|
176
|
+
@x_spread = @maximum_x_value.to_f - @minimum_x_value.to_f
|
177
|
+
@x_spread = @x_spread > 0 ? @x_spread : 1
|
178
|
+
end
|
179
|
+
|
180
|
+
def normalize(force=@xy_normalize)
|
181
|
+
if @norm_data.nil? || force
|
182
|
+
@norm_data = []
|
183
|
+
return unless @has_data
|
184
|
+
|
185
|
+
@data.each do |data_row|
|
186
|
+
norm_data_points = [data_row[DATA_LABEL_INDEX]]
|
187
|
+
norm_data_points << data_row[DATA_VALUES_INDEX].map do |r|
|
188
|
+
(r.to_f - @minimum_value.to_f) / @spread
|
189
|
+
end
|
190
|
+
norm_data_points << data_row[DATA_COLOR_INDEX]
|
191
|
+
norm_data_points << data_row[DATA_VALUES_X_INDEX].map do |r|
|
192
|
+
(r.to_f - @minimum_x_value.to_f) / @x_spread
|
193
|
+
end
|
194
|
+
@norm_data << norm_data_points
|
195
|
+
end
|
196
|
+
end
|
197
|
+
#~ @norm_y_baseline = (@baseline_y_value.to_f / @maximum_value.to_f) if @baseline_y_value
|
198
|
+
#~ @norm_x_baseline = (@baseline_x_value.to_f / @maximum_x_value.to_f) if @baseline_x_value
|
199
|
+
end
|
200
|
+
|
201
|
+
def draw_line_markers
|
202
|
+
# do all of the stuff for the horizontal lines on the y-axis
|
203
|
+
super
|
204
|
+
return if @hide_line_markers
|
205
|
+
|
206
|
+
@d = @d.stroke_antialias false
|
207
|
+
|
208
|
+
if @x_axis_increment.nil?
|
209
|
+
# TODO Do the same for larger numbers...100, 75, 50, 25
|
210
|
+
if @marker_x_count.nil?
|
211
|
+
(3..7).each do |lines|
|
212
|
+
if @x_spread % lines == 0.0
|
213
|
+
@marker_x_count = lines
|
214
|
+
break
|
215
|
+
end
|
216
|
+
end
|
217
|
+
@marker_x_count ||= 4
|
218
|
+
end
|
219
|
+
@x_increment = (@x_spread > 0) ? significant(@x_spread / @marker_x_count) : 1
|
220
|
+
else
|
221
|
+
# TODO Make this work for negative values
|
222
|
+
@maximum_x_value = [@maximum_value.ceil, @x_axis_increment].max
|
223
|
+
@minimum_x_value = @minimum_x_value.floor
|
224
|
+
calculate_spread
|
225
|
+
normalize(true)
|
226
|
+
|
227
|
+
@marker_count = (@x_spread / @x_axis_increment).to_i
|
228
|
+
@x_increment = @x_axis_increment
|
229
|
+
end
|
230
|
+
@increment_x_scaled = @graph_width.to_f / (@x_spread / @x_increment)
|
231
|
+
|
232
|
+
# Draw vertical line markers and annotate with numbers
|
233
|
+
(0..@marker_x_count).each do |index|
|
234
|
+
x = @graph_left + @graph_width - index.to_f * @increment_x_scaled
|
235
|
+
|
236
|
+
# TODO Fix the vertical lines. Not pretty when they don't match up with top y-axis line
|
237
|
+
#~ @d = @d.stroke(@marker_color)
|
238
|
+
#~ @d = @d.stroke_width 1
|
239
|
+
#~ @d = @d.line(x, @graph_top, x, @graph_bottom)
|
240
|
+
|
241
|
+
unless @hide_line_numbers
|
242
|
+
marker_label = index * @x_increment + @minimum_x_value.to_f
|
243
|
+
y_offset = @graph_bottom + LABEL_MARGIN
|
244
|
+
x_offset = getXCoord(index.to_f, @increment_x_scaled, @graph_left)
|
245
|
+
|
246
|
+
@d.fill = @font_color
|
247
|
+
@d.font = @font if @font
|
248
|
+
@d.stroke('transparent')
|
249
|
+
@d.pointsize = scale_fontsize(@marker_font_size)
|
250
|
+
@d.gravity = NorthGravity
|
251
|
+
|
252
|
+
@d = @d.annotate_scaled(@base_image,
|
253
|
+
1.0, 1.0,
|
254
|
+
x_offset, y_offset,
|
255
|
+
label(marker_label), @scale)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
@d = @d.stroke_antialias true
|
260
|
+
end
|
261
|
+
|
262
|
+
private
|
263
|
+
|
264
|
+
def getXCoord(x_data_point, width, offset) #:nodoc:
|
265
|
+
return(x_data_point * width + offset)
|
266
|
+
end
|
267
|
+
|
268
|
+
end # end Gruff::Scatter
|
data/lib/gruff/scene.rb
CHANGED
@@ -133,7 +133,7 @@ class Gruff::Layer
|
|
133
133
|
def initialize(base_dir, folder_name)
|
134
134
|
@base_dir = base_dir.to_s
|
135
135
|
@name = folder_name.to_s
|
136
|
-
@filenames = Dir.open(File.join(base_dir, folder_name)).entries.select { |file| file =~ /^[^.]+\.png$/ }
|
136
|
+
@filenames = Dir.open(File.join(base_dir, folder_name)).entries.select { |file| file =~ /^[^.]+\.png$/ }.sort
|
137
137
|
@selected_filename = select_default
|
138
138
|
end
|
139
139
|
|
data/lib/gruff/side_bar.rb
CHANGED
@@ -5,22 +5,30 @@ require File.dirname(__FILE__) + '/base'
|
|
5
5
|
|
6
6
|
class Gruff::SideBar < Gruff::Base
|
7
7
|
|
8
|
+
# Spacing factor applied between bars
|
9
|
+
attr_accessor :bar_spacing
|
10
|
+
|
8
11
|
def draw
|
9
12
|
@has_left_labels = true
|
10
13
|
super
|
11
14
|
|
12
15
|
return unless @has_data
|
16
|
+
draw_bars
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
13
20
|
|
21
|
+
def draw_bars
|
14
22
|
# Setup spacing.
|
15
23
|
#
|
16
24
|
@bar_spacing ||= 0.9
|
17
25
|
|
18
26
|
@bars_width = @graph_height / @column_count.to_f
|
19
|
-
@bar_width = @bars_width
|
27
|
+
@bar_width = @bars_width / @norm_data.size
|
20
28
|
@d = @d.stroke_opacity 0.0
|
21
29
|
height = Array.new(@column_count, 0)
|
22
30
|
length = Array.new(@column_count, @graph_left)
|
23
|
-
padding = (@
|
31
|
+
padding = (@bar_width * (1 - @bar_spacing)) / 2
|
24
32
|
|
25
33
|
@norm_data.each_with_index do |data_row, row_index|
|
26
34
|
@d = @d.fill data_row[DATA_COLOR_INDEX]
|
@@ -37,7 +45,7 @@ class Gruff::SideBar < Gruff::Base
|
|
37
45
|
left_x = length[point_index] - 1
|
38
46
|
left_y = @graph_top + (@bars_width * point_index) + (@bar_width * row_index) + padding
|
39
47
|
right_x = left_x + difference
|
40
|
-
right_y = left_y + @bar_width
|
48
|
+
right_y = left_y + @bar_width * @bar_spacing
|
41
49
|
|
42
50
|
height[point_index] += (data_point * @graph_width)
|
43
51
|
|
@@ -53,8 +61,6 @@ class Gruff::SideBar < Gruff::Base
|
|
53
61
|
@d.draw(@base_image)
|
54
62
|
end
|
55
63
|
|
56
|
-
protected
|
57
|
-
|
58
64
|
# Instead of base class version, draws vertical background lines and label
|
59
65
|
def draw_line_markers
|
60
66
|
|
@@ -68,14 +74,14 @@ protected
|
|
68
74
|
number_of_lines = 5
|
69
75
|
|
70
76
|
# TODO Round maximum marker value to a round number like 100, 0.1, 0.5, etc.
|
71
|
-
increment = significant(@
|
77
|
+
increment = significant(@spread.to_f / number_of_lines)
|
72
78
|
(0..number_of_lines).each do |index|
|
73
79
|
|
74
80
|
line_diff = (@graph_right - @graph_left) / number_of_lines
|
75
81
|
x = @graph_right - (line_diff * index) - 1
|
76
82
|
@d = @d.line(x, @graph_bottom, x, @graph_top)
|
77
83
|
diff = index - number_of_lines
|
78
|
-
marker_label = diff.abs * increment
|
84
|
+
marker_label = diff.abs * increment + @minimum_value
|
79
85
|
|
80
86
|
unless @hide_line_numbers
|
81
87
|
@d.fill = @font_color
|