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

Methods

Included Modules

Magick Deprecated

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 170
170:     def initialize(target_width=DEFAULT_TARGET_WIDTH)
171:       @top_margin = @bottom_margin = @left_margin = @right_margin = 20.0
172: 
173:       if not Numeric === target_width
174:         geometric_width, geometric_height = target_width.split('x')
175:         @columns = geometric_width.to_f
176:         @rows = geometric_height.to_f
177:       else
178:         @columns = target_width.to_f
179:         @rows = target_width.to_f * 0.75        
180:       end
181: 
182:       initialize_ivars
183: 
184:       reset_themes
185:       theme_keynote
186:     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 250
250:     def add_color(colorname)
251:       @colors << colorname
252:     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 434
434:     def data(name, data_points=[], color=nil)
435:       data_points = Array(data_points) # make sure it's an array
436:       @data << [name, data_points, (color || increment_color)]
437:       # Set column count if this is larger than previous counts
438:       @column_count = (data_points.length > @column_count) ? data_points.length : @column_count
439: 
440:       # Pre-normalize
441:       data_points.each_with_index do |data_point, index|
442:         next if data_point.nil?
443:         
444:         # Setup max/min so spread starts at the low end of the data points
445:         if @maximum_value.nil? && @minimum_value.nil?
446:           @maximum_value = @minimum_value = data_point
447:         end
448: 
449:         # TODO Doesn't work with stacked bar graphs
450:         # Original: @maximum_value = larger_than_max?(data_point, index) ? max(data_point, index) : @maximum_value
451:         @maximum_value = larger_than_max?(data_point) ? data_point : @maximum_value
452:         @has_data = true if @maximum_value > 0
453:         
454:         @minimum_value = less_than_min?(data_point) ? data_point : @minimum_value
455:           @has_data = true if @minimum_value < 0
456:       end
457:     end

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

[Source]

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

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

[Source]

     # File lib/gruff/base.rb, line 236
236:     def margins=(margin)
237:       @top_margin = @left_margin = @right_margin = @bottom_margin = margin
238:     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 260
260:     def replace_colors(color_list=[])
261:       @colors = color_list
262:     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 277
277:     def theme=(options)
278:       reset_themes()
279:       
280:       defaults = {
281:         :colors => ['black', 'white'],
282:         :additional_line_colors => [],
283:         :marker_color => 'white',
284:         :font_color => 'black',
285:         :background_colors => nil,
286:         :background_image => nil
287:       }
288:       @theme_options = defaults.merge options
289: 
290:       @colors = @theme_options[:colors]
291:       @marker_color = @theme_options[:marker_color]
292:       @font_color = @theme_options[:font_color] || @marker_color
293:       @additional_line_colors = @theme_options[:additional_line_colors]
294:       
295:       render_background
296:     end

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

[Source]

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

A greyscale theme

[Source]

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

A color scheme similar to the popular presentation software.

[Source]

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

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

[Source]

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

A pastel theme

[Source]

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

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

[Source]

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

Return the graph as a rendered binary blob.

[Source]

     # File lib/gruff/base.rb, line 469
469:     def to_blob(fileformat='PNG')
470:       draw()
471:       return @base_image.to_blob do
472:          self.format = fileformat
473:       end
474:     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 463
463:     def write(filename="graph.png")
464:       draw()
465:       @base_image.write(filename)
466:     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 483
483:     def draw
484:       make_stacked if @stacked
485:       setup_drawing
486:       
487:       debug {
488:         # Outer margin
489:         @d.rectangle( @left_margin, @top_margin, 
490:                             @raw_columns - @right_margin, @raw_rows - @bottom_margin)
491:         # Graph area box
492:         @d.rectangle( @graph_left, @graph_top, @graph_right, @graph_bottom)
493:       }
494:     end

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

[Source]

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

Draws column labels below graph, centered over x_offset

[Source]

     # File lib/gruff/base.rb, line 797
