Class | Gruff::Base |
In: |
lib/gruff/base.rb
|
Parent: | Object |
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 |
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 |
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.)
# 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
Add a color to the list of available colors for lines.
Example:
add_color('#c0e9d3')
# 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')
# 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.
# 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.
# 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.
# 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']
# 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.)
# 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.
# 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
# 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.
# 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.
# 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
# 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.
# 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.
# 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')
# File lib/gruff/base.rb, line 462 462: def write(filename="graph.png") 463: draw() 464: @base_image.write(filename) 465: end
Overridden by subclasses to do the actual plotting of the graph.
Subclasses should start by calling super() for this method.
# 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.
# 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
# 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.
# 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
# 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.
# 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.
# 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.
# 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
# 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.
# 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 to use an image (800x600 original) background.
# 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
Use with a theme to make a transparent background
# 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).
# 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.
# 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.
# 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.
# 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.
# 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
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.
# 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.
# 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 }
# 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.
# 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.
# 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