Class Gruff::Base
In: lib/gruff/base.rb
Parent: Object
StackedMixin StackedBar SideStackedBar StackedArea AccumulatorBar Base Scene Pie Area Spider PhotoBar SideBar Net Bar Line Pie Observable Group StandardError IncorrectNumberOfDatasetsException Magick SideBar Bar Layer BarConversion lib/gruff/photo_bar.rb lib/gruff/base.rb lib/gruff/accumulator_bar.rb lib/gruff/scene.rb lib/gruff/spider.rb lib/gruff/side_bar.rb lib/gruff/line.rb lib/gruff/net.rb lib/gruff/pie.rb lib/gruff/bar_conversion.rb lib/gruff/side_stacked_bar.rb lib/gruff/area.rb lib/gruff/stacked_bar.rb lib/gruff/bar.rb lib/gruff/stacked_area.rb lib/gruff/mini/bar.rb lib/gruff/mini/pie.rb lib/gruff/mini/side_bar.rb Legend Mini Deprecated Gruff dot/m_10_0.png

Methods

Included Modules

Magick Deprecated

Classes and Modules

Module Gruff::Base::StackedMixin

Constants

DEBUG = false   Draw extra lines showing where the margins and text centers are
DATA_LABEL_INDEX = 0   Used for navigating the array of data to plot
DATA_VALUES_INDEX = 1
DATA_COLOR_INDEX = 2
LEGEND_MARGIN = TITLE_MARGIN = LABEL_MARGIN = 10.0   Space around text elements. Mostly used for vertical spacing
DEFAULT_TARGET_WIDTH = 800

Attributes

additional_line_values  [RW]  Experimental
bottom_margin  [RW]  Blank space below the graph
center_labels_over_point  [RW]  Used internally for spacing.

By default, labels are centered over the point they represent.

colors  [RW]  Get or set the list of colors that will be used to draw the bars or lines.
font  [R]  Font used for titles, labels, etc. Works best if you provide the full path to the TTF font file. RMagick must be built with the Freetype libraries for this to work properly.

Tries to find Bitstream Vera (Vera.ttf) in the location specified by ENV[‘MAGICK_FONT_PATH’]. Uses default RMagick font otherwise.

The font= method below fulfills the role of the writer, so we only need a reader here.

font_color  [RW] 
has_left_labels  [RW]  Used internally for horizontal graph types.
hide_legend  [RW]  Prevent drawing of the legend
hide_line_markers  [RW]  Prevent drawing of line markers
hide_line_numbers  [RW]  Prevent drawing of line numbers
hide_title  [RW]  Prevent drawing of the title
labels  [RW]  A hash of names for the individual columns, where the key is the array index for the column this label represents.

Not all columns need to be named.

Example: 0 => 2005, 3 => 2006, 5 => 2007, 7 => 2008

left_margin  [RW]  Blank space to the left of the graph
legend_box_size  [RW]  Optionally set the size of the colored box by each item in the legend. Default is 20.0

Will be scaled down if graph is smaller than 800px wide.

legend_font_size  [RW]  Optionally set the size of the font. Based on an 800x600px graph. Default is 20.

Will be scaled down if graph is smaller than 800px wide.

marker_color  [RW]  The color of the auxiliary lines
marker_count  [RW]  The number of horizontal lines shown for reference
marker_font_size  [RW]  The font size of the labels around the graph
maximum_value  [RW]  You can manually set a maximum value, such as a percentage-based graph that always goes to 100.

If you use this, you must set it after you have given all your data to the graph object.

minimum_value  [RW]  You can manually set a minimum value instead of having the values guessed for you.

Set it after you have given all your data to the graph object.

no_data_message  [RW]  Message shown when there is no data. Fits up to 20 characters. Defaults to "No Data."
right_margin  [RW]  Blank space to the right of the graph
sort  [RW]  Set to false if you don‘t want the data to be sorted with largest avg values at the back.
stacked  [RW]  Experimental
title  [RW]  The large title of the graph displayed at the top
title_font_size  [RW]  The font size of the large title at the top of the graph
top_margin  [RW]  Blank space above the graph
x_axis_label  [RW]  A label for the bottom of the graph
y_axis_increment  [RW]  Manually set increment of the horizontal marking lines
y_axis_label  [RW]  A label for the left side of the graph

Public Class methods

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.).

Or, send a geometry string for other ratios (‘800x400’, ‘400x225’).