797:     def draw_label(x_offset, index)
798:       return if @hide_line_markers
799: 
800:       if !@labels[index].nil? && @labels_seen[index].nil?
801:         y_offset = @graph_bottom + LABEL_MARGIN
802: 
803:         @d.fill = @font_color
804:         @d.font = @font if @font
805:         @d.stroke('transparent')
806:         @d.font_weight = NormalWeight
807:         @d.pointsize = scale_fontsize(@marker_font_size)
808:         @d.gravity = NorthGravity
809:         @d = @d.annotate_scaled(@base_image,
810:                                 1.0, 1.0,
811:                                 x_offset, y_offset,
812:                                 @labels[index], @scale)
813:         @labels_seen[index] = 1
814:         debug { @d.line 0.0, y_offset, @raw_columns, y_offset }
815:       end
816:     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 721
721:     def draw_legend
722:       return if @hide_legend
723: 
724:       @legend_labels = @data.collect {|item| item[DATA_LABEL_INDEX] }
725: 
726:       legend_square_width = @legend_box_size # small square with color of this item
727: 
728:       # May fix legend drawing problem at small sizes
729:       @d.font = @font if @font
730:       @d.pointsize = @legend_font_size
731: 
732:       metrics = @d.get_type_metrics(@base_image, @legend_labels.join(''))
733:       legend_text_width = metrics.width
734:       legend_width = legend_text_width + 
735:                     (@legend_labels.length * legend_square_width * 2.7)
736:       legend_left = (@raw_columns - legend_width) / 2
737:       legend_increment = legend_width / @legend_labels.length.to_f
738: 
739:       current_x_offset = legend_left
740:       current_y_offset =  @hide_title ? 
741:                           @top_margin + LEGEND_MARGIN : 
742:                           @top_margin + 
743:                           TITLE_MARGIN + @title_caps_height +
744:                           LEGEND_MARGIN
745: 
746:       debug { @d.line 0.0, current_y_offset, @raw_columns, current_y_offset }
747:                                                     
748:       @legend_labels.each_with_index do |legend_label, index|        
749: 
750:         # Draw label
751:         @d.fill = @font_color
752:         @d.font = @font if @font
753:         @d.pointsize = scale_fontsize(@legend_font_size)
754:         @d.stroke('transparent')
755:         @d.font_weight = NormalWeight
756:         @d.gravity = WestGravity
757:         @d = @d.annotate_scaled( @base_image, 
758:                           @raw_columns, 1.0,
759:                           current_x_offset + (legend_square_width * 1.7), current_y_offset, 
760:                           legend_label.to_s, @scale)
761:         
762:         # Now draw box with color of this dataset
763:         @d = @d.stroke('transparent')
764:         @d = @d.fill @data[index][DATA_COLOR_INDEX]
765:         @d = @d.rectangle(current_x_offset, 
766:                           current_y_offset - legend_square_width / 2.0, 
767:                           current_x_offset + legend_square_width, 
768:                           current_y_offset + legend_square_width / 2.0)
769: 
770:         @d.pointsize = @legend_font_size
771:         metrics = @d.get_type_metrics(@base_image, legend_label.to_s)
772:         current_string_offset = metrics.width + (legend_square_width * 2.7)
773:         current_x_offset += current_string_offset
774:       end
775:       @color_index = 0
776:     end

Draws horizontal background lines and labels

[Source]

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

Shows an error message because you have no data.

[Source]

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

Draws a title on the graph.

[Source]

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

Used by StackedBar and child classes.

May need to be moved to the StackedBar class.

[Source]

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

Make copy of data with values scaled between 0-100

[Source]

     # File lib/gruff/base.rb, line 519
519:     def normalize(force=false)
520:       if @norm_data.nil? || force
521:         @norm_data = []
522:         return unless @has_data
523:                 
524:         calculate_spread
525:         
526:         @data.each do |data_row|
527:           norm_data_points = []
528:           data_row[DATA_VALUES_INDEX].each do |data_point|
529:             if data_point.nil?
530:               norm_data_points << nil
531:             else
532:               norm_data_points << ((data_point.to_f - @minimum_value.to_f ) / @spread)
533:             end
534:           end
535:           @norm_data << [data_row[DATA_LABEL_INDEX], norm_data_points, data_row[DATA_COLOR_INDEX]]
536:         end
537:       end
538:     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 835
835:     def render_background
836:       case @theme_options[:background_colors]
837:       when Array
838:         @base_image = render_gradiated_background(*@theme_options[:background_colors])
839:       when String
840:         @base_image = render_solid_background(@theme_options[:background_colors])
841:       else
842:         @base_image = render_image_background(*@theme_options[:background_image])
843:       end
844:     end

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

