Skip to content

Commit de91489

Browse files
authored
Merge pull request #38 from nanobowers/stairs
Adding support for staircase plots, with unit tests
2 parents 793f5e9 + 2d3d01a commit de91489

11 files changed

Lines changed: 320 additions & 1 deletion

example/ex_staircase_plot.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/bin/env ruby
2+
3+
$LOAD_PATH << "#{__dir__}/../lib"
4+
require "unicode_plot"
5+
6+
# single plot at a time
7+
UnicodePlot.stairs([1, 2, 4, 7, 8], [1, 3, 4, 2, 7], style: :post).render
8+
9+
# pre: style
10+
UnicodePlot.stairs([1, 2, 4, 7, 8], [1, 3, 4, 2, 7], style: :pre).render
11+
12+
# Another single plot with title
13+
UnicodePlot.stairs([2, 3, 5, 6, 9], [2, 5, 3, 4, 2], title: "My Staircase Plot").render
14+
15+
# Two plots at a time.
16+
# Using an explicit limit because data for the 2nd plot is outside the bounds from the 1st plot
17+
plot = UnicodePlot.stairs([1, 2, 4, 7, 8], [1, 3, 4, 2, 7], title: "Two Staircases", xlim: [1,10] )
18+
UnicodePlot.stairs!(plot, [0, 3, 5, 6, 9], [2, 5, 3, 4, 0])
19+
plot.render
20+
21+

lib/unicode_plot.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@
2323
require 'unicode_plot/lineplot'
2424
require 'unicode_plot/histogram'
2525
require 'unicode_plot/scatterplot'
26+
require 'unicode_plot/stairs'

lib/unicode_plot/stairs.rb

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# coding: utf-8
2+
module UnicodePlot
3+
4+
5+
# ==Description
6+
#
7+
# Draws a staircase plot on a new canvas.
8+
#
9+
# The first vector `x` should contain the horizontal
10+
# positions for all the points. The second vector `y` should then
11+
# contain the corresponding vertical positions respectively. This
12+
# means that the two vectors must be of the same length and
13+
# ordering.
14+
#
15+
# ==Usage
16+
#
17+
# UnicodePlot.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)
18+
#
19+
# @param x [Array<Numeric>] The horizontal position for each point.
20+
# @param y [Array<Numeric>] The vertical position for each point.
21+
# @param style [Symbol] Specifies where the transition of the stair takes place. Can be either `:pre` or `:post`.
22+
# @param name [String] Annotation of the current drawing to be displayed on the right.
23+
# @param height [Integer] Number of character rows that should be used for plotting.
24+
# @param xlim [Array<Numeric>] Plotting range for the x axis. `[0, 0]` stands for automatic.
25+
# @param ylim [Array<Numeric>] Plotting range for the y axis. `[0, 0]` stands for automatic.
26+
# @param canvas [Symbol] The type of canvas that should be used for drawing.
27+
# @param grid [Boolean] If `true`, draws grid-lines at the origin.
28+
#
29+
# @return [Plot] A plot object
30+
#
31+
# @example
32+
# UnicodePlot.stairs([1, 2, 4, 7, 8], [1, 3, 4, 2, 7], style: :post, title: "My Staircase Plot")
33+
#
34+
#
35+
# ┌────────────────────────────────────────┐
36+
# 7 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
37+
# │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
38+
# │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
39+
# │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
40+
# │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
41+
# │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
42+
# │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
43+
# │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⡄⠀⠀⠀⠀⢸│
44+
# │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⢸│
45+
# │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⢸│
46+
# │⠀⠀⠀⠀⠀⢸⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⢸│
47+
# │⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⢸│
48+
# │⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠧⠤⠤⠤⠤⠼│
49+
# │⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
50+
# 1 │⣀⣀⣀⣀⣀⣸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
51+
# └────────────────────────────────────────┘
52+
# 1 8
53+
#
54+
# @see Plot
55+
# @see scatterplot
56+
# @see lineplot
57+
#
58+
module_function def stairs(xvec, yvec, style: :post, **kw)
59+
x_vex, y_vex = compute_stair_lines(xvec, yvec, style: style)
60+
lineplot(x_vex, y_vex, **kw)
61+
end
62+
63+
# Similar to stairs, but takes an existing plot object as a first argument.
64+
module_function def stairs!(plot, xvec, yvec, style: :post, **kw)
65+
x_vex, y_vex = compute_stair_lines(xvec, yvec, style: style)
66+
lineplot!(plot, x_vex, y_vex, **kw)
67+
end
68+
69+
module_function def compute_stair_lines(x, y, style: :post)
70+
x_vex = Array.new(x.length * 2 - 1, 0)
71+
y_vex = Array.new(x.length * 2 - 1, 0)
72+
x_vex[0] = x[0]
73+
y_vex[0] = y[0]
74+
o = 0
75+
if style == :post
76+
(1 ... x.length).each do |i|
77+
x_vex[i + o] = x[i]
78+
x_vex[i + o + 1] = x[i]
79+
y_vex[i + o] = y[i-1]
80+
y_vex[i + o + 1] = y[i]
81+
o += 1
82+
end
83+
elsif style == :pre
84+
(1 ... x.length).each do |i|
85+
x_vex[i + o] = x[i-1]
86+
x_vex[i + o + 1] = x[i]
87+
y_vex[i + o] = y[i]
88+
y_vex[i + o + 1] = y[i]
89+
o += 1
90+
end
91+
end
92+
return [x_vex, y_vex]
93+
end
94+
95+
end
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
 Hellohow areyou?
