module UnicodePlot
Constants
- BORDER_MAP
- VERSION
Public Class Methods
# File lib/unicode_plot/renderer.rb, line 43 def self.border_types BORDER_MAP.keys end
# File lib/unicode_plot/canvas.rb, line 167 def self.canvas_types Canvas::CANVAS_CLASS_MAP.keys end
Generates one or more {Stemplot} objects from the input data and prints a Single or Double stemplot using {stemplot1!} or {stemplot2!} @see Stemplot
@example Single sided stemplot
>> UnicodePlot.stemplot(eighty_ints) 0 | 257 1 | 00335679 2 | 034455899 3 | 145588 4 | 0022223 5 | 0223399 6 | 012345568889 7 | 01133334466777888 8 | 013689 9 | 22667 Key: 1|0 = 10 The decimal is 1 digit(s) to the right of |
@example Back-to-back stemplot
>> UnicodePlot.stemplot(eighty_ints, another_eighty_ints) 752 | 0 | 1244457899 97653300 | 1 | 4799 998554430 | 2 | 015668 885541 | 3 | 0144557888899 3222200 | 4 | 00268 9933220 | 5 | 0234778 988865543210 | 6 | 122222357889 88877766443333110 | 7 | 134556689 986310 | 8 | 24589 76622 | 9 | 022234468 Key: 1|0 = 10 The decimal is 1 digit(s) to the right of |
# File lib/unicode_plot/stemplot.rb, line 323 def stemplot(*args, scale: 10, **kw) case args.length when 1 # Stemplot object plt = Stemplot.factory(args[0], scale: scale, **kw) # Dispatch to plot routine stemplot1!(plt, scale: scale, **kw) when 2 # Stemplot object plt1 = Stemplot.factory(args[0], scale: scale) plt2 = Stemplot.factory(args[1], scale: scale) raise ArgumentError, "Plot types must be the same for back-to-back stemplot " + "#{plt1.class} != #{plt2.class}" unless plt1.class == plt2.class # Dispatch to plot routine stemplot2!(plt1, plt2, scale: scale, **kw) else raise ArgumentError, "Expecting one or two arguments" end end
Print a Single-Vector stemplot to STDOUT.
-
Stem data is printed on the left.
-
Leaf data is printed on the right.
-
Key is printed at the bottom.
@param plt [Stemplot] Stemplot
object @param scale [Integer] Scale, should be a power of 10 @param divider [String] Divider character between stem and leaf @param padchar [String] Padding character @param trim [Boolean] Trim missing stems from the plot
# File lib/unicode_plot/stemplot.rb, line 233 def stemplot1!(plt, scale: 10, divider: "|", padchar: " ", trim: false, **_kw ) stem_labels = plt.stems(all: !trim) label_len = stem_labels.map(&:length).max column_len = label_len + 1 stem_labels.each do |stem| leaves = plt.leaves(stem).sort stemlbl = stem.rjust(label_len, padchar).ljust(column_len, padchar) puts stemlbl + divider + padchar + leaves.join end plt.print_key(scale, divider) end
Print a Back-to-Back Stemplot
to STDOUT
-
plt1
Leaf data is printed on the left. -
Common stem data is printed in the center.
-
plt2
Leaf data is printed on the right. -
Key is printed at the bottom.
@param plt1 [Stemplot] Stemplot
object for the left side @param plt2 [Stemplot] Stemplot
object for the right side @param scale [Integer] Scale, should be a power of 10 @param divider [String] Divider character between stem and leaf @param padchar [String] Padding character @param trim [Boolean] Trim missing stems from the plot
# File lib/unicode_plot/stemplot.rb, line 265 def stemplot2!(plt1, plt2, scale: 10, divider: "|", padchar: " ", trim: false, **_kw ) stem_labels = plt1.class.sorted_stem_list( (plt1.raw_stems + plt2.raw_stems).uniq, all: !trim ) label_len = stem_labels.map(&:length).max column_len = label_len + 1 leftleaf_len = plt1.max_stem_length stem_labels.each do |stem| left_leaves = plt1.leaves(stem).sort.join('') right_leaves = plt2.leaves(stem).sort.join('') left_leaves_just = left_leaves.reverse.rjust(leftleaf_len, padchar) stem = stem.rjust(column_len, padchar).ljust(column_len+1, padchar) puts left_leaves_just + padchar + divider + stem + divider + padchar + right_leaves end plt1.print_key(scale, divider) end
Public Instance Methods
@overload barplot(text, heights, xscale: nil, title: nil, xlabel: nil, ylabel: nil, labels: true, border: :barplot, margin: Plot::DEFAULT_MARGIN, padding: Plot::DEFAULT_PADDING, color: Barplot::DEFAULT_COLOR, width: Plot::DEFAULT_WIDTH, symbol: Barplot::DEFAULT_SYMBOL)
Draws a horizontal barplot. @param text [Array<String>] The lables / captions of the bars. @param heights [Array<Numeric>] The values / heights of the bars. @param xscale [nil,:log,:ln,:log10,:lg,:log2,:lb,callable] A function name symbol or callable object to transform the bar length before plotting. This effectively scales the x-axis without influencing the captions of the individual bars. e.g. use `xscale: :log10` for logscale. @param title @param xlabel @param ylabel @param labels @param border @param margin @param padding @param color @param width @param symbol [String] Specifies the character that should be used to render the bars. @return [Barplot] A plot object. @example Example usage of barplot on IRB: >> UnicodePlot.barplot(["Paris", "New York", "Moskau", "Madrid"], [2.244, 8.406, 11.92, 3.165], xlabel: "population [in mil]").render ┌ ┐ Paris ┤■■■■■■ 2.244 New York ┤■■■■■■■■■■■■■■■■■■■■■■■ 8.406 Moskau ┤■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 11.92 Madrid ┤■■■■■■■■■ 3.165 └ ┘ population [in mil] => nil @see Plot @see histogram @see Barplot
@overload barplot(data, **kwargs)
The different variation of barplot described above. @param data [Hash] A hash in which the keys will be used as `text` and the values will be utilized as `heights`. @param kwargs Optional keyword arguments same as ones described above. @return [Barplot] A plot object.
# File lib/unicode_plot/barplot.rb, line 123 def barplot(*args, width: Plot::DEFAULT_WIDTH, color: Barplot::DEFAULT_COLOR, symbol: Barplot::DEFAULT_SYMBOL, border: :barplot, xscale: nil, xlabel: nil, data: nil, **kw) case args.length when 0 data = Hash(data) keys = data.keys.map(&:to_s) heights = data.values when 2 keys = Array(args[0]) heights = Array(args[1]) else raise ArgumentError, "invalid arguments" end unless keys.length == heights.length raise ArgumentError, "The given vectors must be of the same length" end unless heights.min >= 0 raise ArgumentError, "All values have to be positive. Negative bars are not supported." end xlabel ||= ValueTransformer.transform_name(xscale) plot = Barplot.new(heights, width, color, symbol, xscale, border: border, xlabel: xlabel, **kw) keys.each_with_index do |key, i| plot.annotate_row!(:l, i, key) end plot end
@overload barplot!(plot, text, heights)
Draw additional bars on the given existing plot. @param plot [Barplot] the existing plot. @return [Barplot] A plot object. @see barplot
@overload barplot!(plot, data)
The different variation of `barplot!` that takes the plotting data in a hash. @param plot [Barplot] the existing plot. @return [Barplot] A plot object.
# File lib/unicode_plot/barplot.rb, line 177 def barplot!(plot, *args, data: nil) case args.length when 0 data = Hash(data) keys = data.keys.map(&:to_s) heights = data.values when 2 keys = Array(args[0]) heights = Array(args[1]) else raise ArgumentError, "invalid arguments" end unless keys.length == heights.length raise ArgumentError, "The given vectors must be of the same length" end if keys.empty? raise ArgumentError, "Can't append empty array to barplot" end cur_idx = plot.n_rows plot.add_row!(heights) keys.each_with_index do |key, i| plot.annotate_row!(:l, cur_idx + i, key) end plot end
# File lib/unicode_plot/boxplot.rb, line 94 def boxplot(*args, data: nil, border: :corners, color: Boxplot::DEFAULT_COLOR, width: Plot::DEFAULT_WIDTH, xlim: [0, 0], **kw) case args.length when 0 data = Hash(data) text = data.keys data = data.values when 1 data = args[0] when 2 text = Array(args[0]) data = args[1] else raise ArgumentError, "wrong number of arguments" end case data[0] when Numeric data = [data] when Array # do nothing else data = data.to_ary end text ||= Array.new(data.length, "") unless text.length == data.length raise ArgumentError, "wrong number of text" end unless xlim.length == 2 raise ArgumentError, "xlim must be a length 2 array" end min_x, max_x = Utils.extend_limits(data.map(&:minmax).flatten, xlim) width = [width, Boxplot::MIN_WIDTH].max plot = Boxplot.new(data[0], width, color, min_x, max_x, border: border, **kw) (1 ... data.length).each do |i| plot.add_series!(data[i]) end mean_x = (min_x + max_x) / 2.0 min_x_str = (Utils.roundable?(min_x) ? min_x.round : min_x).to_s mean_x_str = (Utils.roundable?(mean_x) ? mean_x.round : mean_x).to_s max_x_str = (Utils.roundable?(max_x) ? max_x.round : max_x).to_s plot.annotate!(:bl, min_x_str, color: :light_black) plot.annotate!(:b, mean_x_str, color: :light_black) plot.annotate!(:br, max_x_str, color: :light_black) text.each_with_index do |name, i| plot.annotate_row!(:l, i*3+1, name) if name.length > 0 end plot end
# File lib/unicode_plot/boxplot.rb, line 157 def boxplot!(plot, *args, **kw) case args.length when 1 data = args[0] name = kw[:name] || "" when 2 name = args[0] data = args[1] else raise ArgumentError, "worng number of arguments" end if data.empty? raise ArgumentError, "Can't append empty array to boxplot" end plot.add_series!(data) plot.annotate_row!(:l, (plot.n_data - 1)*3+1, name) if name && name != "" min_x = plot.min_x max_x = plot.max_x mean_x = (min_x + max_x) / 2.0 min_x_str = (Utils.roundable?(min_x) ? min_x.round : min_x).to_s mean_x_str = (Utils.roundable?(mean_x) ? mean_x.round : mean_x).to_s max_x_str = (Utils.roundable?(max_x) ? max_x.round : max_x).to_s plot.annotate!(:bl, min_x_str, color: :light_black) plot.annotate!(:b, mean_x_str, color: :light_black) plot.annotate!(:br, max_x_str, color: :light_black) plot end
# File lib/unicode_plot/stairs.rb, line 63 def compute_stair_lines(x, y, style: :post) x_vex = Array.new(x.length * 2 - 1, 0) y_vex = Array.new(x.length * 2 - 1, 0) x_vex[0] = x[0] y_vex[0] = y[0] o = 0 if style == :post (1 ... x.length).each do |i| x_vex[i + o] = x[i] x_vex[i + o + 1] = x[i] y_vex[i + o] = y[i-1] y_vex[i + o + 1] = y[i] o += 1 end elsif style == :pre (1 ... x.length).each do |i| x_vex[i + o] = x[i-1] x_vex[i + o + 1] = x[i] y_vex[i + o] = y[i] y_vex[i + o + 1] = y[i] o += 1 end end return [x_vex, y_vex] end
# File lib/unicode_plot/densityplot.rb, line 2 def densityplot(x, y, color: :auto, grid: false, name: "", **kw) plot = GridPlot.new(x, y, :density, grid: grid, **kw) scatterplot!(plot, x, y, color: color, name: name) end
# File lib/unicode_plot/densityplot.rb, line 7 def densityplot!(plot, x, y, **kw) scatterplot!(plot, x, y, **kw) end
# File lib/unicode_plot/histogram.rb, line 4 def histogram(x, nbins: nil, closed: :left, symbol: "▇", **kw) hist = x.histogram(*[nbins].compact, closed: closed) edge, counts = hist.edge, hist.weights labels = [] bin_width = edge[1] - edge[0] pad_left, pad_right = 0, 0 (0 ... edge.length).each do |i| val1 = Utils.float_round_log10(edge[i], bin_width) val2 = Utils.float_round_log10(val1 + bin_width, bin_width) a1 = val1.to_s.split('.', 2).map(&:length) a2 = val2.to_s.split('.', 2).map(&:length) pad_left = [pad_left, a1[0], a2[0]].max pad_right = [pad_right, a1[1], a2[1]].max end l_str = hist.closed == :right ? "(" : "[" r_str = hist.closed == :right ? "]" : ")" counts.each_with_index do |n, i| val1 = Utils.float_round_log10(edge[i], bin_width) val2 = Utils.float_round_log10(val1 + bin_width, bin_width) a1 = val1.to_s.split('.', 2).map(&:length) a2 = val2.to_s.split('.', 2).map(&:length) labels[i] = "\e[90m#{l_str}\e[0m" + (" " * (pad_left - a1[0])) + val1.to_s + (" " * (pad_right - a1[1])) + "\e[90m, \e[0m" + (" " * (pad_left - a2[0])) + val2.to_s + (" " * (pad_right - a2[1])) + "\e[90m#{r_str}\e[0m" end xscale = kw.delete(:xscale) xlabel = kw.delete(:xlabel) || ValueTransformer.transform_name(xscale, "Frequency") barplot(labels, counts, symbol: symbol, xscale: xscale, xlabel: xlabel, **kw) end
@overload lineplot(, y, name: “”, canvas: :braille, title: “”, xlabel: “”, ylabel: “”, labels: true, border: :solid, margin: Plot::DEFAULT_MARGIN, padding: Plot::DEFAULT_PADDING, color: :auto, width: Plot::DEFAULT_WIDTH, height: GridPlot::DEFAULT_HEIGHT, xlim: [0, 0], ylim: [0, 0], canvas: :braille, grid: true)
Draws a path through the given points on a new canvas. The first (optional) array `x` should contain the horizontal positions for all the points along the path. The second array `y` should then contain the corresponding vertical positions respectively. This means that the two vectors must be of the same length and ordering. @param x [Array<Numeric>] Optional. The horizontal position for each point. If omitted, the axes of `y` will be used as `x`. @param y [Array<Numeric>] The vertical position for each point. @param name [String] Annotation of the current drawing to be displayed on the right. @param title @param xlabel @param ylabel @param labels @param border @param margin @param padding @param color @param width @param height @param xlim @param ylim @param canvas [Symbol] The type of canvas that should be used for drawing. @param grid [true,false] If `true`, draws grid-lines at the origin. @return [Lineplot] A plot object.
# File lib/unicode_plot/lineplot.rb, line 33 def lineplot(*args, canvas: :braille, color: :auto, name: "", **kw) case args.length when 1 # y only y = Array(args[0]) x = Array(1 .. y.length) when 2 # x and y x = Array(args[0]) y = Array(args[1]) else raise ArgumentError, "wrong number of arguments" end case x[0] when Time, Date if x[0].is_a? Time d = x.map(&:to_f) else origin = Date.new(1, 1, 1) d = x.map {|xi| xi - origin } end plot = lineplot(d, y, canvas: canvas, color: color, name: name, **kw) xmin, xmax = x.minmax plot.annotate!(:bl, xmin.to_s, color: :light_black) plot.annotate!(:br, xmax.to_s, color: :light_black) plot else plot = Lineplot.new(x, y, canvas, **kw) lineplot!(plot, x, y, color: color, name: name) end end
@overload lineplot!(plot, [x], y, name: “”, color: :auto)
Draws a path through the given points on the given canvas. @param plot [Lineplot] The plot object. @param x [Array<Numeric>] Optional. The horizontal position for each point. If omitted, the axes of `y` will be used as `x`. @param y [Array<Numeric>] The vertical position for each point. @param name [String] Annotation of the current drawing to be displayed on the right. @param color @return [Lineplot] The plot object same as the `plot` parameter.
# File lib/unicode_plot/lineplot.rb, line 80 def lineplot!(plot, *args, color: :auto, name: "") case args.length when 1 # y only y = Array(args[0]) x = Array(1 .. y.length) when 2 # x and y x = Array(args[0]) y = Array(args[1]) if x.length == 1 && y.length == 1 # intercept and slope intercept = x[0] slope = y[0] xmin = plot.origin_x xmax = plot.origin_x + plot.plot_width ymin = plot.origin_y ymax = plot.origin_y + plot.plot_height x = [xmin, xmax] y = [intercept + xmin*slope, intercept + xmax*slope] end else raise ArgumentError, "wrong number of arguments" end case x[0] when Time, Date if x[0].is_a? Time d = x.map(&:to_f) else origin = Date.new(1, 1, 1) d = x.map {|xi| xi - origin } end lineplot!(plot, d, y, color: color, name: name) else color = color == :auto ? plot.next_color : color plot.annotate!(:r, name.to_s, color: color) unless name.nil? || name == "" plot.lines!(x, y, color) end plot end
# File lib/unicode_plot/scatterplot.rb, line 5 def scatterplot(*args, canvas: :braille, color: :auto, name: "", **kw) case args.length when 1 # y only y = Array(args[0]) x = Array(1 .. y.length) when 2 # x and y x = Array(args[0]) y = Array(args[1]) else raise ArgumentError, "worng number of arguments" end plot = Scatterplot.new(x, y, canvas, **kw) scatterplot!(plot, x, y, color: color, name: name) end
# File lib/unicode_plot/scatterplot.rb, line 27 def scatterplot!(plot, *args, color: :auto, name: "") case args.length when 1 # y only y = Array(args[0]) x = Array(1 .. y.length) when 2 # x and y x = Array(args[0]) y = Array(args[1]) else raise ArgumentError, "worng number of arguments" end color = color == :auto ? plot.next_color : color plot.annotate!(:r, name.to_s, color: color) unless name.nil? || name == "" plot.points!(x, y, color) plot end
@overload stairs(x, y, style: :post, name: “”, title: “”, xlabel: “”, ylabel: “”, labels: true, border: :solid, margin: 3, padding: 1, color: :auto, width: 40, height: 15, xlim: [0, 0], ylim: [0, 0], canvas: :braille, grid: true)
Draws a staircase plot on a new canvas. The first vector `x` should contain the horizontal positions for all the points. The second vector `y` should then contain the corresponding vertical positions respectively. This means that the two vectors must be of the same length and ordering. @param x [Array<Numeric>] The horizontal position for each point. @param y [Array<Numeric>] The vertical position for each point. @param style [Symbol] Specifies where the transition of the stair takes place. Can be either `:pre` or `:post`. @param name [String] Annotation of the current drawing to be displayed on the right. @param height [Integer] Number of character rows that should be used for plotting. @param xlim [Array<Numeric>] Plotting range for the x axis. `[0, 0]` stands for automatic. @param ylim [Array<Numeric>] Plotting range for the y axis. `[0, 0]` stands for automatic. @param canvas [Symbol] The type of canvas that should be used for drawing. @param grid [Boolean] If `true`, draws grid-lines at the origin. @return [Plot] A plot object. @example Example usage of stairs on IRB: >> UnicodePlot.stairs([1, 2, 4, 7, 8], [1, 3, 4, 2, 7], style: :post, title: "My Staircase Plot").render My Staircase Plot ┌────────────────────────────────────────┐ 7 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│ │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│ │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│ │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│ │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│ │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│ │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│ │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⡄⠀⠀⠀⠀⢸│ │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⢸│ │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⢸│ │⠀⠀⠀⠀⠀⢸⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⢸│ │⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⢸│ │⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠧⠤⠤⠤⠤⠼│ │⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 1 │⣀⣀⣀⣀⣀⣸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ └────────────────────────────────────────┘ 1 8 => nil @see Plot @see scatterplot @see lineplot
# File lib/unicode_plot/stairs.rb, line 52 def stairs(xvec, yvec, style: :post, **kw) x_vex, y_vex = compute_stair_lines(xvec, yvec, style: style) lineplot(x_vex, y_vex, **kw) end
Similar to stairs, but takes an existing plot object as a first argument.
# File lib/unicode_plot/stairs.rb, line 58 def stairs!(plot, xvec, yvec, style: :post, **kw) x_vex, y_vex = compute_stair_lines(xvec, yvec, style: style) lineplot!(plot, x_vex, y_vex, **kw) end
Private Instance Methods
Generates one or more {Stemplot} objects from the input data and prints a Single or Double stemplot using {stemplot1!} or {stemplot2!} @see Stemplot
@example Single sided stemplot
>> UnicodePlot.stemplot(eighty_ints) 0 | 257 1 | 00335679 2 | 034455899 3 | 145588 4 | 0022223 5 | 0223399 6 | 012345568889 7 | 01133334466777888 8 | 013689 9 | 22667 Key: 1|0 = 10 The decimal is 1 digit(s) to the right of |
@example Back-to-back stemplot
>> UnicodePlot.stemplot(eighty_ints, another_eighty_ints) 752 | 0 | 1244457899 97653300 | 1 | 4799 998554430 | 2 | 015668 885541 | 3 | 0144557888899 3222200 | 4 | 00268 9933220 | 5 | 0234778 988865543210 | 6 | 122222357889 88877766443333110 | 7 | 134556689 986310 | 8 | 24589 76622 | 9 | 022234468 Key: 1|0 = 10 The decimal is 1 digit(s) to the right of |
# File lib/unicode_plot/stemplot.rb, line 323 def stemplot(*args, scale: 10, **kw) case args.length when 1 # Stemplot object plt = Stemplot.factory(args[0], scale: scale, **kw) # Dispatch to plot routine stemplot1!(plt, scale: scale, **kw) when 2 # Stemplot object plt1 = Stemplot.factory(args[0], scale: scale) plt2 = Stemplot.factory(args[1], scale: scale) raise ArgumentError, "Plot types must be the same for back-to-back stemplot " + "#{plt1.class} != #{plt2.class}" unless plt1.class == plt2.class # Dispatch to plot routine stemplot2!(plt1, plt2, scale: scale, **kw) else raise ArgumentError, "Expecting one or two arguments" end end
Print a Single-Vector stemplot to STDOUT.
-
Stem data is printed on the left.
-
Leaf data is printed on the right.
-
Key is printed at the bottom.
@param plt [Stemplot] Stemplot
object @param scale [Integer] Scale, should be a power of 10 @param divider [String] Divider character between stem and leaf @param padchar [String] Padding character @param trim [Boolean] Trim missing stems from the plot
# File lib/unicode_plot/stemplot.rb, line 233 def stemplot1!(plt, scale: 10, divider: "|", padchar: " ", trim: false, **_kw ) stem_labels = plt.stems(all: !trim) label_len = stem_labels.map(&:length).max column_len = label_len + 1 stem_labels.each do |stem| leaves = plt.leaves(stem).sort stemlbl = stem.rjust(label_len, padchar).ljust(column_len, padchar) puts stemlbl + divider + padchar + leaves.join end plt.print_key(scale, divider) end
Print a Back-to-Back Stemplot
to STDOUT
-
plt1
Leaf data is printed on the left. -
Common stem data is printed in the center.
-
plt2
Leaf data is printed on the right. -
Key is printed at the bottom.
@param plt1 [Stemplot] Stemplot
object for the left side @param plt2 [Stemplot] Stemplot
object for the right side @param scale [Integer] Scale, should be a power of 10 @param divider [String] Divider character between stem and leaf @param padchar [String] Padding character @param trim [Boolean] Trim missing stems from the plot
# File lib/unicode_plot/stemplot.rb, line 265 def stemplot2!(plt1, plt2, scale: 10, divider: "|", padchar: " ", trim: false, **_kw ) stem_labels = plt1.class.sorted_stem_list( (plt1.raw_stems + plt2.raw_stems).uniq, all: !trim ) label_len = stem_labels.map(&:length).max column_len = label_len + 1 leftleaf_len = plt1.max_stem_length stem_labels.each do |stem| left_leaves = plt1.leaves(stem).sort.join('') right_leaves = plt2.leaves(stem).sort.join('') left_leaves_just = left_leaves.reverse.rjust(leftleaf_len, padchar) stem = stem.rjust(column_len, padchar).ljust(column_len+1, padchar) puts left_leaves_just + padchar + divider + stem + divider + padchar + right_leaves end plt1.print_key(scale, divider) end