Looks for Bitstream Vera as the default font. Expects an environment var of MAGICK_FONT_PATH to be set. (Uses RMagick‘s default font otherwise.)

[Source]

     # File lib/gruff/base.rb, line 169
169:     def initialize(target_width=DEFAULT_TARGET_WIDTH)
170:       @top_margin = @bottom_margin = @left_margin = @right_margin = 20.0
171: 
172:       if not Numeric === target_width
173:         geometric_width, geometric_height = target_width.split('x')
174:         @columns = geometric_width.to_f
175:         @rows = geometric_height.to_f
176:       else
177:         @columns = target_width.to_f
178:         @rows = target_width.to_f * 0.75        
179:       end
180: 
181:       initialize_ivars
182: 
183:       reset_themes
184:       theme_keynote
185:     end

Public Instance methods

Add a color to the list of available colors for lines.

Example:

 add_color('#c0e9d3')

[Source]

     # File lib/gruff/base.rb, line 249
249:     def add_color(colorname)
250:       @colors << colorname
251:     end

Parameters are an array where the first element is the name of the dataset and the value is an array of values to plot.

Can be called multiple times with different datasets for a multi-valued graph.

If the color argument is nil, the next color from the default theme will be used.

NOTE: If you want to use a preset theme, you must set it before calling data().

Example:

  data("Bart S.", [95, 45, 78, 89, 88, 76], '#ffcc00')

[Source]

     # File lib/gruff/base.rb, line 433
433:     def data(name, data_points=[], color=nil)
434:       data_points = Array(data_points) # make sure it's an array
435:       @data << [name, data_points, (color || increment_color)]
436:       # Set column count if this is larger than previous counts
437:       @column_count = (data_points.length > @column_count) ? data_points.length : @column_count
438: 
439:       # Pre-normalize
440:       data_points.each_with_index do |data_point, index|
441:         next if data_point.nil?
442:         
443:         # Setup max/min so spread starts at the low end of the data points
444:         if @maximum_value.nil? && @minimum_value.nil?
445:           @maximum_value = @minimum_value = data_point
446:         end
447: 
448:         # TODO Doesn't work with stacked bar graphs
449:         # Original: @maximum_value = larger_than_max?(data_point, index) ? max(data_point, index) : @maximum_value
450:         @maximum_value = larger_than_max?(data_point) ? data_point : @maximum_value
451:         @has_data = true if @maximum_value > 0
452:         
453:         @minimum_value = less_than_min?(data_point) ? data_point : @minimum_value
454:           @has_data = true if @minimum_value < 0
455:       end
456:     end

Sets the font for graph text to the font at font_path.

[Source]

     # File lib/gruff/base.rb, line 240
240:     def font=(font_path)
241:       @font = font_path
242:       @d.font = @font
243:     end

Set instance variables for this object.

Subclasses can override this, call super, then set values separately.

This makes it possible to set defaults in a subclass but still allow developers to change this values in their program.

[Source]

     # File lib/gruff/base.rb, line 193
193:     def initialize_ivars
194:       # Internal for calculations
195:       @raw_columns = 800.0
196:       @raw_rows = 800.0 * (@rows/@columns)
197:       @column_count = 0
198:       @marker_count = nil
199:       @maximum_value = @minimum_value = nil
200:       @has_data = false
201:       @data = Array.new
202:       @labels = Hash.new
203:       @labels_seen = Hash.new
204:       @sort = true
205:       @title = nil
206: 
207:       @scale = @columns / @raw_columns
208: 
209:       vera_font_path = File.expand_path('Vera.ttf', ENV['MAGICK_FONT_PATH'])
210:       @font = File.exists?(vera_font_path) ? vera_font_path : nil
211: 
212:       @marker_font_size = 21.0
213:       @legend_font_size = 20.0
214:       @title_font_size = 36.0
215:       
216:       @legend_box_size = 20.0
217: 
218:       @no_data_message = "No Data"
219: 
220:       @hide_line_markers = @hide_legend = @hide_title = @hide_line_numbers = false
221:       @center_labels_over_point = true
222:       @has_left_labels = false
223: 
224:       @additional_line_values = []      
225:       @additional_line_colors = []
226:       @theme_options = {}
227:       
228:       @x_axis_label = @y_axis_label = nil
229:       @y_axis_increment = nil
230:       @stacked = nil
231:       @norm_data = nil
232:     end