2+
 ┌──────────┐
3+
7 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
4+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
5+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
6+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
7+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
8+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼│
9+
 │⠀⠀⠀⠀⠀⠀⠀⢀⠜⢸│
10+
 │⠀⠀⠀⠀⡤⠤⢤⠮⢤⢸│
11+
 │⠀⠀⠀⠀⡇⢠⠊⠀⢸⢸│
12+
 │⠀⠀⠀⠀⣧⠃⠀⠀⢸⢸│
13+
 │⠀⡏⠉⡹⠁⠀⠀⠀⢸⢸│
14+
 │⠀⡇⡰⠁⠀⠀⠀⠀⢸⢸│
15+
 │⠀⡟⠀⠀⠀⠀⠀⠀⠸⠼│
16+
 │⡜⡇⠀⠀⠀⠀⠀⠀⠀⠀│
17+
1 │⣀⡇⠀⠀⠀⠀⠀⠀⠀⠀│
18+
 └──────────┘
19+
 Hellohow areyou?
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
 ┌────────────────────────────────────────┐
2+
7000 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
3+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
4+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
5+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
6+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
7+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
8+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
9+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
10+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
11+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
12+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
13+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
14+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
15+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│
16+
0 │⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣸│
17+
 └────────────────────────────────────────┘
18+
 1  8
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
 Foo
2+
 ┌────────────────────────────────────────┐
3+
7 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⢸│ 1
4+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⢸│ 2
5+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⢸│
6+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⢀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⡀⠀⠀⠀⠀⢸⢸│
7+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⢸⢸│
8+
 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⢸⢸│
9+
 │⠀⠀⠀⠀⢰⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠚⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⢸⢸│
10+
 │⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⡧⡄⠀⠀⠀⢸⢸│
11+
 │⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣇⣇⣀⣀⣀⣸⢸│
12+
 │⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⢸│
13+
 │⠀⠀⠀⠀⢸⢸⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⢸│
14+
 │⠒⠒⠒⠒⠚⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⢸│
15+
 │⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠧⠤⠤⠤⠤⠼│
16+
 │⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
17+
1 │⣀⣀⣀⣀⣀⣸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
18+
 └────────────────────────────────────────┘
19+
 1  8
20+
 x

0 commit comments

Comments
 (0)