Browse files

Merge pull request #12 from BRIMIL01/bar_updates

Bar updates
  • Loading branch information...
2 parents 104d361 + 5259be2 commit cf1e0907fdcb9cada1664015db6c42030028cfaf @donv donv committed Nov 29, 2012
Showing with 143 additions and 12 deletions.
  1. +5 −0 lib/gruff/bar.rb
  2. +62 −4 lib/gruff/base.rb
  3. +17 −5 lib/gruff/side_bar.rb
  4. +17 −3 lib/gruff/side_stacked_bar.rb
  5. +1 −0 test/gruff_test_case.rb
  6. +12 −0 test/test_bar.rb
  7. +13 −0 test/test_side_bar.rb
  8. +16 −0 test/test_sidestacked_bar.rb
View
5 lib/gruff/bar.rb
@@ -88,8 +88,13 @@ def draw_bars
label_center = @graph_left +
(@data.length * @bar_width * point_index) +
(@data.length * @bar_width / 2.0)
+
# Subtract half a bar width to center left if requested
draw_label(label_center - (@center_labels_over_point ? @bar_width / 2.0 : 0.0), point_index)
+ if @show_labels_for_bar_values
+ val = (@label_formatting || "%.2f") % @norm_data[row_index][3][point_index]
+ draw_value_label(left_x + (right_x - left_x)/2, conv[0]-30, val.commify, true)
+ end
end
end
View
66 lib/gruff/base.rb
@@ -96,7 +96,7 @@ class Base
# How truncated labels visually appear if they exceed label_max_size
# :absolute - does not show trailing dots to indicate truncation. This is
# the default.
- # :trailing_dots - shows trailing dots to indicate truncation (note
+ # :trailing_dots - shows trailing dots to indicate truncation (note
# that label_max_size must be greater than 3).
attr_accessor :label_truncation_style
@@ -185,6 +185,17 @@ class Base
# Will be scaled down if graph is smaller than 800px wide.
attr_accessor :legend_box_size
+ # Output the values for the bars on a bar graph
+ # Default is false
+ attr_accessor :show_labels_for_bar_values
+
+ # Set the number output format for labels using sprintf
+ # Default is "%.2f"
+ attr_accessor :label_formatting
+
+ # With Side Bars use the data label for the marker value to the left of the bar
+ # Default is false
+ attr_accessor :use_data_label
# If one numerical argument is given, the graph is drawn at 4/3 ratio
# according to the given width (800 results in 800x600, 400 gives 400x300,
# etc.).
@@ -246,7 +257,7 @@ def initialize_ivars
@no_data_message = "No Data"
- @hide_line_markers = @hide_legend = @hide_title = @hide_line_numbers = @legend_at_bottom = false
+ @hide_line_markers = @hide_legend = @hide_title = @hide_line_numbers = @legend_at_bottom = @show_labels_for_bar_values = false
@center_labels_over_point = true
@has_left_labels = false
@label_stagger_height = 0
@@ -473,7 +484,7 @@ def normalize(force=false)
norm_data_points << ((data_point.to_f - @minimum_value.to_f) / @spread)
end
end
- @norm_data << [data_row[DATA_LABEL_INDEX], norm_data_points, data_row[DATA_COLOR_INDEX]]
+ @norm_data << [data_row[DATA_LABEL_INDEX], norm_data_points, data_row[DATA_COLOR_INDEX], data_row[DATA_VALUES_INDEX]]
end
end
end
@@ -597,7 +608,7 @@ def draw_line_markers
end
@marker_count ||= 4
end
- @increment = (@spread > 0) ? significant(@spread / @marker_count) : 1
+ @increment = (@spread > 0 && @marker_count > 0) ? significant(@spread / @marker_count) : 1
else
# TODO Make this work for negative values
@maximum_value = [@maximum_value.ceil, @y_axis_increment].max
@@ -816,6 +827,46 @@ def draw_label(x_offset, index)
debug { @d.line 0.0, y_offset, @raw_columns, y_offset }
end
end
+
+ # Draws the data value over the data point in bar graphs
+ def draw_value_label(x_offset, y_offset, data_point, bar_value=false)
+ return if @hide_line_markers && !bar_value
+
+ #y_offset = @graph_bottom + LABEL_MARGIN
+
+ @d.fill = @font_color
+ @d.font = @font if @font
+ @d.stroke('transparent')
+ @d.font_weight = NormalWeight
+ @d.pointsize = scale_fontsize(@marker_font_size)
+ @d.gravity = NorthGravity
+ @d = @d.annotate_scaled(@base_image,
+ 1.0, 1.0,
+ x_offset, y_offset,
+ data_point.to_s, @scale)
+
+ debug { @d.line 0.0, y_offset, @raw_columns, y_offset }
+ end
+
+ # Draws the data value over the data point in bar graphs
+ def draw_value_label(x_offset, y_offset, data_point, bar_value=false)
+ return if @hide_line_markers && !bar_value
+
+ #y_offset = @graph_bottom + LABEL_MARGIN
+
+ @d.fill = @font_color
+ @d.font = @font if @font
+ @d.stroke('transparent')
+ @d.font_weight = NormalWeight
+ @d.pointsize = scale_fontsize(@marker_font_size)
+ @d.gravity = NorthGravity
+ @d = @d.annotate_scaled(@base_image,
+ 1.0, 1.0,
+ x_offset, y_offset,
+ data_point.to_s, @scale)
+
+ debug { @d.line 0.0, y_offset, @raw_columns, y_offset }
+ end
# Shows an error message because you have no data.
def draw_no_data
@@ -1081,3 +1132,10 @@ def annotate_scaled(img, width, height, x, y, text, scale)
end
end # Magick
+
+class String
+ #Taken from http://codesnippets.joyent.com/posts/show/330
+ def commify(delimiter=",")
+ return self.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}")
+ end
+end
View
22 lib/gruff/side_bar.rb
@@ -57,8 +57,18 @@ def draw_bars
@d = @d.rectangle(left_x, left_y, right_x, right_y)
# Calculate center based on bar_width and current row
- label_center = @graph_top + (@bars_width * point_index + @bars_width / 2)
- draw_label(label_center, point_index)
+
+ if @use_data_label
+ label_center = @graph_top + (@bar_width * (row_index+point_index) + @bar_width / 2)
+ draw_label(label_center, row_index, @norm_data[row_index][DATA_LABEL_INDEX])
+ else
+ label_center = @graph_top + (@bars_width * point_index + @bars_width / 2)
+ draw_label(label_center, point_index)
+ end
+ if @show_labels_for_bar_values
+ val = (@label_formatting || "%.2f") % @norm_data[row_index][3][point_index]
+ draw_value_label(right_x+40, (@graph_top + (((row_index+point_index+1) * @bar_width) - (@bar_width / 2)))-12, val.commify, true)
+ end
end
end
@@ -76,7 +86,8 @@ def draw_line_markers
# Draw horizontal line markers and annotate with numbers
@d = @d.stroke(@marker_color)
@d = @d.stroke_width 1
- number_of_lines = 5
+ number_of_lines = @marker_count || 5
+ number_of_lines = 1 if number_of_lines == 0
# TODO Round maximum marker value to a round number like 100, 0.1, 0.5, etc.
increment = significant(@spread.to_f / number_of_lines)
@@ -107,8 +118,9 @@ def draw_line_markers
##
# Draw on the Y axis instead of the X
- def draw_label(y_offset, index)
+ def draw_label(y_offset, index, label=nil)
if !@labels[index].nil? && @labels_seen[index].nil?
+ lbl = (@use_data_label) ? label : @labels[index]
@d.fill = @font_color
@d.font = @font if @font
@d.stroke = 'transparent'
@@ -118,7 +130,7 @@ def draw_label(y_offset, index)
@d = @d.annotate_scaled(@base_image,
1, 1,
-@graph_left + LABEL_MARGIN * 2.0, y_offset,
- @labels[index], @scale)
+ lbl, @scale)
@labels_seen[index] = 1
end
end
View
20 lib/gruff/side_stacked_bar.rb
@@ -33,7 +33,10 @@ def draw_bars
height = Array.new(@column_count, 0)
length = Array.new(@column_count, @graph_left)
padding = (@bar_width * (1 - @bar_spacing)) / 2
-
+ if @show_labels_for_bar_values
+ label_values = Array.new
+ 0.upto(@column_count-1) {|i| label_values[i] = {:value => 0, :right_x => 0}}
+ end
@norm_data.each_with_index do |data_row, row_index|
data_row[DATA_VALUES_INDEX].each_with_index do |data_point, point_index|
@@ -53,7 +56,12 @@ def draw_bars
right_y = left_y + @bar_width * @bar_spacing
length[point_index] += difference
height[point_index] += (data_point * @graph_width - 2)
-
+
+ if @show_labels_for_bar_values
+ label_values[point_index][:value] += @norm_data[row_index][3][point_index]
+ label_values[point_index][:right_x] = right_x
+ end
+
# if a data point is 0 it can result in weird really thing lines
# that shouldn't even be there being drawn on top of the existing
# bar - this is bad
@@ -68,7 +76,13 @@ def draw_bars
end
end
-
+ if @show_labels_for_bar_values
+ label_values.each_with_index do |data, i|
+ val = (@label_formatting || "%.2f") % data[:value]
+ draw_value_label(data[:right_x]+40, (@graph_top + (((i+1) * @bar_width) - (@bar_width / 2)))-12, val.commify, true)
+ end
+ end
+
@d.draw(@base_image)
end
View
1 test/gruff_test_case.rb
@@ -124,6 +124,7 @@ def setup_basic_graph(*args)
g = klass.new(size)
g.title = "My Bar Graph"
g.labels = @labels
+ g.font = "/Library/Fonts/Verdana.ttf"
@datasets.each do |data|
View
12 test/test_bar.rb
@@ -444,6 +444,18 @@ def test_set_label_max_size_and_label_truncation_style
g.write("test/output/bar_set_trailing_dots_trunc.png")
end
+ def test_bar_value_labels
+ g = setup_basic_graph
+ g.show_labels_for_bar_values = true
+ g.write("test/output/bar_value_labels.png")
+ end
+
+ def test_zero_marker_count
+ g = setup_basic_graph
+ g.marker_count = 0
+ g.write("test/output/bar_zero_marker_count.png")
+ end
+
protected
def setup_basic_graph(size=800)
View
13 test/test_side_bar.rb
@@ -38,6 +38,19 @@ def test_x_axis_range
g.labels = {0 => '2003', 2 => '2004', 4 => '2005'}
g.write("test/output/side_bar_data_range.png")
end
+
+ def test_bar_labels
+ g = Gruff::SideBar.new('400x300')
+ g.title = 'Should show labels for each bar'
+ g.data("Grapes", [8])
+ g.data("Apples", [24])
+ g.data("Oranges", [32])
+ g.data("Watermelon", [8])
+ g.data("Peaches", [12])
+ g.labels = {0 => '2003', 2 => '2004', 4 => '2005'}
+ g.show_labels_for_bar_values = true
+ g.write("test/output/side_bar_labels.png")
+ end
end
View
16 test/test_sidestacked_bar.rb
@@ -72,6 +72,22 @@ def test_should_space_long_left_labels_appropriately
end
g.write "test/output/side_stacked_bar_long_label.png"
end
+
+ def test_bar_labels
+ g = Gruff::SideStackedBar.new
+ g.title = "Stacked Bar Long Label"
+ g.labels = {
+ 0 => 'September',
+ 1 => 'Oct',
+ 2 => 'Nov',
+ 3 => 'Dec',
+ }
+ @datasets.each do |data|
+ g.data(data[0], data[1])
+ end
+ g.show_labels_for_bar_values = true
+ g.write "test/output/side_stacked_bar_labels.png"
+ end
protected

0 comments on commit cf1e090

Please sign in to comment.