Sets the top, bottom, left and right margins to margin.

[Source]

     # File lib/gruff/base.rb, line 235
235:     def margins=(margin)
236:       @top_margin = @left_margin = @right_margin = @bottom_margin = margin
237:     end

Replace the entire color list with a new array of colors. You need to have one more color than the number of datasets you intend to draw. Also aliased as the colors= setter method.

Example:

 replace_colors ['#cc99cc', '#d9e043', '#34d8a2']

[Source]

     # File lib/gruff/base.rb, line 259
259:     def replace_colors(color_list=[])
260:       @colors = color_list
261:     end

You can set a theme manually. Assign a hash to this method before you send your data.

 graph.theme = {
   :colors => %w(orange purple green white red),
   :marker_color => 'blue',
   :background_colors => %w(black grey)
 }

:background_image => ‘squirrel.png’ is also possible.

(Or hopefully something better looking than that.)

[Source]

     # File lib/gruff/base.rb, line 276
276:     def theme=(options)
277:       reset_themes()
278:       
279:       defaults = {
280:         :colors => ['black', 'white'],
281:         :additional_line_colors => [],
282:         :marker_color => 'white',
283:         :font_color => 'black',
284:         :background_colors => nil,
285:         :background_image => nil
286:       }
287:       @theme_options = defaults.merge options
288: 
289:       @colors = @theme_options[:colors]
290:       @marker_color = @theme_options[:marker_color]
291:       @font_color = @theme_options[:font_color] || @marker_color
292:       @additional_line_colors = @theme_options[:additional_line_colors]
293:       
294:       render_background
295:     end

A color scheme plucked from the colors on the popular usability blog.

[Source]

     # File lib/gruff/base.rb, line 318
318:     def theme_37signals
319:       # Colors
320:       @green = '#339933'
321:       @purple = '#cc99cc'
322:       @blue = '#336699'
323:       @yellow = '#FFF804'
324:       @red = '#ff0000'
325:       @orange = '#cf5910'
326:       @black = 'black'
327:       @colors = [@yellow, @blue, @green, @red, @purple, @orange, @black]
328: 
329:       self.theme = {
330:         :colors => @colors,
331:         :marker_color => 'black',
332:         :font_color => 'black',
333:         :background_colors => ['#d1edf5', 'white']
334:       }
335:     end

A greyscale theme

[Source]

     # File lib/gruff/base.rb, line 400
400:     def theme_greyscale
401:       # Colors
402:       @colors = [
403:           '#282828', # 
404:           '#383838', # 
405:           '#686868', # 
406:           '#989898', # 
407:           '#c8c8c8', # 
408:           '#e8e8e8', # 
409:         ]
410:       
411:       self.theme = {
412:         :colors => @colors,
413:         :marker_color => '#aea9a9', # Grey
414:         :font_color => 'black',
415:         :background_colors => 'white'
416:       }
417:     end

A color scheme similar to the popular presentation software.

[Source]

     # File lib/gruff/base.rb, line 298
298:     def theme_keynote
299:       # Colors
300:       @blue = '#6886B4'
301:       @yellow = '#FDD84E'
302:       @green = '#72AE6E'
303:       @red = '#D1695E'
304:       @purple = '#8A6EAF'
305:       @orange = '#EFAA43'
306:       @white = 'white'
307:       @colors = [@yellow, @blue, @green, @red, @purple, @orange, @white]
308: 
309:       self.theme = {
310:         :colors => @colors,
311:         :marker_color => 'white',
312:         :font_color => 'white',
313:         :background_colors => ['black', '#4a465a']
314:       }
315:     end

A color scheme similar to that used on the popular podcast site.

[Source]

     # File lib/gruff/base.rb, line 359
359:     def theme_odeo
360:       # Colors
361:       @grey = '#202020'
362:       @white = 'white'
363:       @dark_pink = '#a21764'
364:       @green = '#8ab438'
365:       @light_grey = '#999999'
366:       @dark_blue = '#3a5b87'
367:       @black = 'black'
368:       @colors = [@grey, @white, @dark_blue, @dark_pink, @green, @light_grey, @black]
369:       
370:       self.theme = {
371:         :colors => @colors,
372:         :marker_color => 'white',
373:         :font_color => 'white',
374:         :background_colors => ['#ff47a4', '#ff1f81']
375:       }
376:     end

