module Digiproc::Plottable::ClassMethods
Contains generic plotting helpers which can be extended to make more specific plotting helpers, or can be used in another class to extend their functionality. Digiproc::Plottable
does extend self::ClassMethods, so they can be used as standalone plotting functions using Digiproc::Plottable.iplot() { |g| … } or Digiproc::Plottable.qplot(…)
Public Instance Methods
Will yield g and allow the caller to define the plot as they wish. It does very little beforehand to setup the plot
# File lib/concerns/plottable.rb, line 76 def iplot(xsteps: 4) g = Gruff::Line.new('1000x1000') g.theme = Digiproc::Plottable::Styles::BLUESCALE g.line_width = 2 g.dot_radius = 0.1 yield g #must insert data :name, data_arr #or dataxy :name, x_arr, y_arr # Go through each dataset, #If there are x values, get max and min #If there are not, get the length of the data #If labels are not inserted by user, do: # get range of largest dataset # label at 0, 0.25*len, 0.5*len, 0.75*len, len return g end
Used by Digiproc::QuickPlot
.
qplot(x: Array[Numeric], y: Array[Numeric], data: Array[Numeric], data_name: String, xyname: String, filename: String, path: String, xsteps: Integer, label_map: ->(Float) returns Float) #=> returns a plot at the entered directory or './plots' by default (ensure directory exists)
x and y OR data must exist to make a plot. `label_map` is used to map the index of the data (or the x value at that point if using xy) to an appropriate label. For example if the x values are between 1 and 10 but data.length is 10000, your label_map could be:
label_map = ->(index_val){ return index_val / 1000.0 }
The frequency of labels will be determined by `xsteps`
# File lib/concerns/plottable.rb, line 104 def qplot(x: nil ,y: nil , data: nil, data_name: "data", xyname: "data",filename: "#{self}_plot", path: "./plots/", xsteps: 4, label_map: nil) raise ArgumentError.new("Either x and y or data must exist") if data.nil? and (x.nil? or y.nil?) data = data raise TypeError.new("Data must be an array, not a #{data.class}") if data and not data.is_a? Array raise TypeError.new("X and Y must be arrays, not #{x.class}, #{y.class}") if (!!x and !!y) and not (x.is_a?(Array) and y.is_a?(Array)) raise ArgumentError.new("X and Y must be the same size") if (!!x and !!y) and (x.length != y.length) g = Gruff::Line.new('1000x1000') g.theme = Styles::BLUESCALE g.line_width = 2.5 g.dot_radius = 0.1 # g.minimum_x_value = 0 g.data data_name, data if !!data g.dataxy xyname, x, y if !!x and !!y xmax = !!data ? data.length : x.max xmin = !!data ? 0 : x.min increment_label = (xmax - xmin) / xsteps.to_f datalength = !!data ? data.length : x.length increment_datapoints = (datalength.to_f / xsteps).round labels = {} for i in 0..xsteps do datapoint_location = i * increment_datapoints datapoint_location -= 1 if datapoint_location > (datalength - 1) label_val = label_map.nil? ? (i * increment_label).round(2) : label_map.call((i * increment_label)).round(2) labels[datapoint_location] = label_val end g.labels = labels g.show_vertical_markers = false yield g g.write(path + filename + '.png') end