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 = 20.0 | Space around text elements. Mostly used for vertical spacing | |
LABEL_MARGIN | = | 10.0 | ||
DEFAULT_MARGIN | = | 20.0 | ||
DEFAULT_TARGET_WIDTH | = | 800 | ||
THOUSAND_SEPARATOR | = | ',' |
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. |
legend_margin | [RW] | Blank space below the legend |
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 |
title_margin | [RW] | Blank space below the title |
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 182 182: def initialize(target_width=DEFAULT_TARGET_WIDTH) 183: if not Numeric === target_width 184: geometric_width, geometric_height = target_width.split('x') 185: @columns = geometric_width.to_f 186: @rows = geometric_height.to_f 187: else 188: @columns = target_width.to_f 189: @rows = target_width.to_f * 0.75 190: end 191: 192: initialize_ivars 193: 194: reset_themes 195: theme_keynote 196: end
Add a color to the list of available colors for lines.
Example:
add_color('#c0e9d3')
# File lib/gruff/base.rb, line 264 264: def add_color(colorname) 265: @colors << colorname 266: 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 457 457: def data(name, data_points=[], color=nil) 458: data_points = Array(data_points) # make sure it's an array 459: @data << [name, data_points, (color || increment_color)] 460: # Set column count if this is larger than previous counts 461: @column_count = (data_points.length > @column_count) ? data_points.length : @column_count 462: 463: # Pre-normalize 464: data_points.each_with_index do |data_point, index| 465: next if data_point.nil? 466: 467: # Setup max/min so spread starts at the low end of the data points 468: if @maximum_value.nil? && @minimum_value.nil? 469: @maximum_value = @minimum_value = data_point 470: end 471: 472: # TODO Doesn't work with stacked bar graphs 473: # Original: @maximum_value = larger_than_max?(data_point, index) ? max(data_point, index) : @maximum_value 474: @maximum_value = larger_than_max?(data_point) ? data_point : @maximum_value 475: @has_data = true if @maximum_value >= 0 476: 477: @minimum_value = less_than_min?(data_point) ? data_point : @minimum_value 478: @has_data = true if @minimum_value < 0 479: end 480: end
Sets the font for graph text to the font at font_path.
# File lib/gruff/base.rb, line 255 255: def font=(font_path) 256: @font = font_path 257: @d.font = @font 258: 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 204 204: def initialize_ivars 205: # Internal for calculations 206: @raw_columns = 800.0 207: @raw_rows = 800.0 * (@rows/@columns) 208: @column_count = 0 209: @marker_count = nil 210: @maximum_value = @minimum_value = nil 211: @has_data = false 212: @data = Array.new 213: @labels = Hash.new 214: @labels_seen = Hash.new 215: @sort = true 216: @title = nil 217: 218: @scale = @columns / @raw_columns 219: 220: vera_font_path = File.expand_path('Vera.ttf', ENV['MAGICK_FONT_PATH']) 221: @font = File.exists?(vera_font_path) ? vera_font_path : nil 222: 223: @marker_font_size = 21.0 224: @legend_font_size = 20.0 225: @title_font_size = 36.0 226: 227: @top_margin = @bottom_margin = @left_margin = @right_margin = DEFAULT_MARGIN 228: @legend_margin = LEGEND_MARGIN 229: @title_margin = TITLE_MARGIN 230: 231: @legend_box_size = 20.0 232: 233: @no_data_message = "No Data" 234: 235: @hide_line_markers = @hide_legend = @hide_title = @hide_line_numbers = false 236: @center_labels_over_point = true 237: @has_left_labels = false 238: 239: @additional_line_values = [] 240: @additional_line_colors = [] 241: @theme_options = {} 242: 243: @x_axis_label = @y_axis_label = nil 244: @y_axis_increment = nil 245: @stacked = nil 246: @norm_data = nil 247: end
Sets the top, bottom, left and right margins to margin.
# File lib/gruff/base.rb, line 250 250: def margins=(margin) 251: @top_margin = @left_margin = @right_margin = @bottom_margin = margin 252: end
Replace the entire color list with a new array of colors. Also aliased as the colors= setter method.
If you specify fewer colors than the number of datasets you intend to draw, ‘increment_color’ will cycle through the array, reusing colors as needed.
Note that (as with the ‘theme’ method), you should set up your color list before you send your data (via the ‘data’ method). Calls to the ‘data’ method made prior to this call will use whatever color scheme was in place at the time data was called.
Example:
replace_colors ['#cc99cc', '#d9e043', '#34d8a2']
# File lib/gruff/base.rb, line 282 282: def replace_colors(color_list=[]) 283: @colors = color_list 284: @color_index = 0 285: 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 300 300: def theme=(options) 301: reset_themes() 302: 303: defaults = { 304: :colors => ['black', 'white'], 305: :additional_line_colors => [], 306: :marker_color => 'white', 307: :font_color => 'black', 308: :background_colors => nil, 309: :background_image => nil 310: } 311: @theme_options = defaults.merge options 312: 313: @colors = @theme_options[:colors] 314: @marker_color = @theme_options[:marker_color] 315: @font_color = @theme_options[:font_color] || @marker_color 316: @additional_line_colors = @theme_options[:additional_line_colors] 317: 318: render_background 319: end
A color scheme plucked from the colors on the popular usability blog.
# File lib/gruff/base.rb, line 342 342: def theme_37signals 343: # Colors 344: @green = '#339933' 345: @purple = '#cc99cc' 346: @blue = '#336699' 347: @yellow = '#FFF804' 348: @red = '#ff0000' 349: @orange = '#cf5910' 350: @black = 'black' 351: @colors = [@yellow, @blue, @green, @red, @purple, @orange, @black] 352: 353: self.theme = { 354: :colors => @colors, 355: :marker_color => 'black', 356: :font_color => 'black', 357: :background_colors => ['#d1edf5', 'white'] 358: } 359: end
A greyscale theme
# File lib/gruff/base.rb, line 424 424: def theme_greyscale 425: # Colors 426: @colors = [ 427: '#282828', # 428: '#383838', # 429: '#686868', # 430: '#989898', # 431: '#c8c8c8', # 432: '#e8e8e8', # 433: ] 434: 435: self.theme = { 436: :colors => @colors, 437: :marker_color => '#aea9a9', # Grey 438: :font_color => 'black', 439: :background_colors => 'white' 440: } 441: end
A color scheme similar to the popular presentation software.
# File lib/gruff/base.rb, line 322 322: def theme_keynote 323: # Colors 324: @blue = '#6886B4' 325: @yellow = '#FDD84E' 326: @green = '#72AE6E' 327: @red = '#D1695E' 328: @purple = '#8A6EAF' 329: @orange = '#EFAA43' 330: @white = 'white' 331: @colors = [@yellow, @blue, @green, @red, @purple, @orange, @white] 332: 333: self.theme = { 334: :colors => @colors, 335: :marker_color => 'white', 336: :font_color => 'white', 337: :background_colors => ['black', '#4a465a'] 338: } 339: end
A color scheme similar to that used on the popular podcast site.
# File lib/gruff/base.rb, line 383 383: def theme_odeo 384: # Colors 385: @grey = '#202020' 386: @white = 'white' 387: @dark_pink = '#a21764' 388: @green = '#8ab438' 389: @light_grey = '#999999' 390: @dark_blue = '#3a5b87' 391: @black = 'black' 392: @colors = [@grey, @white, @dark_blue, @dark_pink, @green, @light_grey, @black] 393: 394: self.theme = { 395: :colors => @colors, 396: :marker_color => 'white', 397: :font_color => 'white', 398: :background_colors => ['#ff47a4', '#ff1f81'] 399: } 400: end
A pastel theme
# File lib/gruff/base.rb, line 403 403: def theme_pastel 404: # Colors 405: @colors = [ 406: '#a9dada', # blue 407: '#aedaa9', # green 408: '#daaea9', # peach 409: '#dadaa9', # yellow 410: '#a9a9da', # dk purple 411: '#daaeda', # purple 412: '#dadada' # grey 413: ] 414: 415: self.theme = { 416: :colors => @colors, 417: :marker_color => '#aea9a9', # Grey 418: :font_color => 'black', 419: :background_colors => 'white' 420: } 421: end
A color scheme from the colors used on the 2005 Rails keynote presentation at RubyConf.
# File lib/gruff/base.rb, line 363 363: def theme_rails_keynote 364: # Colors 365: @green = '#00ff00' 366: @grey = '#333333' 367: @orange = '#ff5d00' 368: @red = '#f61100' 369: @white = 'white' 370: @light_grey = '#999999' 371: @black = 'black' 372: @colors = [@green, @grey, @orange, @red, @white, @light_grey, @black] 373: 374: self.theme = { 375: :colors => @colors, 376: :marker_color => 'white', 377: :font_color => 'white', 378: :background_colors => ['#0083a3', '#0083a3'] 379: } 380: end
Return the graph as a rendered binary blob.
# File lib/gruff/base.rb, line 492 492: def to_blob(fileformat='PNG') 493: draw() 494: return @base_image.to_blob do 495: self.format = fileformat 496: end 497: end
Writes the graph to a file. Defaults to ‘graph.png‘
Example:
write('graphs/my_pretty_graph.png')
# File lib/gruff/base.rb, line 486 486: def write(filename="graph.png") 487: draw() 488: @base_image.write(filename) 489: 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 506 506: def draw 507: make_stacked if @stacked 508: setup_drawing 509: 510: debug { 511: # Outer margin 512: @d.rectangle( @left_margin, @top_margin, 513: @raw_columns - @right_margin, @raw_rows - @bottom_margin) 514: # Graph area box 515: @d.rectangle( @graph_left, @graph_top, @graph_right, @graph_bottom) 516: } 517: end
Draw the optional labels for the x axis and y axis.
# File lib/gruff/base.rb, line 630 630: def draw_axis_labels 631: unless @x_axis_label.nil? 632: # X Axis 633: # Centered vertically and horizontally by setting the 634: # height to 1.0 and the width to the width of the graph. 635: x_axis_label_y_coordinate = @graph_bottom + LABEL_MARGIN * 2 + @marker_caps_height 636: 637: # TODO Center between graph area 638: @d.fill = @font_color 639: @d.font = @font if @font 640: @d.stroke('transparent') 641: @d.pointsize = scale_fontsize(@marker_font_size) 642: @d.gravity = NorthGravity 643: @d = @d.annotate_scaled( @base_image, 644: @raw_columns, 1.0, 645: 0.0, x_axis_label_y_coordinate, 646: @x_axis_label, @scale) 647: debug { @d.line 0.0, x_axis_label_y_coordinate, @raw_columns, x_axis_label_y_coordinate } 648: end 649: 650: unless @y_axis_label.nil? 651: # Y Axis, rotated vertically 652: @d.rotation = 90.0 653: @d.gravity = CenterGravity 654: @d = @d.annotate_scaled( @base_image, 655: 1.0, @raw_rows, 656: @left_margin + @marker_caps_height / 2.0, 0.0, 657: @y_axis_label, @scale) 658: @d.rotation = -90.0 659: end 660: end
Draws column labels below graph, centered over x_offset
# File lib/gruff/base.rb, line 857 857: def draw_label(x_offset, index) 858: return if @hide_line_markers 859: 860: if !@labels[index].nil? && @labels_seen[index].nil? 861: y_offset = @graph_bottom + LABEL_MARGIN 862: 863: @d.fill = @font_color 864: @d.font = @font if @font 865: @d.stroke('transparent') 866: @d.font_weight = NormalWeight 867: @d.pointsize = scale_fontsize(@marker_font_size) 868: @d.gravity = NorthGravity 869: @d = @d.annotate_scaled(@base_image, 870: 1.0, 1.0, 871: x_offset, y_offset, 872: @labels[index], @scale) 873: @labels_seen[index] = 1 874: debug { @d.line 0.0, y_offset, @raw_columns, y_offset } 875: end 876: end
Draws a legend with the names of the datasets matched to the colors used to draw them.
# File lib/gruff/base.rb, line 764 764: def draw_legend 765: return if @hide_legend 766: 767: @legend_labels = @data.collect {|item| item[DATA_LABEL_INDEX] } 768: 769: legend_square_width = @legend_box_size # small square with color of this item 770: 771: # May fix legend drawing problem at small sizes 772: @d.font = @font if @font 773: @d.pointsize = @legend_font_size 774: 775: label_widths = [[]] # Used to calculate line wrap 776: @legend_labels.each do |label| 777: metrics = @d.get_type_metrics(@base_image, label.to_s) 778: label_width = metrics.width + legend_square_width * 2.7 779: label_widths.last.push label_width 780: 781: if sum(label_widths.last) > (@raw_columns * 0.9) 782: label_widths.push [label_widths.last.pop] 783: end 784: end 785: 786: current_x_offset = center(sum(label_widths.first)) 787: current_y_offset = @hide_title ? 788: @top_margin + title_margin : 789: @top_margin + title_margin + @title_caps_height 790: 791: @legend_labels.each_with_index do |legend_label, index| 792: 793: # Draw label 794: @d.fill = @font_color 795: @d.font = @font if @font 796: @d.pointsize = scale_fontsize(@legend_font_size) 797: @d.stroke('transparent') 798: @d.font_weight = NormalWeight 799: @d.gravity = WestGravity 800: @d = @d.annotate_scaled( @base_image, 801: @raw_columns, 1.0, 802: current_x_offset + (legend_square_width * 1.7), current_y_offset, 803: legend_label.to_s, @scale) 804: 805: # Now draw box with color of this dataset 806: @d = @d.stroke('transparent') 807: @d = @d.fill @data[index][DATA_COLOR_INDEX] 808: @d = @d.rectangle(current_x_offset, 809: current_y_offset - legend_square_width / 2.0, 810: current_x_offset + legend_square_width, 811: current_y_offset + legend_square_width / 2.0) 812: 813: @d.pointsize = @legend_font_size 814: metrics = @d.get_type_metrics(@base_image, legend_label.to_s) 815: current_string_offset = metrics.width + (legend_square_width * 2.7) 816: 817: # Handle wrapping 818: label_widths.first.shift 819: if label_widths.first.empty? 820: debug { @d.line 0.0, current_y_offset, @raw_columns, current_y_offset } 821: 822: label_widths.shift 823: current_x_offset = center(sum(label_widths.first)) unless label_widths.empty? 824: line_height = [@legend_caps_height, legend_square_width].max + legend_margin 825: if label_widths.length > 0 826: # Wrap to next line and shrink available graph dimensions 827: current_y_offset += line_height 828: @graph_top += line_height 829: @graph_height = @graph_bottom - @graph_top 830: end 831: else 832: current_x_offset += current_string_offset 833: end 834: end 835: @color_index = 0 836: end
Draws horizontal background lines and labels
# File lib/gruff/base.rb, line 663 663: def draw_line_markers 664: return if @hide_line_markers 665: 666: @d = @d.stroke_antialias false 667: 668: if @y_axis_increment.nil? 669: # Try to use a number of horizontal lines that will come out even. 670: # 671: # TODO Do the same for larger numbers...100, 75, 50, 25 672: if @marker_count.nil? 673: (3..7).each do |lines| 674: if @spread % lines == 0.0 675: @marker_count = lines 676: break 677: end 678: end 679: @marker_count ||= 4 680: end 681: @increment = (@spread > 0) ? significant(@spread / @marker_count) : 1 682: else 683: # TODO Make this work for negative values 684: @maximum_value = [@maximum_value.ceil, @y_axis_increment].max 685: @minimum_value = @minimum_value.floor 686: calculate_spread 687: normalize(true) 688: 689: @marker_count = (@spread / @y_axis_increment).to_i 690: @increment = @y_axis_increment 691: end 692: @increment_scaled = @graph_height.to_f / (@spread / @increment) 693: 694: # Draw horizontal line markers and annotate with numbers 695: (0..@marker_count).each do |index| 696: y = @graph_top + @graph_height - index.to_f * @increment_scaled 697: 698: @d = @d.fill(@marker_color) 699: @d = @d.line(@graph_left, y, @graph_right, y) 700: 701: marker_label = index * @increment + @minimum_value.to_f 702: 703: unless @hide_line_numbers 704: @d.fill = @font_color 705: @d.font = @font if @font 706: @d.stroke('transparent') 707: @d.pointsize = scale_fontsize(@marker_font_size) 708: @d.gravity = EastGravity 709: 710: # Vertically center with 1.0 for the height 711: @d = @d.annotate_scaled( @base_image, 712: @graph_left - LABEL_MARGIN, 1.0, 713: 0.0, y, 714: label(marker_label), @scale) 715: end 716: end 717: 718: # # Submitted by a contibutor...the utility escapes me 719: # i = 0 720: # @additional_line_values.each do |value| 721: # @increment_scaled = @graph_height.to_f / (@maximum_value.to_f / value) 722: # 723: # y = @graph_top + @graph_height - @increment_scaled 724: # 725: # @d = @d.stroke(@additional_line_colors[i]) 726: # @d = @d.line(@graph_left, y, @graph_right, y) 727: # 728: # 729: # @d.fill = @additional_line_colors[i] 730: # @d.font = @font if @font 731: # @d.stroke('transparent') 732: # @d.pointsize = scale_fontsize(@marker_font_size) 733: # @d.gravity = EastGravity 734: # @d = @d.annotate_scaled( @base_image, 735: # 100, 20, 736: # -10, y - (@marker_font_size/2.0), 737: # "", @scale) 738: # i += 1 739: # end 740: 741: @d = @d.stroke_antialias true 742: end
Shows an error message because you have no data.
# File lib/gruff/base.rb, line 879 879: def draw_no_data 880: @d.fill = @font_color 881: @d.font = @font if @font 882: @d.stroke('transparent') 883: @d.font_weight = NormalWeight 884: @d.pointsize = scale_fontsize(80) 885: @d.gravity = CenterGravity 886: @d = @d.annotate_scaled( @base_image, 887: @raw_columns, @raw_rows/2.0, 888: 0, 10, 889: @no_data_message, @scale) 890: end
Draws a title on the graph.
# File lib/gruff/base.rb, line 839 839: def draw_title 840: return if (@hide_title || @title.nil?) 841: 842: @d.fill = @font_color 843: @d.font = @font if @font 844: @d.stroke('transparent') 845: @d.pointsize = scale_fontsize(@title_font_size) 846: @d.font_weight = BoldWeight 847: @d.gravity = NorthGravity 848: @d = @d.annotate_scaled( @base_image, 849: @raw_columns, 1.0, 850: 0, @top_margin, 851: @title, @scale) 852: end
Used by StackedBar and child classes.
May need to be moved to the StackedBar class.
# File lib/gruff/base.rb, line 1016 1016: def get_maximum_by_stack 1017: # Get sum of each stack 1018: max_hash = {} 1019: @data.each do |data_set| 1020: data_set[DATA_VALUES_INDEX].each_with_index do |data_point, i| 1021: max_hash[i] = 0.0 unless max_hash[i] 1022: max_hash[i] += data_point.to_f 1023: end 1024: end 1025: 1026: # @maximum_value = 0 1027: max_hash.keys.each do |key| 1028: @maximum_value = max_hash[key] if max_hash[key] > @maximum_value 1029: end 1030: @minimum_value = 0 1031: end
Make copy of data with values scaled between 0-100
# File lib/gruff/base.rb, line 542 542: def normalize(force=false) 543: if @norm_data.nil? || force 544: @norm_data = [] 545: return unless @has_data 546: 547: calculate_spread 548: 549: @data.each do |data_row| 550: norm_data_points = [] 551: data_row[DATA_VALUES_INDEX].each do |data_point| 552: if data_point.nil? 553: norm_data_points << nil 554: else 555: norm_data_points << ((data_point.to_f - @minimum_value.to_f ) / @spread) 556: end 557: end 558: @norm_data << [data_row[DATA_LABEL_INDEX], norm_data_points, data_row[DATA_COLOR_INDEX]] 559: end 560: end 561: 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 895 895: def render_background 896: case @theme_options[:background_colors] 897: when Array 898: @base_image = render_gradiated_background(*@theme_options[:background_colors]) 899: when String 900: @base_image = render_solid_background(@theme_options[:background_colors]) 901: else 902: @base_image = render_image_background(*@theme_options[:background_image]) 903: end 904: end
Use with a theme to use an image (800x600 original) background.
# File lib/gruff/base.rb, line 920 920: def render_image_background(image_path) 921: image = Image.read(image_path) 922: if @scale != 1.0 923: image[0].resize!(@scale) # TODO Resize with new scale (crop if necessary for wide graph) 924: end 925: image[0] 926: end
Use with a theme to make a transparent background
# File lib/gruff/base.rb, line 929 929: def render_transparent_background 930: Image.new(@columns, @rows) do 931: self.background_color = 'transparent' 932: end 933: end
Resets everything to defaults (except data).
# File lib/gruff/base.rb, line 936 936: def reset_themes 937: @color_index = 0 938: @labels_seen = {} 939: @theme_options = {} 940: 941: @d = Draw.new 942: # Scale down from 800x600 used to calculate drawing. 943: @d = @d.scale(@scale, @scale) 944: end
Return a comparable fontsize for the current graph.
# File lib/gruff/base.rb, line 951 951: def scale_fontsize(value) 952: new_fontsize = value * @scale 953: # return new_fontsize < 10.0 ? 10.0 : new_fontsize 954: return new_fontsize 955: end
Calculates size of drawable area and draws the decorations.
# File lib/gruff/base.rb, line 524 524: def setup_drawing 525: # Maybe should be done in one of the following functions for more granularity. 526: unless @has_data 527: draw_no_data() 528: return 529: end 530: 531: normalize() 532: setup_graph_measurements() 533: sort_norm_data() if @sort # Sort norm_data with avg largest values set first (for display) 534: 535: draw_legend() 536: draw_line_markers() 537: draw_axis_labels() 538: draw_title 539: end
Calculates size of drawable area, general font dimensions, etc.
# File lib/gruff/base.rb, line 571 571: def setup_graph_measurements 572: @marker_caps_height = @hide_line_markers ? 0 : 573: calculate_caps_height(@marker_font_size) 574: @title_caps_height = @hide_title ? 0 : 575: calculate_caps_height(@title_font_size) 576: @legend_caps_height = @hide_legend ? 0 : 577: calculate_caps_height(@legend_font_size) 578: 579: if @hide_line_markers 580: (@graph_left, 581: @graph_right_margin, 582: @graph_bottom_margin) = [@left_margin, @right_margin, @bottom_margin] 583: else 584: longest_left_label_width = 0 585: if @has_left_labels 586: longest_left_label_width = calculate_width(@marker_font_size, 587: labels.values.inject('') { |value, memo| (value.to_s.length > memo.to_s.length) ? value : memo }) * 1.25 588: else 589: longest_left_label_width = calculate_width(@marker_font_size, 590: label(@maximum_value.to_f)) 591: end 592: 593: # Shift graph if left line numbers are hidden 594: line_number_width = @hide_line_numbers && !@has_left_labels ? 595: 0.0 : 596: (longest_left_label_width + LABEL_MARGIN * 2) 597: 598: @graph_left = @left_margin + 599: line_number_width + 600: (@y_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN * 2) 601: 602: # Make space for half the width of the rightmost column label. 603: # Might be greater than the number of columns if between-style bar markers are used. 604: last_label = @labels.keys.sort.last.to_i 605: extra_room_for_long_label = (last_label >= (@column_count-1) && @center_labels_over_point) ? 606: calculate_width(@marker_font_size, @labels[last_label]) / 2.0 : 607: 0 608: @graph_right_margin = @right_margin + extra_room_for_long_label 609: 610: @graph_bottom_margin = @bottom_margin + 611: @marker_caps_height + LABEL_MARGIN 612: end 613: 614: @graph_right = @raw_columns - @graph_right_margin 615: @graph_width = @raw_columns - @graph_left - @graph_right_margin 616: 617: # When @hide title, leave a title_margin space for aesthetics. 618: # Same with @hide_legend 619: @graph_top = @top_margin + 620: (@hide_title ? title_margin : @title_caps_height + title_margin ) + 621: (@hide_legend ? legend_margin : @legend_caps_height + legend_margin) 622: 623: x_axis_label_height = @x_axis_label.nil? ? 0.0 : 624: @marker_caps_height + LABEL_MARGIN 625: @graph_bottom = @raw_rows - @graph_bottom_margin - x_axis_label_height 626: @graph_height = @graph_bottom - @graph_top 627: 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 1003 1003: def sort_norm_data 1004: @norm_data.sort! { |a,b| sums(b[DATA_VALUES_INDEX]) <=> sums(a[DATA_VALUES_INDEX]) } 1005: 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 1086 1086: def calculate_caps_height(font_size) 1087: @d.pointsize = font_size 1088: @d.get_type_metrics(@base_image, 'X').height 1089: 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 1095 1095: def calculate_width(font_size, text) 1096: @d.pointsize = font_size 1097: @d.get_type_metrics(@base_image, text.to_s).width 1098: 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 1049 1049: def debug 1050: if DEBUG 1051: @d = @d.fill 'transparent' 1052: @d = @d.stroke 'turquoise' 1053: @d = yield 1054: end 1055: end
Returns the next color in your color list.
# File lib/gruff/base.rb, line 1058 1058: def increment_color 1059: @color_index = (@color_index + 1) % @colors.length 1060: return @colors[@color_index - 1] 1061: end
Return a formatted string representing a number value that should be printed as a label.
# File lib/gruff/base.rb, line 1065 1065: def label(value) 1066: label = if (@spread.to_f % @marker_count.to_f == 0) || !@y_axis_increment.nil? 1067: value.to_i.to_s 1068: elsif @spread > 10.0 1069: sprintf("%0i", value) 1070: elsif @spread >= 3.0 1071: sprintf("%0.2f", value) 1072: else 1073: value.to_s 1074: end 1075: 1076: parts = label.split('.') 1077: parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{THOUSAND_SEPARATOR}") 1078: parts.join('.') 1079: end