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 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
Add a color to the list of available colors for lines.
Example:
add_color('#c0e9d3')
# 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')
# 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.
# 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.
# 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.
# 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']
# 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.)
# 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.
# 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
# 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.
# 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.
# 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
# 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.
# 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.
# 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')
# File lib/gruff/base.rb, line 463 463: def write(filename="graph.png") 464: draw() 465: @base_image.write(filename) 466: 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 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.
# 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
# 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.
# 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
# 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.
# 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.
# 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.
# 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
# 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.
# 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 to use an image (800x600 original) background.
# 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
Use with a theme to make a transparent background
# 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).
# 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.
# 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.
# 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.
# 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.
# 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
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 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.
# 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 }
# 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.
# 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.
# 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