A pastel theme

[Source]

     # File lib/gruff/base.rb, line 379
379:     def theme_pastel
380:       # Colors
381:       @colors = [
382:           '#a9dada', # blue
383:           '#aedaa9', # green
384:           '#daaea9', # peach
385:           '#dadaa9', # yellow
386:           '#a9a9da', # dk purple
387:           '#daaeda', # purple
388:           '#dadada' # grey
389:         ]
390:       
391:       self.theme = {
392:         :colors => @colors,
393:         :marker_color => '#aea9a9', # Grey
394:         :font_color => 'black',
395:         :background_colors => 'white'
396:       }
397:     end

A color scheme from the colors used on the 2005 Rails keynote presentation at RubyConf.

[Source]

     # File lib/gruff/base.rb, line 339
339:     def theme_rails_keynote
340:       # Colors
341:       @green = '#00ff00'
342:       @grey = '#333333'
343:       @orange = '#ff5d00'
344:       @red = '#f61100'
345:       @white = 'white'
346:       @light_grey = '#999999'
347:       @black = 'black'
348:       @colors = [@green, @grey, @orange, @red, @white, @light_grey, @black]
349:       
350:       self.theme = {
351:         :colors => @colors,
352:         :marker_color => 'white',
353:         :font_color => 'white',
354:         :background_colors => ['#0083a3', '#0083a3']
355:       }
356:     end

Return the graph as a rendered binary blob.

[Source]

     # File lib/gruff/base.rb, line 468
468:     def to_blob(fileformat='PNG')
469:       draw()
470:       return @base_image.to_blob do
471:          self.format = fileformat
472:       end
473:     end

Writes the graph to a file. Defaults to ‘graph.png‘

Example:

  write('graphs/my_pretty_graph.png')

[Source]

     # File lib/gruff/base.rb, line 462
462:     def write(filename="graph.png")
463:       draw()
464:       @base_image.write(filename)
465:     end

Protected Instance methods

Overridden by subclasses to do the actual plotting of the graph.

Subclasses should start by calling super() for this method.

[Source]

     # File lib/gruff/base.rb, line 480
480:     def draw
481:       make_stacked if @stacked
482:       setup_drawing
483:       
484:       debug {
485:         # Outer margin
486:         @d.rectangle( @left_margin, @top_margin, 
487:                             @raw_columns - @right_margin, @raw_rows - @bottom_margin)
488:         # Graph area box
489:         @d.rectangle( @graph_left, @graph_top, @graph_right, @graph_bottom)
490:       }
491:     end

Draw the optional labels for the x axis and y axis.

[Source]

     # File lib/gruff/base.rb, line 601
601:     def draw_axis_labels
602:       unless @x_axis_label.nil?
603:         # X Axis
604:         # Centered vertically and horizontally by setting the
605:         # height to 1.0 and the width to the width of the graph.
606:         x_axis_label_y_coordinate = @graph_bottom + LABEL_MARGIN * 2 + @marker_caps_height
607: 
608:         # TODO Center between graph area
609:         @d.fill = @font_color
610:         @d.font = @font if @font
611:         @d.stroke('transparent')
612:         @d.pointsize = scale_fontsize(@marker_font_size)
613:         @d.gravity = NorthGravity
614:         @d = @d.annotate_scaled( @base_image, 
615:                           @raw_columns, 1.0, 
616:                           0.0, x_axis_label_y_coordinate, 
617:                           @x_axis_label, @scale)
618:         debug { @d.line 0.0, x_axis_label_y_coordinate, @raw_columns, x_axis_label_y_coordinate }
619:       end
620: 
621:       unless @y_axis_label.nil?
622:         # Y Axis, rotated vertically
623:         @d.rotation = 90.0
624:         @d.gravity = CenterGravity
625:         @d = @d.annotate_scaled( @base_image, 
626:                           1.0, @raw_rows,
627:                           @left_margin + @marker_caps_height / 2.0, 0.0, 
628:                           @y_axis_label, @scale)
629:         @d.rotation = -90.0
630:       end
631:     end

Draws column labels below graph, centered over x_offset

[Source]

     # File lib/gruff/base.rb, line 794
