Class: Rubyplot::Artist
- Inherits:
-
Object
- Object
- Rubyplot::Artist
- Includes:
- Magick
- Defined in:
- lib/rubyplot/artist/data.rb,
lib/rubyplot/artist/math.rb,
lib/rubyplot/artist/artist.rb,
lib/rubyplot/artist/themes.rb,
lib/rubyplot/artist/initialize.rb,
lib/rubyplot/artist/constantsAndAttributes.rb
Constant Summary collapse
- DATA_LABEL_INDEX =
Used for navigating the array of data to plot
0
- DATA_VALUES_INDEX =
1
- DATA_COLOR_INDEX =
2
- DATA_VALUES_X_INDEX =
3
- LEGEND_MARGIN =
Space around text elements. Mostly used for vertical spacing. This way the vertical text doesn't overlap.
TITLE_MARGIN = 20.0
- LABEL_MARGIN =
10.0
- DEFAULT_MARGIN =
20.0
- DEFAULT_TARGET_WIDTH =
800
- THOUSAND_SEPARATOR =
','.freeze
Instance Attribute Summary collapse
-
#base_image ⇒ Object
Accessor base image.
-
#font ⇒ Object
readonly
Font used for titles, labels, etc.
-
#font_color ⇒ Object
Returns the value of attribute font_color.
-
#has_left_labels ⇒ Object
Used internally for horizontal graph types.
-
#hide_legend ⇒ Object
Prevent drawing of the legend.
-
#hide_line_numbers ⇒ Object
Prevent drawing of line numbers.
-
#labels ⇒ Object
A hash of names for the individual columns, where the key is the array index for the column this label represents.
-
#legend_font_size ⇒ Object
Optionally set the size of the font.
-
#legend_margin ⇒ Object
Blank space below the legend.
-
#marker_color ⇒ Object
The color of the auxiliary lines.
-
#marker_count ⇒ Object
The number of horizontal lines shown for reference.
-
#marker_shadow_color ⇒ Object
Returns the value of attribute marker_shadow_color.
-
#maximum_value ⇒ Object
You can manually set a maximum value, such as a percentage-based graph that always goes to 100.
-
#minimum_value ⇒ Object
You can manually set a minimum value instead of having the values guessed for you.
-
#title ⇒ Object
The large title of the graph displayed at the top.
-
#title_margin ⇒ Object
Blank space below the title.
-
#x_axis_label ⇒ Object
A label for the bottom of the graph.
-
#y_axis_label ⇒ Object
A label for the left side of the graph.
Instance Method Summary collapse
-
#artist_draw ⇒ Object
An alias to draw function to facilitate the ease of function calling with subclasses used to define different plots.
-
#calculate_caps_height(font_size) ⇒ Object
Returns the height of the capital letter 'X' for the current font and size.
-
#calculate_spread ⇒ Object
Calculates the spread of the data.
-
#calculate_width(font_size, text) ⇒ Object
Returns the width of a string at this pointsize.
-
#center(size) ⇒ Object
Return a calculation of center.
-
#clip_value_if_greater_than(value, max_value) ⇒ Object
:nodoc:.
-
#construct_colors_array ⇒ Object
Makes an array of colors randomly selected from all the possible list of colors supported by RMagick.
-
#data(name, data_points = []) ⇒ Object
Parameters are an array where the first element is the name of the dataset and the value is an array of values to plot.
-
#draw ⇒ Object
Basic Rendering function that takes pre-processed input and plots it on a figure canvas.
-
#draw_axis_labels ⇒ Object
Draw the optional labels for the x axis and y axis.
-
#draw_label(x_offset, index) ⇒ Object
Draws column labels below graph, centered over x_offset.
-
#draw_legend ⇒ Object
Draws a legend with the names of the datasets matched to the colors used to draw them.
-
#draw_line_markers! ⇒ Object
Draws horizontal background lines and labels.
-
#draw_title ⇒ Object
Draws a title on the graph.
-
#get_colors_array ⇒ Object
Returns the current color array for the labels.
-
#initialize(target_width = DEFAULT_TARGET_WIDTH) ⇒ Artist
constructor
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.).
-
#initialize_variables ⇒ Object
Set instance variables for this object.
-
#normalize ⇒ Object
Make copy of data with values scaled between 0-100 TODO: Add spec for this method.
-
#render_gradiated_background(top_color, bottom_color, direct = :top_bottom) ⇒ Object
Use with a theme definition method to draw a gradiated background.
-
#reset_themes ⇒ Object
Resets the themes to defaults.
- #scale(value) ⇒ Object
-
#scale_fontsize(value) ⇒ Object
Return a comparable fontsize for the current graph.
-
#set_colors_array(color_array) ⇒ Object
Sets the colors for the data labels of the plot.
-
#setup_drawing ⇒ Object
Calculates size of drawable area and generates normalized data.
-
#setup_graph_measurements ⇒ Object
Calculates size of drawable area, general font dimensions, etc.
- #significant(i) ⇒ Object
-
#sort_norm_data ⇒ Object
Sort with largest overall summed value at front of array so it shows up correctly in the drawn graph.
-
#sum(arr) ⇒ Object
Return the sum of values in an array.
-
#theme=(options) ⇒ Object
You can set a theme manually.
-
#write(filename = 'plot.png') ⇒ Object
Writes the plot to a file.
Constructor Details
#initialize(target_width = DEFAULT_TARGET_WIDTH) ⇒ Artist
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.)
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/rubyplot/artist/initialize.rb', line 11 def initialize(target_width = DEFAULT_TARGET_WIDTH) if Numeric === target_width @columns = target_width.to_f @rows = target_width.to_f * 0.75 else geometric_width, geometric_height = target_width.split('x') @columns = geometric_width.to_f @rows = geometric_height.to_f end @geometry = Rubyplot::ArtistGeometry.new initialize_variables reset_themes self.theme = Themes::RITA end |
Instance Attribute Details
#base_image ⇒ Object
Accessor base image
85 86 87 |
# File 'lib/rubyplot/artist/constantsAndAttributes.rb', line 85 def base_image @base_image end |
#font ⇒ Object (readonly)
Font used for titles, labels, etc. The font= method below fulfills the role of the writer, so we only need a reader here.
48 49 50 |
# File 'lib/rubyplot/artist/constantsAndAttributes.rb', line 48 def font @font end |
#font_color ⇒ Object
Returns the value of attribute font_color
50 51 52 |
# File 'lib/rubyplot/artist/constantsAndAttributes.rb', line 50 def font_color @font_color end |
#has_left_labels ⇒ Object
Used internally for horizontal graph types.
34 35 36 |
# File 'lib/rubyplot/artist/constantsAndAttributes.rb', line 34 def has_left_labels @has_left_labels end |
#hide_legend ⇒ Object
Prevent drawing of the legend
53 54 55 |
# File 'lib/rubyplot/artist/constantsAndAttributes.rb', line 53 def hide_legend @hide_legend end |
#hide_line_numbers ⇒ Object
Prevent drawing of line numbers
56 57 58 |
# File 'lib/rubyplot/artist/constantsAndAttributes.rb', line 56 def hide_line_numbers @hide_line_numbers end |
#labels ⇒ Object
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
31 32 33 |
# File 'lib/rubyplot/artist/constantsAndAttributes.rb', line 31 def labels @labels end |
#legend_font_size ⇒ Object
Optionally set the size of the font. Based on an 800x600px graph. Default is 20.
Will be scaled down if the graph is smaller than 800px wide.
62 63 64 |
# File 'lib/rubyplot/artist/constantsAndAttributes.rb', line 62 def legend_font_size @legend_font_size end |
#legend_margin ⇒ Object
Blank space below the legend
23 24 25 |
# File 'lib/rubyplot/artist/constantsAndAttributes.rb', line 23 def legend_margin @legend_margin end |
#marker_color ⇒ Object
The color of the auxiliary lines
68 69 70 |
# File 'lib/rubyplot/artist/constantsAndAttributes.rb', line 68 def marker_color @marker_color end |
#marker_count ⇒ Object
The number of horizontal lines shown for reference
65 66 67 |
# File 'lib/rubyplot/artist/constantsAndAttributes.rb', line 65 def marker_count @marker_count end |
#marker_shadow_color ⇒ Object
Returns the value of attribute marker_shadow_color
69 70 71 |
# File 'lib/rubyplot/artist/constantsAndAttributes.rb', line 69 def marker_shadow_color @marker_shadow_color end |
#maximum_value ⇒ Object
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.
82 83 84 |
# File 'lib/rubyplot/artist/constantsAndAttributes.rb', line 82 def maximum_value @maximum_value end |
#minimum_value ⇒ Object
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.
75 76 77 |
# File 'lib/rubyplot/artist/constantsAndAttributes.rb', line 75 def minimum_value @minimum_value end |
#title ⇒ Object
The large title of the graph displayed at the top
43 44 45 |
# File 'lib/rubyplot/artist/constantsAndAttributes.rb', line 43 def title @title end |
#title_margin ⇒ Object
Blank space below the title
20 21 22 |
# File 'lib/rubyplot/artist/constantsAndAttributes.rb', line 20 def title_margin @title_margin end |
#x_axis_label ⇒ Object
A label for the bottom of the graph
37 38 39 |
# File 'lib/rubyplot/artist/constantsAndAttributes.rb', line 37 def x_axis_label @x_axis_label end |
#y_axis_label ⇒ Object
A label for the left side of the graph
40 41 42 |
# File 'lib/rubyplot/artist/constantsAndAttributes.rb', line 40 def y_axis_label @y_axis_label end |
Instance Method Details
#artist_draw ⇒ Object
An alias to draw function to facilitate the ease of function calling with subclasses used to define different plots.
43 44 45 46 47 48 49 50 51 |
# File 'lib/rubyplot/artist/artist.rb', line 43 def artist_draw return unless @geometry.has_data setup_drawing construct_colors_array draw_legend draw_line_markers! draw_title draw_axis_labels end |
#calculate_caps_height(font_size) ⇒ Object
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.
77 78 79 80 81 |
# File 'lib/rubyplot/artist/math.rb', line 77 def calculate_caps_height(font_size) @d.pointsize = font_size @d.font = @font if @font @d.get_type_metrics(@base_image, 'X').height end |
#calculate_spread ⇒ Object
Calculates the spread of the data.
23 24 25 |
# File 'lib/rubyplot/artist/math.rb', line 23 def calculate_spread @spread = @geometry.maximum_value.to_f - @geometry.minimum_value.to_f end |
#calculate_width(font_size, text) ⇒ Object
Returns the width of a string at this pointsize.
Not scaled since it deals with dimensions that the regular scaling will handle.
87 88 89 90 91 92 93 94 95 |
# File 'lib/rubyplot/artist/math.rb', line 87 def calculate_width(font_size, text) return 0 if text.nil? @d.pointsize = font_size @d.font = @font if @font @d.get_type_metrics(@base_image, text.to_s).width # get_type_metrics function returns information for a specific string if rendered on a image. # It's extreemly useful for understanding positioning and location of text. # This will be used to identify positioning of text. end |
#center(size) ⇒ Object
Return a calculation of center
34 35 36 |
# File 'lib/rubyplot/artist/math.rb', line 34 def center(size) (@geometry.raw_columns - size) / 2 end |
#clip_value_if_greater_than(value, max_value) ⇒ Object
:nodoc:
18 19 20 |
# File 'lib/rubyplot/artist/math.rb', line 18 def clip_value_if_greater_than(value, max_value) # :nodoc: value > max_value ? max_value : value end |
#construct_colors_array ⇒ Object
Makes an array of colors randomly selected from all the possible list of colors supported by RMagick. This function is used because it helps to decide the colors for data labels if user doesn't specify the colors for data labels.
8 9 10 11 12 13 |
# File 'lib/rubyplot/artist/artist.rb', line 8 def construct_colors_array return unless @plot_colors.empty? 0.upto(@geometry.norm_data.size - 1) do |_i| @plot_colors.push(@geometry.all_colors_array[rand(@geometry.all_colors_array.size)].name) end end |
#data(name, data_points = []) ⇒ Object
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.
Example:
data("Arafat", [95, 45, 78, 89, 88, 76])
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/rubyplot/artist/data.rb', line 12 def data(name, data_points = []) data_points = Array(data_points) # make sure it's an array # TODO: Adding an empty color array which can be developed later # to make graphs super customizable with regards to coloring of # individual data points. color = [] @data << [name, data_points, color] # Set column count if this is larger than previous column counts @geometry.column_count = data_points.length > @geometry.column_count ? data_points.length : @geometry.column_count # Pre-normalize => Set the max and min values of the data. data_points.each do |data_point| # Initialize the maximum and minimum values so that the spread starts # at the lowest points in the data and then changes as iteration. if @geometry.maximum_value.nil? && @geometry.minimum_value.nil? @geometry.maximum_value = @geometry.minimum_value = data_point end @geometry.maximum_value = data_point > @geometry.maximum_value ? data_point : @geometry.maximum_value @geometry.minimum_value = data_point < @geometry.minimum_value ? data_point : @geometry.minimum_value @geometry.has_data = true end end |
#draw ⇒ Object
Basic Rendering function that takes pre-processed input and plots it on a figure canvas. This function only contains the generalized layout of a plot. Based on individual cases the actual drawing function of a plot will use super to call this method. And then draw upon the figure canvas.
37 38 39 |
# File 'lib/rubyplot/artist/artist.rb', line 37 def draw artist_draw end |
#draw_axis_labels ⇒ Object
Draw the optional labels for the x axis and y axis.
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/rubyplot/artist/artist.rb', line 126 def draw_axis_labels unless @geometry.x_axis_label .nil? # X Axis # Centered vertically and horizontally by setting the # height to 1.0 and the width to the width of the graph. x_axis_label_y_coordinate = @graph_bottom + LABEL_MARGIN * 2 + @marker_caps_height # TODO: Center between graph area @d.fill = @font_color @d.font = @font if @font @d.stroke('transparent') @d.pointsize = scale_fontsize(@marker_font_size) @d.gravity = NorthGravity @d = @d.scale_annotation(@base_image, @geometry.raw_columns, 1.0, 0.0, x_axis_label_y_coordinate, @geometry.x_axis_label, @scale) end unless @geometry.y_axis_label .nil? # Y Axis, rotated vertically @d.rotation = -90.0 @d.gravity = CenterGravity @d = @d.scale_annotation(@base_image, 1.0, @raw_rows, @geometry.left_margin + @marker_caps_height / 2.0, 0.0, @geometry.y_axis_label, @scale) @d.rotation = 90.0 end end |
#draw_label(x_offset, index) ⇒ Object
Draws column labels below graph, centered over x_offset
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 |
# File 'lib/rubyplot/artist/artist.rb', line 331 def draw_label(x_offset, index) return if @geometry.hide_line_markers if !@labels[index].nil? && @geometry.labels_seen[index].nil? y_offset = @graph_bottom + LABEL_MARGIN # TESTME # TODO: See if index.odd? is the best stragegy y_offset += @label_stagger_height if index.odd? label_text = labels[index].to_s # TESTME # FIXME: Consider chart types other than bar if label_text.size > @label_max_size if @geometry.label_truncation_style == :trailing_dots if @label_max_size > 3 # 4 because '...' takes up 3 chars label_text = "#{label_text[0..(@label_max_size - 4)]}..." end else # @geometry.label_truncation_style is :absolute (default) label_text = label_text[0..(@label_max_size - 1)] end end if x_offset >= @graph_left && x_offset <= @graph_right @d.fill = @font_color @d.font = @font if @font @d.stroke('transparent') @d.font_weight = NormalWeight @d.pointsize = scale_fontsize(@marker_font_size) @d.gravity = NorthGravity @d = @d.scale_annotation(@base_image, 1.0, 1.0, x_offset, y_offset, label_text, @scale) end @geometry.labels_seen[index] = 1 end end |
#draw_legend ⇒ Object
Draws a legend with the names of the datasets matched to the colors used to draw them.
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
# File 'lib/rubyplot/artist/artist.rb', line 176 def draw_legend @legend_labels = @data.collect { |item| item[DATA_LABEL_INDEX] } legend_square_width = @legend_box_size # small square with color of this item # May fix legend drawing problem at small sizes @d.font = @font if @font @d.pointsize = @legend_font_size label_widths = [[]] # Used to calculate line wrap @legend_labels.each do |label| metrics = @d.get_type_metrics(@base_image, label.to_s) label_width = metrics.width + legend_square_width * 2.7 label_widths.last.push label_width if sum(label_widths.last) > (@geometry.raw_columns * 0.9) label_widths.push [label_widths.last.pop] end end current_x_offset = center(sum(label_widths.first)) current_y_offset = @geometry.legend_at_bottom ? @graph_height + title_margin : (@geometry.hide_title ? @geometry.top_margin + title_margin : @geometry.top_margin + title_margin + @title_caps_height) @legend_labels.each_with_index do |legend_label, _index| # Draw label @d.fill = @font_color @d.font = @font if @font @d.pointsize = scale_fontsize(@legend_font_size) # font size in points @d.stroke('transparent') @d.font_weight = NormalWeight @d.gravity = WestGravity @d = @d.scale_annotation(@base_image, @geometry.raw_columns, 1.0, current_x_offset + (legend_square_width * 1.7), current_y_offset, legend_label.to_s, @scale) # Now draw box with color of this dataset @d = @d.stroke('transparent') @d = @d.fill('black') @d = @d.fill(@plot_colors[_index]) if defined? @plot_colors @d = @d.rectangle(current_x_offset, current_y_offset - legend_square_width / 2.0, current_x_offset + legend_square_width, current_y_offset + legend_square_width / 2.0) # string = 'hello' + _index.to_s + '.png' # @base_image.write(string) @d.pointsize = @legend_font_size metrics = @d.get_type_metrics(@base_image, legend_label.to_s) current_string_offset = metrics.width + (legend_square_width * 2.7) # Handle wrapping label_widths.first.shift if label_widths.first.empty? label_widths.shift current_x_offset = center(sum(label_widths.first)) unless label_widths.empty? line_height = [@legend_caps_height, legend_square_width].max + legend_margin unless label_widths.empty? # Wrap to next line and shrink available graph dimensions current_y_offset += line_height @graph_top += line_height @graph_height = @graph_bottom - @graph_top end else current_x_offset += current_string_offset end end @color_index = 0 end |
#draw_line_markers! ⇒ Object
Draws horizontal background lines and labels
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
# File 'lib/rubyplot/artist/artist.rb', line 250 def draw_line_markers! return if @geometry.hide_line_markers @d = @d.stroke_antialias false if @geometry.y_axis_increment .nil? # Try to use a number of horizontal lines that will come out even. # # TODO Do the same for larger numbers...100, 75, 50, 25 if @geometry.marker_count.nil? (3..7).each do |lines| if @spread % lines == 0.0 @geometry.marker_count = lines break end end @geometry.marker_count ||= 4 end @geometry.increment = @spread > 0 && @geometry.marker_count > 0 ? significant(@spread / @geometry.marker_count) : 1 else # TODO: Make this work for negative values @geometry.marker_count = (@spread / @geometry.y_axis_increment).to_i @geometry.increment = @geometry.y_axis_increment end @geometry.increment_scaled = @graph_height.to_f / (@spread / @geometry.increment) # Draw horizontal line markers and annotate with numbers (0..@geometry.marker_count).each do |index| y = @graph_top + @graph_height - index.to_f * @geometry.increment_scaled @d = @d.fill(@marker_color) @d = @d.line(@graph_left, y, @graph_right, y) # If the user specified a marker shadow color, draw a shadow just below it unless @marker_shadow_color.nil? @d = @d.fill(@marker_shadow_color) @d = @d.line(@graph_left, y + 1, @graph_right, y + 1) end marker_label = BigDecimal(index.to_s) * BigDecimal(@geometry.increment.to_s) + BigDecimal(@geometry.minimum_value.to_s) next if @geometry.hide_line_numbers @d.fill = @font_color @d.font = @font if @font @d.stroke('transparent') @d.pointsize = scale_fontsize(@marker_font_size) @d.gravity = EastGravity # Vertically center with 1.0 for the height @d = @d.scale_annotation(@base_image, @graph_left - LABEL_MARGIN, 1.0, 0.0, y, label(marker_label, @geometry.increment), @scale) end @d = @d.stroke_antialias true # string = 'hello' + '.png' # @d.draw(@base_image) # @base_image.write(string) end |
#draw_title ⇒ Object
Draws a title on the graph.
158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/rubyplot/artist/artist.rb', line 158 def draw_title return if @geometry.hide_title || @title.nil? @d.fill = @font_color @d.font = @title_font || @font if @title_font || @font @d.stroke('transparent') @d.pointsize = scale_fontsize(@title_font_size) @d.font_weight = BoldWeight @d.gravity = NorthGravity @d = @d.scale_annotation(@base_image, @geometry.raw_columns, 1.0, 0, @geometry.top_margin, @title, @scale) end |
#get_colors_array ⇒ Object
Returns the current color array for the labels
21 22 23 |
# File 'lib/rubyplot/artist/artist.rb', line 21 def get_colors_array @plot_colors end |
#initialize_variables ⇒ Object
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.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/rubyplot/artist/initialize.rb', line 33 def initialize_variables # Internal for calculations @data = [] @raw_rows = 800.0 * (@rows / @columns) @labels = {} @sort = false @title = nil @title_font = nil @scale = @columns / @geometry.raw_columns vera_font_path = File.('Vera.ttf', ENV['MAGICK_FONT_PATH']) @font = File.exist?(vera_font_path) ? vera_font_path : nil @marker_font_size = 21.0 @legend_font_size = 20.0 @title_font_size = 36.0 @legend_margin = LEGEND_MARGIN @title_margin = TITLE_MARGIN @legend_box_size = 20.0 @label_stagger_height = 0 @label_max_size = 0 @label_truncation_style = :absolute @plot_colors = [] end |
#normalize ⇒ Object
Make copy of data with values scaled between 0-100 TODO: Add spec for this method.
6 7 8 9 10 11 12 13 14 15 16 |
# File 'lib/rubyplot/artist/math.rb', line 6 def normalize @geometry.norm_data = [] @data.each do |data_row| norm_data_points = [] data_row[DATA_VALUES_INDEX].each do |data_point| norm_data_points << ((data_point.to_f - @geometry.minimum_value.to_f) / @spread) # Add support for nil values in data etc. end @geometry.norm_data << [data_row[DATA_LABEL_INDEX], norm_data_points] end end |
#render_gradiated_background(top_color, bottom_color, direct = :top_bottom) ⇒ Object
Use with a theme definition method to draw a gradiated background.
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 |
# File 'lib/rubyplot/artist/artist.rb', line 312 def render_gradiated_background(top_color, bottom_color, direct = :top_bottom) gradient_fill = case direct when :bottom_top GradientFill.new(0, 0, 100, 0, bottom_color, top_color) when :left_right GradientFill.new(0, 0, 0, 100, top_color, bottom_color) when :right_left GradientFill.new(0, 0, 0, 100, bottom_color, top_color) when :topleft_bottomright GradientFill.new(0, 100, 100, 0, top_color, bottom_color) when :topright_bottomleft GradientFill.new(0, 0, 100, 100, bottom_color, top_color) else GradientFill.new(0, 0, 100, 0, top_color, bottom_color) end Image.new(@columns, @rows, gradient_fill) end |
#reset_themes ⇒ Object
Resets the themes to defaults.
30 31 32 33 34 |
# File 'lib/rubyplot/artist/themes.rb', line 30 def reset_themes @d = Draw.new # Scale down from defaut scale to scale used to calculate drawing. @d = @d.scale(@scale, @scale) end |
#scale(value) ⇒ Object
36 37 38 |
# File 'lib/rubyplot/artist/themes.rb', line 36 def scale(value) value * @scale end |
#scale_fontsize(value) ⇒ Object
Return a comparable fontsize for the current graph.
39 40 41 |
# File 'lib/rubyplot/artist/math.rb', line 39 def scale_fontsize(value) value * @scale end |
#set_colors_array(color_array) ⇒ Object
Sets the colors for the data labels of the plot.
16 17 18 |
# File 'lib/rubyplot/artist/artist.rb', line 16 def set_colors_array(color_array) @plot_colors = color_array end |
#setup_drawing ⇒ Object
Calculates size of drawable area and generates normalized data.
-
line markers
-
legend
-
title
-
labels
-
X/Y offsets
61 62 63 64 65 |
# File 'lib/rubyplot/artist/artist.rb', line 61 def setup_drawing calculate_spread normalize setup_graph_measurements end |
#setup_graph_measurements ⇒ Object
Calculates size of drawable area, general font dimensions, etc. This is the most crucial part of the code and is based on geometry. It calcuates the measurments in pixels to figure out the positioning gap pixels of Legends, Labels and Titles from the picture edge.
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/rubyplot/artist/artist.rb', line 72 def setup_graph_measurements @marker_caps_height = calculate_caps_height(@marker_font_size) @title_caps_height = @geometry.hide_title || @title.nil? ? 0 : calculate_caps_height(@title_font_size) * @title.lines.to_a.size # Initially the title is nil. @legend_caps_height = calculate_caps_height(@legend_font_size) # For now, the labels feature only focuses on the dot graph so it makes sense to only have # this as an attribute for this kind of graph and not for others. if @geometry.has_left_labels longest_left_label_width = calculate_width(@marker_font_size, labels.values.inject('') { |value, memo| value.to_s.length > memo.to_s.length ? value : memo }) * 1.25 else longest_left_label_width = calculate_width(@marker_font_size, label(@geometry.maximum_value.to_f, @geometry.increment)) end # Shift graph if left line numbers are hidden line_number_width = @geometry.hide_line_numbers && !@geometry.has_left_labels ? 0.0 : (longest_left_label_width + LABEL_MARGIN * 2) # Pixel offset from the left edge of the plot @graph_left = @geometry.left_margin + line_number_width + (@geometry.y_axis_label .nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN * 2) # Make space for half the width of the rightmost column label. last_label = @labels.keys.max.to_i extra_room_for_long_label = last_label >= (@geometry.column_count - 1) && @geometry.center_labels_over_point ? calculate_width(@marker_font_size, @labels[last_label]) / 2.0 : 0 # Margins @graph_right_margin = @geometry.right_margin + extra_room_for_long_label @graph_bottom_margin = @geometry.bottom_margin + @marker_caps_height + LABEL_MARGIN @graph_right = @geometry.raw_columns - @graph_right_margin @graph_width = @geometry.raw_columns - @graph_left - @graph_right_margin # When @hide title, leave a title_margin space for aesthetics. @graph_top = @geometry.legend_at_bottom ? @geometry.top_margin : (@geometry.top_margin + (@geometry.hide_title ? title_margin : @title_caps_height + title_margin) + (@legend_caps_height + legend_margin)) x_axis_label_height = @geometry.x_axis_label .nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN # The actual height of the graph inside the whole image in pixels. @graph_bottom = @raw_rows - @graph_bottom_margin - x_axis_label_height - @label_stagger_height @graph_height = @graph_bottom - @graph_top end |
#significant(i) ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/rubyplot/artist/math.rb', line 43 def significant(i) return 1.0 if i == 0 # Keep from going into infinite loop inc = BigDecimal(i.to_s) factor = BigDecimal('1.0') while inc < 10 inc *= 10 factor /= 10 end while inc > 100 inc /= 10 factor *= 10 end res = inc.floor * factor if res.to_i.to_f == res res.to_i else res end end |
#sort_norm_data ⇒ Object
Sort with largest overall summed value at front of array so it shows up correctly in the drawn graph.
67 68 69 70 |
# File 'lib/rubyplot/artist/math.rb', line 67 def sort_norm_data @geometry.norm_data = @geometry.norm_data.sort_by { |a| -a[DATA_VALUES_INDEX].inject(0) { |sum, num| sum + num.to_f } } end |
#sum(arr) ⇒ Object
Return the sum of values in an array.
28 29 30 |
# File 'lib/rubyplot/artist/math.rb', line 28 def sum(arr) arr.inject(0) { |i, m| m + i } end |
#theme=(options) ⇒ Object
You can set a theme manually. Assign a hash to this method before you send your data. This permits you to set a background color and also customize the background color to make it look prettier. Aside from that we could also have a feature to draw on a background image So later adding prebuilt background images to draw upon would also be possible.
graph.theme = {
:marker_color => 'blue',
:background_colors => ['black', 'grey', :top_bottom]
}
16 17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/rubyplot/artist/themes.rb', line 16 def theme=() reset_themes defaults = { marker_color: 'white', font_color: 'black', background_image: nil } @geometry. = defaults.merge @marker_color = @geometry.[:marker_color] @font_color = @geometry.[:font_color] || @marker_color @base_image = render_gradiated_background(@geometry.[:background_colors][0], @geometry.[:background_colors][1], @geometry.[:background_direction]) end |
#write(filename = 'plot.png') ⇒ Object
Writes the plot to a file. Defaults to 'plot.png' All file writing formats supported by RMagicks are supported by this function.
28 29 30 31 |
# File 'lib/rubyplot/artist/artist.rb', line 28 def write(filename = 'plot.png') draw @base_image.write(filename) end |