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 172 172: def initialize(target_width=DEFAULT_TARGET_WIDTH) 173: @top_margin = @bottom_margin = @left_margin = @right_margin = 20.0 174: 175: if not Numeric === target_width 176: geometric_width, geometric_height = target_width.split('x') 177: @columns = geometric_width.to_f 178: @rows = geometric_height.to_f 179: else 180: @columns = target_width.to_f 181: @rows = target_width.to_f * 0.75 182: end 183: 184: initialize_ivars 185: 186: reset_themes 187: theme_keynote 188: end
Add a color to the list of available colors for lines.
Example:
add_color('#c0e9d3')
# File lib/gruff/base.rb, line 252 252: def add_color(colorname) 253: @colors << colorname 254: 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 436 436: def data(name, data_points=[], color=nil) 437: data_points = Array(data_points) # make sure it's an array 438: @data << [name, data_points, (color || increment_color)] 439: # Set column count if this is larger than previous counts 440: @column_count = (data_points.length > @column_count) ? data_points.length : @column_count 441: 442: # Pre-normalize 443: data_points.each_with_index do |data_point, index| 444: next if data_point.nil? 445: 446: # Setup max/min so spread starts at the low end of the data points 447: if @maximum_value.nil? && @minimum_value.nil? 448: @maximum_value = @minimum_value = data_point 449: end 450: 451: # TODO Doesn't work with stacked bar graphs 452: # Original: @maximum_value = larger_than_max?(data_point, index) ? max(data_point, index) : @maximum_value 453: @maximum_value = larger_than_max?(data_point) ? data_point : @maximum_value 454: @has_data = true if @maximum_value > 0 455: 456: @minimum_value = less_than_min?(data_point) ? data_point : @minimum_value 457: @has_data = true if @minimum_value < 0 458: end 459: end
Sets the font for graph text to the font at font_path.
# File lib/gruff/base.rb, line 243 243: def font=(font_path) 244: @font = font_path 245: @d.font = @font 246: 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 196 196: def initialize_ivars 197: # Internal for calculations 198: @raw_columns = 800.0 199: @raw_rows = 800.0 * (@rows/@columns) 200: @column_count = 0 201: @marker_count = nil 202: @maximum_value = @minimum_value = nil 203: @has_data = false 204: @data = Array.new 205: @labels = Hash.new 206: @labels_seen = Hash.new 207: @sort = true 208: @title = nil 209: 210: @scale = @columns / @raw_columns 211: 212: vera_font_path = File.expand_path('Vera.ttf', ENV['MAGICK_FONT_PATH']) 213: @font = File.exists?(vera_font_path) ? vera_font_path : nil 214: 215: @marker_font_size = 21.0 216: @legend_font_size = 20.0 217: @title_font_size = 36.0 218: 219: @legend_box_size = 20.0 220: 221: @no_data_message = "No Data" 222: 223: @hide_line_markers = @hide_legend = @hide_title = @hide_line_numbers = false 224: @center_labels_over_point = true 225: @has_left_labels = false 226: 227: @additional_line_values = [] 228: @additional_line_colors = [] 229: @theme_options = {} 230: 231: @x_axis_label = @y_axis_label = nil 232: @y_axis_increment = nil 233: @stacked = nil 234: @norm_data = nil 235: end
Sets the top, bottom, left and right margins to margin.
# File lib/gruff/base.rb, line 238 238: def margins=(margin) 239: @top_margin = @left_margin = @right_margin = @bottom_margin = margin 240: 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 262 262: def replace_colors(color_list=[]) 263: @colors = color_list 264: 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 279 279: def theme=(options) 280: reset_themes() 281: 282: defaults = { 283: :colors => ['black', 'white'], 284: :additional_line_colors => [], 285: :marker_color => 'white', 286: :font_color => 'black', 287: :background_colors => nil, 288: :background_image => nil 289: } 290: @theme_options = defaults.merge options 291: 292: @colors = @theme_options[:colors] 293: @marker_color = @theme_options[:marker_color] 294: @font_color = @theme_options[:font_color] || @marker_color 295: @additional_line_colors = @theme_options[:additional_line_colors] 296: 297: render_background 298: end
A color scheme plucked from the colors on the popular usability blog.
# File lib/gruff/base.rb, line 321 321: def theme_37signals 322: # Colors 323: @green = '#339933' 324: @purple = '#cc99cc' 325: @blue = '#336699' 326: @yellow = '#FFF804' 327: @red = '#ff0000' 328: @orange = '#cf5910' 329: @black = 'black' 330: @colors = [@yellow, @blue, @green, @red, @purple, @orange, @black] 331: 332: self.theme = { 333: :colors => @colors, 334: :marker_color => 'black', 335: :font_color => 'black', 336: :background_colors => ['#d1edf5', 'white'] 337: } 338: end
A greyscale theme
# File lib/gruff/base.rb, line 403 403: def theme_greyscale 404: # Colors 405: @colors = [ 406: '#282828', # 407: '#383838', # 408: '#686868', # 409: '#989898', # 410: '#c8c8c8', # 411: '#e8e8e8', # 412: ] 413: 414: self.theme = { 415: :colors => @colors, 416: :marker_color => '#aea9a9', # Grey 417: :font_color => 'black', 418: :background_colors => 'white' 419: } 420: end
A color scheme similar to the popular presentation software.
# File lib/gruff/base.rb, line 301 301: def theme_keynote 302: # Colors 303: @blue = '#6886B4' 304: @yellow = '#FDD84E' 305: @green = '#72AE6E' 306: @red = '#D1695E' 307: @purple = '#8A6EAF' 308: @orange = '#EFAA43' 309: @white = 'white' 310: @colors = [@yellow, @blue, @green, @red, @purple, @orange, @white] 311: 312: self.theme = { 313: :colors => @colors, 314: :marker_color => 'white', 315: :font_color => 'white', 316: :background_colors => ['black', '#4a465a'] 317: } 318: end
A color scheme similar to that used on the popular podcast site.
# File lib/gruff/base.rb, line 362 362: def theme_odeo 363: # Colors 364: @grey = '#202020' 365: @white = 'white' 366: @dark_pink = '#a21764' 367: @green = '#8ab438' 368: @light_grey = '#999999' 369: @dark_blue = '#3a5b87' 370: @black = 'black' 371: @colors = [@grey, @white, @dark_blue, @dark_pink, @green, @light_grey, @black] 372: 373: self.theme = { 374: :colors => @colors, 375: :marker_color => 'white', 376: :font_color => 'white', 377: :background_colors => ['#ff47a4', '#ff1f81'] 378: } 379: end
A pastel theme
# File lib/gruff/base.rb, line 382 382: def theme_pastel 383: # Colors 384: @colors = [ 385: '#a9dada', # blue 386: '#aedaa9', # green 387: '#daaea9', # peach 388: '#dadaa9', # yellow 389: '#a9a9da', # dk purple 390: '#daaeda', # purple 391: '#dadada' # grey 392: ] 393: 394: self.theme = { 395: :colors => @colors, 396: :marker_color => '#aea9a9', # Grey 397: :font_color => 'black', 398: :background_colors => 'white' 399: } 400: end
A color scheme from the colors used on the 2005 Rails keynote presentation at RubyConf.
# File lib/gruff/base.rb, line 342 342: def theme_rails_keynote 343: # Colors 344: @green = '#00ff00' 345: @grey = '#333333' 346: @orange = '#ff5d00' 347: @red = '#f61100' 348: @white = 'white' 349: @light_grey = '#999999' 350: @black = 'black' 351: @colors = [@green, @grey, @orange, @red, @white, @light_grey, @black] 352: 353: self.theme = { 354: :colors => @colors, 355: :marker_color => 'white', 356: :font_color => 'white', 357: :background_colors => ['#0083a3', '#0083a3'] 358: } 359: end
Return the graph as a rendered binary blob.
# File lib/gruff/base.rb, line 471 471: def to_blob(fileformat='PNG') 472: draw() 473: return @base_image.to_blob do 474: self.format = fileformat 475: end 476: end
Writes the graph to a file. Defaults to ‘graph.png‘
Example:
write('graphs/my_pretty_graph.png')
# File lib/gruff/base.rb, line 465 465: def write(filename="graph.png") 466: draw() 467: @base_image.write(filename) 468: 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 485 485: def draw 486: make_stacked if @stacked 487: setup_drawing 488: 489: debug { 490: # Outer margin 491: @d.rectangle( @left_margin, @top_margin, 492: @raw_columns - @right_margin, @raw_rows - @bottom_margin) 493: # Graph area box 494: @d.rectangle( @graph_left, @graph_top, @graph_right, @graph_bottom) 495: } 496: end
Draw the optional labels for the x axis and y axis.
# File lib/gruff/base.rb, line 609 609: def draw_axis_labels 610: unless @x_axis_label.nil? 611: # X Axis 612: # Centered vertically and horizontally by setting the 613: # height to 1.0 and the width to the width of the graph. 614: x_axis_label_y_coordinate = @graph_bottom + LABEL_MARGIN * 2 + @marker_caps_height 615: 616: # TODO Center between graph area 617: @d.fill = @font_color 618: @d.font = @font if @font 619: @d.stroke('transparent') 620: @d.pointsize = scale_fontsize(@marker_font_size) 621: @d.gravity = NorthGravity 622: @d = @d.annotate_scaled( @base_image, 623: @raw_columns, 1.0, 624: 0.0, x_axis_label_y_coordinate, 625: @x_axis_label, @scale) 626: debug { @d.line 0.0, x_axis_label_y_coordinate, @raw_columns, x_axis_label_y_coordinate } 627: end 628: 629: unless @y_axis_label.nil? 630: # Y Axis, rotated vertically 631: @d.rotation = 90.0 632: @d.gravity = CenterGravity 633: @d = @d.annotate_scaled( @base_image, 634: 1.0, @raw_rows, 635: @left_margin + @marker_caps_height / 2.0, 0.0, 636: @y_axis_label, @scale) 637: @d.rotation = -90.0 638: end 639: end
Draws column labels below graph, centered over x_offset
# File lib/gruff/base.rb, line 837 837: def draw_label(x_offset, index) 838: return if @hide_line_markers 839: 840: if !@labels[index].nil? && @labels_seen[index].nil? 841: y_offset = @graph_bottom + LABEL_MARGIN 842: 843: @d.fill = @font_color 844: @d.font = @font if @font 845: @d.stroke('transparent') 846: @d.font_weight = NormalWeight 847: @d.pointsize = scale_fontsize(@marker_font_size) 848: @d.gravity = NorthGravity 849: @d = @d.annotate_scaled(@base_image, 850: 1.0, 1.0, 851: x_offset, y_offset, 852: @labels[index], @scale) 853: @labels_seen[index] = 1 854: debug { @d.line 0.0, y_offset, @raw_columns, y_offset } 855: end 856: end
Draws a legend with the names of the datasets matched to the colors used to draw them.
# File lib/gruff/base.rb, line 744 744: def draw_legend 745: return if @hide_legend 746: 747: @legend_labels = @data.collect {|item| item[DATA_LABEL_INDEX] } 748: 749: legend_square_width = @legend_box_size # small square with color of this item 750: 751: # May fix legend drawing problem at small sizes 752: @d.font = @font if @font 753: @d.pointsize = @legend_font_size 754: 755: label_widths = [[]] # Used to calculate line wrap 756: @legend_labels.each do |label| 757: metrics = @d.get_type_metrics(@base_image, label.to_s) 758: label_width = metrics.width + legend_square_width * 2.7 759: label_widths.last.push label_width 760: 761: if sum(label_widths.last) > (@raw_columns * 0.9) 762: label_widths.push [label_widths.last.pop] 763: end 764: end 765: 766: current_x_offset = center(sum(label_widths.first)) 767: current_y_offset = @hide_title ? 768: @top_margin + LEGEND_MARGIN : 769: @top_margin + TITLE_MARGIN + @title_caps_height + LEGEND_MARGIN 770: 771: @legend_labels.each_with_index do |legend_label, index| 772: 773: # Draw label 774: @d.fill = @font_color 775: @d.font = @font if @font 776: @d.pointsize = scale_fontsize(@legend_font_size) 777: @d.stroke('transparent') 778: @d.font_weight = NormalWeight 779: @d.gravity = WestGravity 780: @d = @d.annotate_scaled( @base_image, 781: @raw_columns, 1.0, 782: current_x_offset + (legend_square_width * 1.7), current_y_offset, 783: legend_label.to_s, @scale) 784: 785: # Now draw box with color of this dataset 786: @d = @d.stroke('transparent') 787: @d = @d.fill @data[index][DATA_COLOR_INDEX] 788: @d = @d.rectangle(current_x_offset, 789: current_y_offset - legend_square_width / 2.0, 790: current_x_offset + legend_square_width, 791: current_y_offset + legend_square_width / 2.0) 792: 793: @d.pointsize = @legend_font_size 794: metrics = @d.get_type_metrics(@base_image, legend_label.to_s) 795: current_string_offset = metrics.width + (legend_square_width * 2.7) 796: 797: # Handle wrapping 798: label_widths.first.shift 799: if label_widths.first.empty? 800: debug { @d.line 0.0, current_y_offset, @raw_columns, current_y_offset } 801: 802: label_widths.shift 803: current_x_offset = center(sum(label_widths.first)) unless label_widths.empty? 804: line_height = [@legend_caps_height, legend_square_width].max + LEGEND_MARGIN 805: if label_widths.length > 0 806: # Wrap to next line and shrink available graph dimensions 807: current_y_offset += line_height 808: @graph_top += line_height 809: @graph_height = @graph_bottom - @graph_top 810: end 811: else 812: current_x_offset += current_string_offset 813: end 814: end 815: @color_index = 0 816: end
Draws horizontal background lines and labels
# File lib/gruff/base.rb, line 642 642: def draw_line_markers 643: return if @hide_line_markers 644: 645: @d = @d.stroke_antialias false 646: 647: if @y_axis_increment.nil? 648: # Try to use a number of horizontal lines that will come out even. 649: # 650: # TODO Do the same for larger numbers...100, 75, 50, 25 651: if @marker_count.nil? 652: (3..7).each do |lines| 653: if @spread % lines == 0.0 654: @marker_count = lines 655: break 656: end 657: end 658: @marker_count ||= 4 659: end 660: @increment = (@spread > 0) ? significant(@spread / @marker_count) : 1 661: else 662: # TODO Make this work for negative values 663: @maximum_value = [@maximum_value.ceil, @y_axis_increment].max 664: @minimum_value = @minimum_value.floor 665: calculate_spread 666: normalize(true) 667: 668: @marker_count = (@spread / @y_axis_increment).to_i 669: @increment = @y_axis_increment 670: end 671: @increment_scaled = @graph_height.to_f / (@spread / @increment) 672: 673: # Draw horizontal line markers and annotate with numbers 674: (0..@marker_count).each do |index| 675: y = @graph_top + @graph_height - index.to_f * @increment_scaled 676: 677: @d = @d.stroke(@marker_color) 678: @d = @d.stroke_width 1 679: @d = @d.line(@graph_left, y, @graph_right, y) 680: 681: marker_label = index * @increment + @minimum_value.to_f 682: 683: unless @hide_line_numbers 684: @d.fill = @font_color 685: @d.font = @font if @font 686: @d.stroke('transparent') 687: @d.pointsize = scale_fontsize(@marker_font_size) 688: @d.gravity = EastGravity 689: 690: # Vertically center with 1.0 for the height 691: @d = @d.annotate_scaled( @base_image, 692: @graph_left - LABEL_MARGIN, 1.0, 693: 0.0, y, 694: label(marker_label), @scale) 695: end 696: end 697: 698: # # Submitted by a contibutor...the utility escapes me 699: # i = 0 700: # @additional_line_values.each do |value| 701: # @increment_scaled = @graph_height.to_f / (@maximum_value.to_f / value) 702: # 703: # y = @graph_top + @graph_height - @increment_scaled 704: # 705: # @d = @d.stroke(@additional_line_colors[i]) 706: # @d = @d.line(@graph_left, y, @graph_right, y) 707: # 708: # 709: # @d.fill = @additional_line_colors[i] 710: # @d.font = @font if @font 711: # @d.stroke('transparent') 712: # @d.pointsize = scale_fontsize(@marker_font_size) 713: # @d.gravity = EastGravity 714: # @d = @d.annotate_scaled( @base_image, 715: # 100, 20, 716: # -10, y - (@marker_font_size/2.0), 717: # "", @scale) 718: # i += 1 719: # end 720: 721: @d = @d.stroke_antialias true 722: end
Shows an error message because you have no data.
# File lib/gruff/base.rb, line 859 859: def draw_no_data 860: @d.fill = @font_color 861: @d.font = @font if @font 862: @d.stroke('transparent') 863: @d.font_weight = NormalWeight 864: @d.pointsize = scale_fontsize(80) 865: @d.gravity = CenterGravity 866: @d = @d.annotate_scaled( @base_image, 867: @raw_columns, @raw_rows/2.0, 868: 0, 10, 869: @no_data_message, @scale) 870: end
Draws a title on the graph.
# File lib/gruff/base.rb, line 819 819: def draw_title 820: return if (@hide_title || @title.nil?) 821: 822: @d.fill = @font_color 823: @d.font = @font if @font 824: @d.stroke('transparent') 825: @d.pointsize = scale_fontsize(@title_font_size) 826: @d.font_weight = BoldWeight 827: @d.gravity = NorthGravity 828: @d = @d.annotate_scaled( @base_image, 829: @raw_columns, 1.0, 830: 0, @top_margin, 831: @title, @scale) 832: end
Used by StackedBar and child classes.
May need to be moved to the StackedBar class.
# File lib/gruff/base.rb, line 996 996: def get_maximum_by_stack 997: # Get sum of each stack 998: max_hash = {} 999: @data.each do |data_set| 1000: data_set[DATA_VALUES_INDEX].each_with_index do |data_point, i| 1001: max_hash[i] = 0.0 unless max_hash[i] 1002: max_hash[i] += data_point.to_f 1003: end 1004: end 1005: 1006: # @maximum_value = 0 1007: max_hash.keys.each do |key| 1008: @maximum_value = max_hash[key] if max_hash[key] > @maximum_value 1009: end 1010: @minimum_value = 0 1011: end
Make copy of data with values scaled between 0-100
# File lib/gruff/base.rb, line 521 521: def normalize(force=false) 522: if @norm_data.nil? || force 523: @norm_data = [] 524: return unless @has_data 525: 526: calculate_spread 527: 528: @data.each do |data_row| 529: norm_data_points = [] 530: data_row[DATA_VALUES_INDEX].each do |data_point| 531: if data_point.nil? 532: norm_data_points << nil 533: else 534: norm_data_points << ((data_point.to_f - @minimum_value.to_f ) / @spread) 535: end 536: end 537: @norm_data << [data_row[DATA_LABEL_INDEX], norm_data_points, data_row[DATA_COLOR_INDEX]] 538: end 539: end 540: 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 875 875: def render_background 876: case @theme_options[:background_colors] 877: when Array 878: @base_image = render_gradiated_background(*@theme_options[:background_colors]) 879: when String 880: @base_image = render_solid_background(@theme_options[:background_colors]) 881: else 882: @base_image = render_image_background(*@theme_options[:background_image]) 883: end 884: end
Use with a theme to use an image (800x600 original) background.
# File lib/gruff/base.rb, line 900 900: def render_image_background(image_path) 901: image = Image.read(image_path) 902: if @scale != 1.0 903: image[0].resize!(@scale) # TODO Resize with new scale (crop if necessary for wide graph) 904: end 905: image[0] 906: end
Use with a theme to make a transparent background
# File lib/gruff/base.rb, line 909 909: def render_transparent_background 910: Image.new(@columns, @rows) do 911: self.background_color = 'transparent' 912: end 913: end
Resets everything to defaults (except data).
# File lib/gruff/base.rb, line 916 916: def reset_themes 917: @color_index = 0 918: @labels_seen = {} 919: @theme_options = {} 920: 921: @d = Draw.new 922: # Scale down from 800x600 used to calculate drawing. 923: @d = @d.scale(@scale, @scale) 924: end
Return a comparable fontsize for the current graph.
# File lib/gruff/base.rb, line 931 931: def scale_fontsize(value) 932: new_fontsize = value * @scale 933: # return new_fontsize < 10.0 ? 10.0 : new_fontsize 934: return new_fontsize 935: end
Calculates size of drawable area and draws the decorations.
# File lib/gruff/base.rb, line 503 503: def setup_drawing 504: # Maybe should be done in one of the following functions for more granularity. 505: unless @has_data 506: draw_no_data() 507: return 508: end 509: 510: normalize() 511: setup_graph_measurements() 512: sort_norm_data() if @sort # Sort norm_data with avg largest values set first (for display) 513: 514: draw_legend() 515: draw_line_markers() 516: draw_axis_labels() 517: draw_title 518: end
Calculates size of drawable area, general font dimensions, etc.
# File lib/gruff/base.rb, line 550 550: def setup_graph_measurements 551: @marker_caps_height = @hide_line_markers ? 0 : 552: calculate_caps_height(@marker_font_size) 553: @title_caps_height = @hide_title ? 0 : 554: calculate_caps_height(@title_font_size) 555: @legend_caps_height = @hide_legend ? 0 : 556: calculate_caps_height(@legend_font_size) 557: 558: if @hide_line_markers 559: (@graph_left, 560: @graph_right_margin, 561: @graph_bottom_margin) = [@left_margin, @right_margin, @bottom_margin] 562: else 563: longest_left_label_width = 0 564: if @has_left_labels 565: longest_left_label_width = calculate_width(@marker_font_size, 566: labels.values.inject('') { |value, memo| (value.to_s.length > memo.to_s.length) ? value : memo }) * 1.25 567: else 568: longest_left_label_width = calculate_width(@marker_font_size, 569: label(@maximum_value.to_f)) 570: end 571: 572: # Shift graph if left line numbers are hidden 573: line_number_width = @hide_line_numbers && !@has_left_labels ? 574: 0.0 : 575: (longest_left_label_width + LABEL_MARGIN * 2) 576: 577: @graph_left = @left_margin + 578: line_number_width + 579: (@y_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN * 2) 580: 581: # Make space for half the width of the rightmost column label. 582: # Might be greater than the number of columns if between-style bar markers are used. 583: last_label = @labels.keys.sort.last.to_i 584: extra_room_for_long_label = (last_label >= (@column_count-1) && @center_labels_over_point) ? 585: calculate_width(@marker_font_size, @labels[last_label]) / 2.0 : 586: 0 587: @graph_right_margin = @right_margin + extra_room_for_long_label 588: 589: @graph_bottom_margin = @bottom_margin + 590: @marker_caps_height + LABEL_MARGIN 591: end 592: 593: @graph_right = @raw_columns - @graph_right_margin 594: @graph_width = @raw_columns - @graph_left - @graph_right_margin 595: 596: # When @hide title, leave a TITLE_MARGIN space for aesthetics. 597: # Same with @hide_legend 598: @graph_top = @top_margin + 599: (@hide_title ? TITLE_MARGIN : @title_caps_height + TITLE_MARGIN * 2) + 600: (@hide_legend ? LEGEND_MARGIN : @legend_caps_height + LEGEND_MARGIN * 2) 601: 602: x_axis_label_height = @x_axis_label.nil? ? 0.0 : 603: @marker_caps_height + LABEL_MARGIN 604: @graph_bottom = @raw_rows - @graph_bottom_margin - x_axis_label_height 605: @graph_height = @graph_bottom - @graph_top 606: 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 983 983: def sort_norm_data 984: @norm_data.sort! { |a,b| sums(b[DATA_VALUES_INDEX]) <=> sums(a[DATA_VALUES_INDEX]) } 985: 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 1064 1064: def calculate_caps_height(font_size) 1065: @d.pointsize = font_size 1066: @d.get_type_metrics(@base_image, 'X').height 1067: 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 1073 1073: def calculate_width(font_size, text) 1074: @d.pointsize = font_size 1075: @d.get_type_metrics(@base_image, text.to_s).width 1076: 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 1029 1029: def debug 1030: if DEBUG 1031: @d = @d.fill 'transparent' 1032: @d = @d.stroke 'turquoise' 1033: @d = yield 1034: end 1035: end
Uses the next color in your color list.
# File lib/gruff/base.rb, line 1038 1038: def increment_color 1039: @color_index = (@color_index + 1) % @colors.length 1040: return @colors[@color_index - 1] 1041: end
Return a formatted string representing a number value that should be printed as a label.
# File lib/gruff/base.rb, line 1045 1045: def label(value) 1046: if (@spread.to_f % @marker_count.to_f == 0) || !@y_axis_increment.nil? 1047: return value.to_i.to_s 1048: end 1049: 1050: if @spread > 10.0 1051: sprintf("%0i", value) 1052: elsif @spread >= 3.0 1053: sprintf("%0.2f", value) 1054: else 1055: value.to_s 1056: end 1057: end