794:     def draw_label(x_offset, index)
795:       return if @hide_line_markers
796: 
797:       if !@labels[index].nil? && @labels_seen[index].nil?
798:         y_offset = @graph_bottom + LABEL_MARGIN
799: 
800:         @d.fill = @font_color
801:         @d.font = @font if @font
802:         @d.stroke('transparent')
803:         @d.font_weight = NormalWeight
804:         @d.pointsize = scale_fontsize(@marker_font_size)
805:         @d.gravity = NorthGravity
806:         @d = @d.annotate_scaled(@base_image,
807:                                 1.0, 1.0,
808:                                 x_offset, y_offset,
809:                                 @labels[index], @scale)
810:         @labels_seen[index] = 1
811:         debug { @d.line 0.0, y_offset, @raw_columns, y_offset }
812:       end
813:     end

Draws a legend with the names of the datasets matched to the colors used to draw them.

[Source]

     # File lib/gruff/base.rb, line 718
718:     def draw_legend
719:       return if @hide_legend
720: 
721:       @legend_labels = @data.collect {|item| item[DATA_LABEL_INDEX] }
722: 
723:       legend_square_width = @legend_box_size # small square with color of this item
724: 
725:       # May fix legend drawing problem at small sizes
726:       @d.font = @font if @font
727:       @d.pointsize = @legend_font_size
728: 
729:       metrics = @d.get_type_metrics(@base_image, @legend_labels.join(''))
730:       legend_text_width = metrics.width
731:       legend_width = legend_text_width + 
732:                     (@legend_labels.length * legend_square_width * 2.7)
733:       legend_left = (@raw_columns - legend_width) / 2
734:       legend_increment = legend_width / @legend_labels.length.to_f
735: 
736:       current_x_offset = legend_left
737:       current_y_offset =  @hide_title ? 
738:                           @top_margin + LEGEND_MARGIN : 
739:                           @top_margin + 
740:                           TITLE_MARGIN + @title_caps_height +
741:                           LEGEND_MARGIN
742: 
743:       debug { @d.line 0.0, current_y_offset, @raw_columns, current_y_offset }
744:                                                     
745:       @legend_labels.each_with_index do |legend_label, index|        
746: 
747:         # Draw label
748:         @d.fill = @font_color
749:         @d.font = @font if @font
750:         @d.pointsize = scale_fontsize(@legend_font_size)
751:         @d.stroke('transparent')
752:         @d.font_weight = NormalWeight
753:         @d.gravity = WestGravity
754:         @d = @d.annotate_scaled( @base_image, 
755:                           @raw_columns, 1.0,
756:                           current_x_offset + (legend_square_width * 1.7), current_y_offset, 
757:                           legend_label.to_s, @scale)
758:         
759:         # Now draw box with color of this dataset
760:         @d = @d.stroke('transparent')
761:         @d = @d.fill @data[index][DATA_COLOR_INDEX]
762:         @d = @d.rectangle(current_x_offset, 
763:                           current_y_offset - legend_square_width / 2.0, 
764:                           current_x_offset + legend_square_width, 
765:                           current_y_offset + legend_square_width / 2.0)
766: 
767:         @d.pointsize = @legend_font_size
768:         metrics = @d.get_type_metrics(@base_image, legend_label.to_s)
769:         current_string_offset = metrics.width + (legend_square_width * 2.7)
770:         current_x_offset += current_string_offset
771:       end
772:       @color_index = 0
773:     end

Draws horizontal background lines and labels

[Source]

     # File lib/gruff/base.rb, line 634
