class Gruff::Pie

Here's how to make a Pie graph:

g = Gruff::Pie.new
g.title = "Visual Pie Graph Test"
g.data 'Fries', 20
g.data 'Hamburgers', 50
g.write("test/output/pie_keynote.png")

To control where the pie chart starts creating slices, use zero_degree.

Constants

DEFAULT_TEXT_OFFSET_PERCENTAGE

Attributes

hide_labels_less_than[RW]

Do not show labels for slices that are less than this percent. Use 0 to always show all labels. Defaults to 0

show_values_as_labels[RW]

Use values instead of percentages

text_offset_percentage[RW]

Affect the distance between the percentages and the pie chart Defaults to 0.15

zero_degree[RW]

Can be used to make the pie start cutting slices at the top (-90.0) or at another angle. Default is 0.0, which starts at 3 o'clock.

Public Instance Methods

draw() click to toggle source
Calls superclass method Gruff::Base#draw
# File lib/gruff/pie.rb, line 38
def draw
  @hide_line_markers = true
  
  super

  return unless @has_data

  diameter = @graph_height
  radius = ([@graph_width, @graph_height].min / 2.0) * 0.8
  center_x = @graph_left + (@graph_width / 2.0)
  center_y = @graph_top + (@graph_height / 2.0) - 10 # Move graph up a bit
  total_sum = sums_for_pie()
  prev_degrees = @zero_degree

  # Use full data since we can easily calculate percentages
  data = (@sort ? @data.sort{ |a, b| a[DATA_VALUES_INDEX].first <=> b[DATA_VALUES_INDEX].first } : @data)
  data.each do |data_row|
    if data_row[DATA_VALUES_INDEX].first > 0
      @d = @d.stroke data_row[DATA_COLOR_INDEX]
      @d = @d.fill 'transparent'
      @d.stroke_width(radius) # stroke width should be equal to radius. we'll draw centered on (radius / 2)

      current_degrees = (data_row[DATA_VALUES_INDEX].first / total_sum) * 360.0 

      # ellipse will draw the the stroke centered on the first two parameters offset by the second two.
      # therefore, in order to draw a circle of the proper diameter we must center the stroke at
      # half the radius for both x and y
      @d = @d.ellipse(center_x, center_y, 
                radius / 2.0, radius / 2.0,
                prev_degrees, prev_degrees + current_degrees + 0.5) # <= +0.5 'fudge factor' gets rid of the ugly gaps
                
      half_angle = prev_degrees + ((prev_degrees + current_degrees) - prev_degrees) / 2
      
      label_val = ((data_row[DATA_VALUES_INDEX].first / total_sum) * 100.0).round
      unless label_val < @hide_labels_less_than
        # RMagick must use sprintf with the string and % has special significance.
        label_string = @show_values_as_labels ? data_row[DATA_VALUES_INDEX].first.to_s : label_val.to_s + '%'
        @d = draw_label(center_x,center_y, half_angle,
                        radius + (radius * @text_offset_percentage),
                        label_string)
      end

      prev_degrees += current_degrees
    end
  end

  # TODO debug a circle where the text is drawn...
  
  @d.draw(@base_image)
end
initialize_ivars() click to toggle source
Calls superclass method Gruff::Base#initialize_ivars
# File lib/gruff/pie.rb, line 30
def initialize_ivars
  super
  @zero_degree = 0.0
  @hide_labels_less_than = 0.0
  @text_offset_percentage = DEFAULT_TEXT_OFFSET_PERCENTAGE
  @show_values_as_labels = false
end

Private Instance Methods

draw_label(center_x, center_y, angle, radius, amount) click to toggle source

Labels are drawn around a slightly wider ellipse to give room for labels on the left and right.

# File lib/gruff/pie.rb, line 94
def draw_label(center_x, center_y, angle, radius, amount)
  # TODO Don't use so many hard-coded numbers
  r_offset = 20.0      # The distance out from the center of the pie to get point
  x_offset = center_x  # + 15.0 # The label points need to be tweaked slightly
  y_offset = center_y  # This one doesn't though
  radius_offset = (radius + r_offset)
  ellipse_factor = radius_offset * @text_offset_percentage
  x = x_offset + ((radius_offset + ellipse_factor) * Math.cos(deg2rad(angle)))
  y = y_offset + (radius_offset * Math.sin(deg2rad(angle)))
  
  # Draw label
  @d.fill = @font_color
  @d.font = @font if @font
  @d.pointsize = scale_fontsize(@marker_font_size)
  @d.stroke = 'transparent'
  @d.font_weight = BoldWeight
  @d.gravity = CenterGravity
  @d.annotate_scaled( @base_image, 
                    0, 0,
                    x, y, 
                    amount, @scale)
end
sums_for_pie() click to toggle source
# File lib/gruff/pie.rb, line 117
def sums_for_pie
  total_sum = 0.0
  @data.collect {|data_row| total_sum += data_row[DATA_VALUES_INDEX].first }
  total_sum
end