[Source]

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

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

[Source]

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

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

[Source]

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

Use with a theme to make a transparent background

[Source]

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

Resets everything to defaults (except data).

[Source]

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

Return a comparable fontsize for the current graph.

[Source]

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

Calculates size of drawable area and draws the decorations.

  • line markers
  • legend
  • title

[Source]

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

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

[Source]

     # File lib/gruff/base.rb, line 546
546:     def setup_graph_measurements
547:       @marker_caps_height = @hide_line_markers ? 0 :
548:                               calculate_caps_height(@marker_font_size)
549:       @title_caps_height = @hide_title ? 0 :
550:                               calculate_caps_height(@title_font_size)
551:       @legend_caps_height = @hide_legend ? 0 :
552:                               calculate_caps_height(@legend_font_size)
553: 
554:       if @hide_line_markers
555:         (@graph_left,
556:          @graph_right_margin,
557:          @graph_bottom_margin) = [@left_margin, @right_margin, @bottom_margin]
558:       else
559:         longest_left_label_width = 0
560:         if @has_left_labels
561:           longest_left_label_width =  calculate_width(@marker_font_size,
562:                                       labels.values.inject('') { |value, memo| (value.to_s.length > memo.to_s.length) ? value : memo }) * 1.25
563:         else
564:           longest_left_label_width = calculate_width(@marker_font_size, 
565:                           label(@maximum_value.to_f))
566:         end
567: 
568:         # Shift graph if left line numbers are hidden
569:         line_number_width = @hide_line_numbers && !@has_left_labels ? 
570:                               0.0 : 
571:                               (longest_left_label_width + LABEL_MARGIN * 2)
572: 
573:         @graph_left = @left_margin + 
574:                       line_number_width + 
575:                       (@y_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN * 2)
576:         # Make space for half the width of the rightmost column label.
577:         # Might be greater than the number of columns if between-style bar markers are used.
578:         last_label = @labels.keys.sort.last.to_i
579:         extra_room_for_long_label = (last_label >= (@column_count-1) && @center_labels_over_point) ?
580:           calculate_width(@marker_font_size, @labels[last_label])/2.0 :
581:           0
582:         @graph_right_margin =   @right_margin + extra_room_for_long_label
583:                                 
584:         @graph_bottom_margin =  @bottom_margin + 
585:                                 @marker_caps_height + LABEL_MARGIN
586:       end
587: 
588:       @graph_right = @raw_columns - @graph_right_margin
589:       @graph_width = @raw_columns - @graph_left - @graph_right_margin
590: 
591:       # When @hide title, leave a TITLE_MARGIN space for aesthetics.
592:       # Same with @hide_legend
593:       @graph_top = @top_margin + 
594:                     (@hide_title ? TITLE_MARGIN : @title_caps_height + TITLE_MARGIN * 2) +
595:                     (@hide_legend ? LEGEND_MARGIN : @legend_caps_height + LEGEND_MARGIN * 2)
596: 
597:       x_axis_label_height = @x_axis_label.nil? ? 0.0 :
598:                               @marker_caps_height + LABEL_MARGIN
599:       @graph_bottom = @raw_rows - @graph_bottom_margin - x_axis_label_height
600:       @graph_height = @graph_bottom - @graph_top
601:     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 943
943:     def sort_norm_data
944:       @norm_data.sort! { |a,b| sums(b[1]) <=> sums(a[1]) }
945:     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 1035
1035:     def calculate_caps_height(font_size)
1036:       @d.pointsize = font_size
1037:       @d.get_type_metrics(@base_image, 'X').height
1038:     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 1044
1044:     def calculate_width(font_size, text)
1045:       @d.pointsize = font_size
1046:       @d.get_type_metrics(@base_image, text.to_s).width
1047:     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 989
989:     def debug
990:       if DEBUG
991:         @d = @d.fill 'transparent'
992:         @d = @d.stroke 'turquoise'
993:         @d = yield
994:       end
995:     end

Uses the next color in your color list.

[Source]

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

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

[Source]

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

[Validate]