634:     def draw_line_markers
635:       return if @hide_line_markers
636:       
637:       @d = @d.stroke_antialias false
638:             
639:       if @y_axis_increment.nil?
640:         # Try to use a number of horizontal lines that will come out even.
641:         #
642:         # TODO Do the same for larger numbers...100, 75, 50, 25
643:         if @marker_count.nil?
644:           (3..7).each do |lines|
645:             if @spread % lines == 0.0
646:               @marker_count = lines
647:               break
648:             end
649:           end
650:           @marker_count ||= 4
651:         end
652:         @increment = (@spread > 0) ? significant(@spread / @marker_count) : 1
653:       else
654:         # TODO Make this work for negative values
655:         @maximum_value = [@maximum_value.ceil, @y_axis_increment].max
656:         @minimum_value = @minimum_value.floor
657:         calculate_spread
658:         normalize(true)
659:         
660:         @marker_count = (@spread / @y_axis_increment).to_i
661:         @increment = @y_axis_increment
662:       end
663:       @increment_scaled = @graph_height.to_f / (@spread / @increment)
664: 
665:       # Draw horizontal line markers and annotate with numbers
666:       (0..@marker_count).each do |index|
667:         y = @graph_top + @graph_height - index.to_f * @increment_scaled
668:         
669:         @d = @d.stroke(@marker_color)
670:         @d = @d.stroke_width 1
671:         @d = @d.line(@graph_left, y, @graph_right, y)
672: 
673:         marker_label = index * @increment + @minimum_value.to_f
674: 
675:         unless @hide_line_numbers
676:           @d.fill = @font_color
677:           @d.font = @font if @font
678:           @d.stroke('transparent')
679:           @d.pointsize = scale_fontsize(@marker_font_size)
680:           @d.gravity = EastGravity
681:         
682:           # Vertically center with 1.0 for the height
683:           @d = @d.annotate_scaled( @base_image, 
684:                             @graph_left - LABEL_MARGIN, 1.0,
685:                             0.0, y,
686:                             label(marker_label), @scale)
687:         end
688:       end
689:       
690:       # # Submitted by a contibutor...the utility escapes me
691:       # i = 0
692:       # @additional_line_values.each do |value|
693:       #   @increment_scaled = @graph_height.to_f / (@maximum_value.to_f / value)
694:       # 
695:       #   y = @graph_top + @graph_height - @increment_scaled
696:       # 
697:       #   @d = @d.stroke(@additional_line_colors[i])
698:       #   @d = @d.line(@graph_left, y, @graph_right, y)
699:       # 
700:       # 
701:       #   @d.fill = @additional_line_colors[i]
702:       #   @d.font = @font if @font
703:       #   @d.stroke('transparent')
704:       #   @d.pointsize = scale_fontsize(@marker_font_size)
705:       #   @d.gravity = EastGravity
706:       #   @d = @d.annotate_scaled( @base_image, 
707:       #                     100, 20,
708:       #                     -10, y - (@marker_font_size/2.0), 
709:       #                     "", @scale)
710:       #   i += 1   
711:       # end
712:       
713:       @d = @d.stroke_antialias true
714:     end

Shows an error message because you have no data.

[Source]

     # File lib/gruff/base.rb, line 816
816:     def draw_no_data
817:         @d.fill = @font_color
818:         @d.font = @font if @font
819:         @d.stroke('transparent')
820:         @d.font_weight = NormalWeight
821:         @d.pointsize = scale_fontsize(80)
822:         @d.gravity = CenterGravity
823:         @d = @d.annotate_scaled( @base_image, 
824:                         @raw_columns, @raw_rows/2.0,
825:                         0, 10, 
826:                         @no_data_message, @scale)
827:     end

Draws a title on the graph.

[Source]

     # File lib/gruff/base.rb, line 776
776:     def draw_title
777:       return if (@hide_title || @title.nil?)
778: 
779:       @d.fill = @font_color
780:       @d.font = @font if @font
781:       @d.stroke('transparent')
782:       @d.pointsize = scale_fontsize(@title_font_size)
783:       @d.font_weight = BoldWeight
784:       @d.gravity = NorthGravity
785:       @d = @d.annotate_scaled( @base_image, 
786:                         @raw_columns, 1.0,
787:                         0, @top_margin, 
788:                         @title, @scale)
789:     end

Used by StackedBar and child classes.

May need to be moved to the StackedBar class.

[Source]

     # File lib/gruff/base.rb, line 953
953:     def get_maximum_by_stack
954:       # Get sum of each stack
955:       max_hash = {}
956:       @data.each do |data_set|
957:         data_set[DATA_VALUES_INDEX].each_with_index do |data_point, i|
958:           max_hash[i] = 0.0 unless max_hash[i]
959:           max_hash[i] += data_point.to_f
960:         end
961:       end
962: 
963:       # @maximum_value = 0
964:       max_hash.keys.each do |key|
965:         @maximum_value = max_hash[key] if max_hash[key] > @maximum_value
966:       end
967:       @minimum_value = 0
968:     end

Make copy of data with values scaled between 0-100

[Source]

     # File lib/gruff/base.rb, line 516
516:     def normalize(force=false)
517:       if @norm_data.nil? || force
518:         @norm_data = []
519:         return unless @has_data
520:                 
521:         calculate_spread
522:         
523:         @data.each do |data_row|
524:           norm_data_points = []
525:           data_row[DATA_VALUES_INDEX].each do |data_point|
526:             if data_point.nil?
527:               norm_data_points << nil
528:             else
529:               norm_data_points << ((data_point.to_f - @minimum_value.to_f ) / @spread)
530:             end
531:           end
532:           @norm_data << [data_row[DATA_LABEL_INDEX], norm_data_points, data_row[DATA_COLOR_INDEX]]
533:         end
534:       end
535:     end

Finds the best background to render based on the provided theme options.

Creates a @base_image to draw on.

[Source]

     # File lib/gruff/base.rb, line 832
832:     def render_background
833:       case @theme_options[:background_colors]
834:       when Array
835:         @base_image = render_gradiated_background(*@theme_options[:background_colors])
836:       when String
837:         @base_image = render_solid_background(@theme_options[:background_colors])
838:       else
839:         @base_image = render_image_background(*@theme_options[:background_image])
840:       end
841:     end

Use with a theme definition method to draw a gradiated background.

[Source]

     # File lib/gruff/base.rb, line 851
851:     def render_gradiated_background(top_color, bottom_color)
852:       Image.new(@columns, @rows, 
853:           GradientFill.new(0, 0, 100, 0, top_color, bottom_color))
854:     end

Use with a theme to use an image (800x600 original) background.

[Source]

     # File lib/gruff/base.rb, line 857
857:     def render_image_background(image_path)
858:       image = Image.read(image_path)
859:       if @scale != 1.0
860:         image[0].resize!(@scale) # TODO Resize with new scale (crop if necessary for wide graph)
861:       end
862:       image[0]
863:     end

Make a new image at the current size with a solid color.

[Source]

     # File lib/gruff/base.rb, line 844
844:     def render_solid_background(color)
845:       Image.new(@columns, @rows) {
846:         self.background_color = color
847:       }
848:     end

Use with a theme to make a transparent background

[Source]

     # File lib/gruff/base.rb, line 866
866:     def render_transparent_background
867:       Image.new(@columns, @rows) do
868:         self.background_color = 'transparent'
869:       end
870:     end

Resets everything to defaults (except data).

[Source]

     # File lib/gruff/base.rb, line 873
873:     def reset_themes
874:       @color_index = 0
875:       @labels_seen = {}
876:       @theme_options = {}
877: 
878:       @d = Draw.new
879:       # Scale down from 800x600 used to calculate drawing.
880:       @d = @d.scale(@scale, @scale)
881:     end

Return a comparable fontsize for the current graph.

[Source]

     # File lib/gruff/base.rb, line 888
888:     def scale_fontsize(value)
889:       new_fontsize = value * @scale
890:       # return new_fontsize < 10.0 ? 10.0 : new_fontsize
891:       return new_fontsize
892:     end

Calculates size of drawable area and draws the decorations.

  • line markers
  • legend
  • title

[Source]

     # File lib/gruff/base.rb, line 498
498:     def setup_drawing
499:       # Maybe should be done in one of the following functions for more granularity.
500:       unless @has_data
501:         draw_no_data()
502:         return
503:       end
504:       
505:       normalize()
506:       setup_graph_measurements()
507:       sort_norm_data() if @sort # Sort norm_data with avg largest values set first (for display)
508:       
509:       draw_legend()
510:       draw_line_markers()
511:       draw_axis_labels()
512:       draw_title
513:     end

Calculates size of drawable area, general font dimensions, etc.

[Source]

     # File lib/gruff/base.rb, line 543
543:     def setup_graph_measurements
544:       @marker_caps_height = @hide_line_markers ? 0 :
545:                               calculate_caps_height(@marker_font_size)
546:       @title_caps_height = @hide_title ? 0 :
547:                               calculate_caps_height(@title_font_size)
548:       @legend_caps_height = @hide_legend ? 0 :
549:                               calculate_caps_height(@legend_font_size)
550: 
551:       if @hide_line_markers
552:         (@graph_left,
553:          @graph_right_margin,
554:          @graph_bottom_margin) = [@left_margin, @right_margin, @bottom_margin]
555:       else
556:         longest_left_label_width = 0
557:         if @has_left_labels
558:           longest_left_label_width =  calculate_width(@marker_font_size,
559:                                       labels.values.inject('') { |value, memo| (value.to_s.length > memo.to_s.length) ? value : memo }) * 1.25
560:         else
561:           longest_left_label_width = calculate_width(@marker_font_size, 
562:                           label(@maximum_value.to_f))
563:         end
564: 
565:         # Shift graph if left line numbers are hidden
566:         line_number_width = @hide_line_numbers && !@has_left_labels ? 
567:                               0.0 : 
568:                               (longest_left_label_width + LABEL_MARGIN * 2)
569: 
570:         @graph_left = @left_margin + 
571:                       line_number_width + 
572:                       (@y_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN * 2)
573:         # Make space for half the width of the rightmost column label.
574:         # Might be greater than the number of columns if between-style bar markers are used.
575:         last_label = @labels.keys.sort.last.to_i
576:         extra_room_for_long_label = (last_label >= (@column_count-1) && @center_labels_over_point) ?
577:           calculate_width(@marker_font_size, @labels[last_label])/2.0 :
578:           0
579:         @graph_right_margin =   @right_margin + extra_room_for_long_label
580:                                 
581:         @graph_bottom_margin =  @bottom_margin + 
582:                                 @marker_caps_height + LABEL_MARGIN
583:       end
584: 
585:       @graph_right = @raw_columns - @graph_right_margin
586:       @graph_width = @raw_columns - @graph_left - @graph_right_margin
587: 
588:       # When @hide title, leave a TITLE_MARGIN space for aesthetics.
589:       # Same with @hide_legend
590:       @graph_top = @top_margin + 
591:                     (@hide_title ? TITLE_MARGIN : @title_caps_height + TITLE_MARGIN * 2) +
592:                     (@hide_legend ? LEGEND_MARGIN : @legend_caps_height + LEGEND_MARGIN * 2)
593: 
594:       x_axis_label_height = @x_axis_label.nil? ? 0.0 :
595:                               @marker_caps_height + LABEL_MARGIN
596:       @graph_bottom = @raw_rows - @graph_bottom_margin - x_axis_label_height
597:       @graph_height = @graph_bottom - @graph_top
598:     end

Sort with largest overall summed value at front of array so it shows up correctly in the drawn graph.

[Source]

     # File lib/gruff/base.rb, line 940
940:     def sort_norm_data
941:       @norm_data.sort! { |a,b| sums(b[1]) <=> sums(a[1]) }
942:     end

Private Instance methods

Returns the height of the capital letter ‘X’ for the current font and size.

Not scaled since it deals with dimensions that the regular scaling will handle.

[Source]

      # File lib/gruff/base.rb, line 1032
1032:     def calculate_caps_height(font_size)
1033:       @d.pointsize = font_size
1034:       @d.get_type_metrics(@base_image, 'X').height
1035:     end

Returns the width of a string at this pointsize.

Not scaled since it deals with dimensions that the regular scaling will handle.

[Source]

      # File lib/gruff/base.rb, line 1041
1041:     def calculate_width(font_size, text)
1042:       @d.pointsize = font_size
1043:       @d.get_type_metrics(@base_image, text.to_s).width
1044:     end

Takes a block and draws it if DEBUG is true.

Example:

  debug { @d.rectangle x1, y1, x2, y2 }

[Source]

     # File lib/gruff/base.rb, line 986
986:     def debug
987:       if DEBUG
988:         @d = @d.fill 'transparent'
989:         @d = @d.stroke 'turquoise'
990:         @d = yield
991:       end
992:     end

Uses the next color in your color list.

[Source]

      # File lib/gruff/base.rb, line 995
 995:     def increment_color
 996:       if @color_index == 0
 997:         @color_index += 1
 998:         return @colors[0]
 999:       else
1000:         if @color_index < @colors.length
1001:           @color_index += 1
1002:           return @colors[@color_index - 1]
1003:         else
1004:           # Start over
1005:           @color_index = 0
1006:           return @colors[-1]
1007:         end
1008:       end
1009:     end

Return a formatted string representing a number value that should be printed as a label.

[Source]

      # File lib/gruff/base.rb, line 1013
1013:     def label(value)
1014:       if (@spread.to_f % @marker_count.to_f == 0) || !@y_axis_increment.nil?
1015:         return value.to_i.to_s
1016:       end
1017: 
1018:       if @spread > 10.0
1019:         sprintf("%0i", value)
1020:       elsif @spread >= 3.0
1021:         sprintf("%0.2f", value)
1022:       else
1023:         value.to_s
1024:       end
1025:     end

[Validate]