tessella 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +900 -0
- data/doc/README.md +74 -0
- data/doc/bitfield.md +123 -0
- data/doc/charts.md +1370 -0
- data/doc/check.rb +75 -0
- data/doc/cli.md +483 -0
- data/doc/composition.md +599 -0
- data/doc/getting-started.md +121 -0
- data/doc/glyphs.md +134 -0
- data/doc/images.md +325 -0
- data/doc/library.md +239 -0
- data/doc/lint.md +270 -0
- data/doc/meter.md +210 -0
- data/doc/rule.md +51 -0
- data/doc/seq.md +169 -0
- data/doc/sparkline.md +63 -0
- data/doc/table.md +347 -0
- data/doc/targets.md +222 -0
- data/doc/text.md +84 -0
- data/doc/tree.md +108 -0
- data/doc/wave.md +122 -0
- data/examples/README.md +103 -0
- data/examples/ages.txt +9 -0
- data/examples/bad.csv +3 -0
- data/examples/boxes.txt +3 -0
- data/examples/broken.txt +4 -0
- data/examples/calibration.rb +12 -0
- data/examples/cities.csv +4 -0
- data/examples/cjk.rb +13 -0
- data/examples/comment.rb +9 -0
- data/examples/comment.sh +13 -0
- data/examples/cpu.txt +60 -0
- data/examples/dashboard.sh +25 -0
- data/examples/datasheet.rb +16 -0
- data/examples/disc.pgm +0 -0
- data/examples/disks.sh +18 -0
- data/examples/disks.txt +5 -0
- data/examples/dose.txt +7 -0
- data/examples/drift.txt +4 -0
- data/examples/ethernet.txt +3 -0
- data/examples/figure.c +5 -0
- data/examples/fit.rb +16 -0
- data/examples/floors.rb +21 -0
- data/examples/gallery.sh +20 -0
- data/examples/gauges.sh +31 -0
- data/examples/gradient.rb +16 -0
- data/examples/growth.txt +6 -0
- data/examples/hosts.csv +4 -0
- data/examples/icmp.txt +3 -0
- data/examples/ipv4.txt +12 -0
- data/examples/kinds.csv +4 -0
- data/examples/langs.csv +4 -0
- data/examples/lint.rb +16 -0
- data/examples/load.rb +14 -0
- data/examples/login.txt +10 -0
- data/examples/neg.csv +4 -0
- data/examples/normal.txt +200 -0
- data/examples/note.txt +2 -0
- data/examples/notes-fixed.md +17 -0
- data/examples/notes.md +17 -0
- data/examples/ohlc.txt +7 -0
- data/examples/os.csv +10 -0
- data/examples/outline.txt +8 -0
- data/examples/plot.txt +5 -0
- data/examples/refusals.rb +17 -0
- data/examples/report.sh +21 -0
- data/examples/rfc.sh +22 -0
- data/examples/samples.txt +7 -0
- data/examples/shapes.pgm +0 -0
- data/examples/sizes.tsv +3 -0
- data/examples/spi.txt +6 -0
- data/examples/status.sh +23 -0
- data/examples/stem.txt +12 -0
- data/examples/table-drift.txt +4 -0
- data/examples/temps.txt +31 -0
- data/examples/trig.sh +13 -0
- data/examples/trig.txt +102 -0
- data/examples/week.txt +8 -0
- data/examples/wide.txt +2 -0
- data/exe/tessella +6 -0
- data/lib/tessella/axis.rb +71 -0
- data/lib/tessella/bitfield.rb +194 -0
- data/lib/tessella/block.rb +56 -0
- data/lib/tessella/borders.rb +85 -0
- data/lib/tessella/canvas/area.rb +155 -0
- data/lib/tessella/canvas/ascii.rb +120 -0
- data/lib/tessella/canvas/block.rb +40 -0
- data/lib/tessella/canvas/braille.rb +30 -0
- data/lib/tessella/canvas/clip.rb +49 -0
- data/lib/tessella/canvas/density.rb +51 -0
- data/lib/tessella/canvas/dot.rb +27 -0
- data/lib/tessella/canvas/eighths.rb +43 -0
- data/lib/tessella/canvas/half.rb +51 -0
- data/lib/tessella/canvas/sextant.rb +36 -0
- data/lib/tessella/canvas.rb +168 -0
- data/lib/tessella/cell.rb +10 -0
- data/lib/tessella/chart.rb +211 -0
- data/lib/tessella/check.rb +52 -0
- data/lib/tessella/cli/bitfield.rb +121 -0
- data/lib/tessella/cli/chart.rb +615 -0
- data/lib/tessella/cli/chart_candle.rb +36 -0
- data/lib/tessella/cli/chart_heatmap.rb +21 -0
- data/lib/tessella/cli/chart_help.rb +85 -0
- data/lib/tessella/cli/chart_pie.rb +38 -0
- data/lib/tessella/cli/compose.rb +156 -0
- data/lib/tessella/cli/compose_options.rb +259 -0
- data/lib/tessella/cli/glyphs.rb +97 -0
- data/lib/tessella/cli/image.rb +250 -0
- data/lib/tessella/cli/input.rb +44 -0
- data/lib/tessella/cli/iso_time.rb +28 -0
- data/lib/tessella/cli/lint.rb +102 -0
- data/lib/tessella/cli/lint_options.rb +99 -0
- data/lib/tessella/cli/main.rb +121 -0
- data/lib/tessella/cli/meter.rb +80 -0
- data/lib/tessella/cli/rule.rb +57 -0
- data/lib/tessella/cli/seq.rb +117 -0
- data/lib/tessella/cli/sparkline.rb +72 -0
- data/lib/tessella/cli/table.rb +167 -0
- data/lib/tessella/cli/text.rb +78 -0
- data/lib/tessella/cli/tree.rb +100 -0
- data/lib/tessella/cli/wave.rb +148 -0
- data/lib/tessella/cli.rb +36 -0
- data/lib/tessella/color.rb +106 -0
- data/lib/tessella/compose.rb +243 -0
- data/lib/tessella/compose_fill.rb +176 -0
- data/lib/tessella/compose_grid.rb +36 -0
- data/lib/tessella/compose_shadow.rb +41 -0
- data/lib/tessella/error.rb +13 -0
- data/lib/tessella/frame.rb +170 -0
- data/lib/tessella/glyphs.rb +106 -0
- data/lib/tessella/image.rb +454 -0
- data/lib/tessella/image_octant.rb +46 -0
- data/lib/tessella/image_petscii.rb +116 -0
- data/lib/tessella/kinds/bar.rb +344 -0
- data/lib/tessella/kinds/box.rb +213 -0
- data/lib/tessella/kinds/box_upright.rb +110 -0
- data/lib/tessella/kinds/candlestick.rb +164 -0
- data/lib/tessella/kinds/columns.rb +259 -0
- data/lib/tessella/kinds/date_axis.rb +102 -0
- data/lib/tessella/kinds/error_bars.rb +71 -0
- data/lib/tessella/kinds/heatmap.rb +130 -0
- data/lib/tessella/kinds/line.rb +173 -0
- data/lib/tessella/kinds/multibar.rb +98 -0
- data/lib/tessella/kinds/multibar_columns.rb +130 -0
- data/lib/tessella/kinds/multibar_fine.rb +45 -0
- data/lib/tessella/kinds/multibar_rows.rb +93 -0
- data/lib/tessella/kinds/pie.rb +123 -0
- data/lib/tessella/kinds/pie_rim.rb +78 -0
- data/lib/tessella/kinds/sideways.rb +62 -0
- data/lib/tessella/kinds/stem.rb +134 -0
- data/lib/tessella/kinds/threshold.rb +73 -0
- data/lib/tessella/legend.rb +31 -0
- data/lib/tessella/lint/alphabet.rb +56 -0
- data/lib/tessella/lint/drift.rb +82 -0
- data/lib/tessella/lint/fences.rb +51 -0
- data/lib/tessella/lint/geometry.rb +120 -0
- data/lib/tessella/lint/geometry_checks.rb +224 -0
- data/lib/tessella/lint/lines.rb +115 -0
- data/lib/tessella/lint/mixing.rb +61 -0
- data/lib/tessella/lint/runner.rb +73 -0
- data/lib/tessella/lint/shadows.rb +120 -0
- data/lib/tessella/lint/target_rows.rb +66 -0
- data/lib/tessella/lint.rb +158 -0
- data/lib/tessella/meter.rb +133 -0
- data/lib/tessella/meter_upright.rb +43 -0
- data/lib/tessella/png.rb +456 -0
- data/lib/tessella/raster.rb +92 -0
- data/lib/tessella/rmagick_reader.rb +52 -0
- data/lib/tessella/rule.rb +59 -0
- data/lib/tessella/seq.rb +522 -0
- data/lib/tessella/sparkline.rb +57 -0
- data/lib/tessella/stats.rb +199 -0
- data/lib/tessella/table.rb +547 -0
- data/lib/tessella/table_cells.rb +225 -0
- data/lib/tessella/target.rb +105 -0
- data/lib/tessella/text.rb +76 -0
- data/lib/tessella/text_forms.rb +150 -0
- data/lib/tessella/tree.rb +221 -0
- data/lib/tessella/version.rb +5 -0
- data/lib/tessella/wave.rb +353 -0
- data/lib/tessella/width.rb +122 -0
- data/lib/tessella/width_class.rb +77 -0
- data/lib/tessella/width_invisible.rb +66 -0
- data/lib/tessella/width_invisible_high.rb +60 -0
- data/lib/tessella.rb +94 -0
- metadata +226 -0
data/doc/charts.md
ADDED
|
@@ -0,0 +1,1370 @@
|
|
|
1
|
+
# Charts
|
|
2
|
+
|
|
3
|
+
A chart turns numbers into a framed figure: a plot area of character
|
|
4
|
+
cells, the y extremes on its left, the x extremes under it, a title
|
|
5
|
+
above and a legend on the right. There are eleven kinds:
|
|
6
|
+
|
|
7
|
+
| Kind | Draws | Input |
|
|
8
|
+
|-------------|--------------------------------------------|-----------------|
|
|
9
|
+
| `line` | points joined by straight segments | y, or x and y |
|
|
10
|
+
| `scatter` | points, not joined | y, or x and y |
|
|
11
|
+
| `stairs` | a step path between points | y, or x and y |
|
|
12
|
+
| `density` | points, shaded by how many share a cell | y, or x and y |
|
|
13
|
+
| `bar` | one horizontal bar per label | labels, values |
|
|
14
|
+
| `histogram` | counts of samples per bin, as bars | samples |
|
|
15
|
+
| `box` | a box-and-whisker plot per sample set | sets of samples |
|
|
16
|
+
| `stem` | a stem-and-leaf plot, as text | values |
|
|
17
|
+
| `heatmap` | a matrix as a grid of shaded cells | rows of values |
|
|
18
|
+
| `candlestick` | open, high, low, close per x, as candles | x, four prices |
|
|
19
|
+
| `pie` | shares of a whole, as a disc or a ring | labels, values |
|
|
20
|
+
|
|
21
|
+
Most charts on this page are drawn with `--target web`, which uses
|
|
22
|
+
quadrant blocks instead of braille: these pages are read on GitHub,
|
|
23
|
+
where braille is drawn about 1.2 columns wide and a braille chart
|
|
24
|
+
does not line up ([width targets](targets.md#web)). The few that stay
|
|
25
|
+
in braille, because braille is their subject, say so; read them in a
|
|
26
|
+
terminal. Every example on this page is the command's output, byte
|
|
27
|
+
for byte;
|
|
28
|
+
the input files are in [examples/](../examples/), and every command
|
|
29
|
+
runs there.
|
|
30
|
+
|
|
31
|
+
## From the command line
|
|
32
|
+
|
|
33
|
+
`tessella chart` reads one file, or stdin when no file is given, and
|
|
34
|
+
prints one chart. `--kind` picks the kind; `line` is the default.
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
$ tessella --target web chart --title trig --width 30 --height 6 trig.txt
|
|
38
|
+
trig
|
|
39
|
+
┌──────────────────────────────┐
|
|
40
|
+
1 │▀▜▄▀▀▀▚▖ ▗▀▀▀▚▟▀▀▀▚ │ sin
|
|
41
|
+
│ ▟▀▙ ▝▖ ▟▘ ▞▀▄ ▀▖ │ cos
|
|
42
|
+
│▞ ▝▚ ▝▖ ▞▘ ▗▞ ▝▖ ▜▖ │
|
|
43
|
+
│▀▀▀▀▀█▀▀▀▀▛▀▀█▀▀▀▀▛▀▀▀▀▀▛▀▀▀▜▛│
|
|
44
|
+
│ ▙ ▝▖▞ ▗▛ ▝▄ ▀│
|
|
45
|
+
-1 │ ▜▄▄▄▛▚▄▄▟▀ ▝▚▄▄▄│
|
|
46
|
+
└──────────────────────────────┘
|
|
47
|
+
0 10
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`trig.txt` is a header row `x sin cos` and 101 rows of numbers. The
|
|
51
|
+
first column is x; each further column is one series, named by the
|
|
52
|
+
header.
|
|
53
|
+
|
|
54
|
+
### The input format
|
|
55
|
+
|
|
56
|
+
- A line holding a comma splits on commas, one holding a tab on
|
|
57
|
+
tabs, any other on runs of spaces. A CSV or TSV label may therefore
|
|
58
|
+
hold spaces.
|
|
59
|
+
- Blank lines and lines starting with `#` are skipped.
|
|
60
|
+
- A first row that is not all numbers is a header: it names the
|
|
61
|
+
series (line, scatter, stairs, density), the boxes (box) or the two
|
|
62
|
+
sides (back-to-back stem). For `bar`, the first row is a header
|
|
63
|
+
when its value field is not a number.
|
|
64
|
+
- A number keeps its kind: `12` stays an Integer and prints `12`,
|
|
65
|
+
`7.5` stays a Float.
|
|
66
|
+
|
|
67
|
+
What each kind reads:
|
|
68
|
+
|
|
69
|
+
| Kind | Columns |
|
|
70
|
+
|---------------------------------------|-----------------------------------------------------------------|
|
|
71
|
+
| `line`, `scatter`, `stairs`, `density` | one column: y against 1..n; two: x y; more: x, then one series each |
|
|
72
|
+
| `bar` | label, value; or label and one value per series |
|
|
73
|
+
| `histogram` | one column of samples (further columns are ignored) |
|
|
74
|
+
| `box` | one or more columns, one box per column |
|
|
75
|
+
| `stem` | one column; two for the back-to-back form |
|
|
76
|
+
| `heatmap` | a label, then the row's values; a header names the columns |
|
|
77
|
+
| `candlestick` | x, open, high, low, close |
|
|
78
|
+
| `pie` | label, value |
|
|
79
|
+
|
|
80
|
+
## The kinds
|
|
81
|
+
|
|
82
|
+
### line, scatter, stairs
|
|
83
|
+
|
|
84
|
+
`line` joins consecutive points; `scatter` draws them alone; `stairs`
|
|
85
|
+
draws a step path. Each series gets the next colour of the cycle
|
|
86
|
+
(used only under `--color`) and, when it has a name, a legend entry.
|
|
87
|
+
|
|
88
|
+
```text
|
|
89
|
+
$ tessella --target web chart --kind scatter --width 30 --height 6 trig.txt
|
|
90
|
+
┌──────────────────────────────┐
|
|
91
|
+
1 │▀▜▄▀▀▀▚▖ ▗▀▀▀▚▟▀▀▀▚ │ sin
|
|
92
|
+
│ ▟▀▙ ▝▖ ▟▘ ▞▀▄ ▀▖ │ cos
|
|
93
|
+
│▞ ▝▚ ▝▖ ▞▘ ▗▞ ▝▖ ▜▖ │
|
|
94
|
+
│▀▀▀▀▀█▀▀▀▀▛▀▀█▀▀▀▀▛▀▀▀▀▀▛▀▀▀▜▛│
|
|
95
|
+
│ ▙ ▝▖▞ ▗▛ ▝▄ ▜│
|
|
96
|
+
-1 │ ▜▄▄▄▛▚▄▄▟▀ ▝▚▄▄▄│
|
|
97
|
+
└──────────────────────────────┘
|
|
98
|
+
0 10
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`stairs` steps after each point by default (`--style post`); `--style
|
|
102
|
+
pre` steps before it:
|
|
103
|
+
|
|
104
|
+
```text
|
|
105
|
+
$ printf '1 1\n2 3\n3 2\n4 4\n' | \
|
|
106
|
+
tessella --target web chart --kind stairs --style pre \
|
|
107
|
+
--width 20 --height 4
|
|
108
|
+
┌────────────────────┐
|
|
109
|
+
4 │ ▛▀▀▀▀▀▀│
|
|
110
|
+
│▛▀▀▀▀▀▜ ▌ │
|
|
111
|
+
│▌ ▐▄▄▄▄▄▄▌ │
|
|
112
|
+
1 │▌ │
|
|
113
|
+
└────────────────────┘
|
|
114
|
+
1 4
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Filled areas
|
|
118
|
+
|
|
119
|
+
`--area` (`area: true`) fills under each line or stairs series, from
|
|
120
|
+
the floor up, as btop draws its graphs. Every pixel column is a bar
|
|
121
|
+
of its own, so a block cell holds two bars of 0 to 2 (a braille cell
|
|
122
|
+
two of 0 to 4), and a peak narrower than a cell still shows. The y axis starts at 0 unless
|
|
123
|
+
`--ylim` says otherwise. `cpu.txt` is 60 load samples between 10 and
|
|
124
|
+
90:
|
|
125
|
+
|
|
126
|
+
```text
|
|
127
|
+
$ tessella --target web chart --area --width 30 --height 6 cpu.txt
|
|
128
|
+
┌──────────────────────────────┐
|
|
129
|
+
90 │ ▄██▙▄ ▟██▙▖ │
|
|
130
|
+
│ ▗██████▙ ▗██████▙ │
|
|
131
|
+
│▗████████▙▖ ▗████████▙ │
|
|
132
|
+
│▐██████████▖ ▟██████████▙│
|
|
133
|
+
│▐███████████▄ ▗▟████████████│
|
|
134
|
+
0 │▐█████████████▄▟██████████████│
|
|
135
|
+
└──────────────────────────────┘
|
|
136
|
+
0 60
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The same in braille, finer, and aligned only in a terminal; under
|
|
140
|
+
`--ascii` the fill is drawn in ASCII strokes:
|
|
141
|
+
|
|
142
|
+
```text
|
|
143
|
+
$ tessella chart --area --canvas braille --width 30 --height 6 cpu.txt
|
|
144
|
+
┌──────────────────────────────┐
|
|
145
|
+
90 │ ⢀⣴⣾⣿⣷⣄ ⢀⣴⣿⣿⣶⣄ │
|
|
146
|
+
│ ⢠⣾⣿⣿⣿⣿⣿⣧⡀ ⣠⣿⣿⣿⣿⣿⣿⣦ │
|
|
147
|
+
│⢠⣿⣿⣿⣿⣿⣿⣿⣿⣷⡀ ⣰⣿⣿⣿⣿⣿⣿⣿⣿⣧⡀│
|
|
148
|
+
│⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡄ ⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷│
|
|
149
|
+
│⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣄ ⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿│
|
|
150
|
+
0 │⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿│
|
|
151
|
+
└──────────────────────────────┘
|
|
152
|
+
0 60
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
```text
|
|
156
|
+
$ tessella chart --area --ascii --width 30 --height 6 cpu.txt
|
|
157
|
+
+------------------------------+
|
|
158
|
+
90 | .+###- .+###_ |
|
|
159
|
+
| _######+ -######- |
|
|
160
|
+
|-########+. -########+ |
|
|
161
|
+
|+##########. +##########+|
|
|
162
|
+
|+###########- .#############|
|
|
163
|
+
0 |+#############-###############|
|
|
164
|
+
+------------------------------+
|
|
165
|
+
0 60
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`--canvas eighths` fills one bar per character instead, in eighths
|
|
169
|
+
of a cell, `▁` to `█` (`▏` to `█` sideways): coarser across than
|
|
170
|
+
braille, finer up. It is for areas only (`--canvas eighths` without
|
|
171
|
+
`--area` is a usage error) and takes no `--threshold`.
|
|
172
|
+
|
|
173
|
+
```text
|
|
174
|
+
$ tessella chart --area --canvas eighths --width 30 --height 6 cpu.txt
|
|
175
|
+
┌──────────────────────────────┐
|
|
176
|
+
90 │ ▅▇█▇▄ ▁▅▇█▇▄ │
|
|
177
|
+
│ ▂██████▇▁ ▃██████▆ │
|
|
178
|
+
│▃█████████▂ ▄█████████▁│
|
|
179
|
+
│███████████▃ ▅███████████│
|
|
180
|
+
│████████████▅▁ ▁▆████████████│
|
|
181
|
+
0 │██████████████▆▆██████████████│
|
|
182
|
+
└──────────────────────────────┘
|
|
183
|
+
0 60
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
With `--ylim` the floor moves up, so the variation fills the height:
|
|
187
|
+
|
|
188
|
+
```text
|
|
189
|
+
$ tessella --target web chart --area --ylim 30,100 \
|
|
190
|
+
--width 30 --height 4 cpu.txt
|
|
191
|
+
┌──────────────────────────────┐
|
|
192
|
+
100 │ ▄▄▖ ▄▄▖ │
|
|
193
|
+
│ ▄█████▖ ▟████▙▖ │
|
|
194
|
+
│▗▟███████▙ ▗████████▄ │
|
|
195
|
+
30 │▐█████████▙▖ ▄██████████▙│
|
|
196
|
+
└──────────────────────────────┘
|
|
197
|
+
0 60
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Under `--color` a filled cell is coloured by its height, bottom row
|
|
201
|
+
first, from a gradient: `--gradient C,C,...` (`gradient: [...]`), by
|
|
202
|
+
default green, yellow, red in equal bands. A gradient whose colours
|
|
203
|
+
are all `#rrggbb` blends smoothly from the bottom row to the top
|
|
204
|
+
instead of in bands. `--gradient none` (`gradient: false`) keeps the
|
|
205
|
+
series' own colour. Without `--color` a gradient changes nothing and
|
|
206
|
+
the glyphs are plain.
|
|
207
|
+
|
|
208
|
+
`--area` is for line and stairs only, and `--gradient` needs
|
|
209
|
+
`--area`; anything else is a usage error:
|
|
210
|
+
|
|
211
|
+
```text
|
|
212
|
+
$ tessella chart --gradient red,blue cpu.txt
|
|
213
|
+
tessella chart: gradient: needs area: true
|
|
214
|
+
Usage: tessella chart [options] [file]
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### density
|
|
218
|
+
|
|
219
|
+
`density` draws the points on its own canvas, where a cell's shade
|
|
220
|
+
grows with the number of points that fall in it (` ░▒▓█`, or `
|
|
221
|
+
.:+#` under `--ascii`). It ignores `--canvas`, and draws no x = 0
|
|
222
|
+
or y = 0 axis line.
|
|
223
|
+
|
|
224
|
+
```text
|
|
225
|
+
$ tessella chart --kind density --width 30 --height 6 trig.txt
|
|
226
|
+
┌──────────────────────────────┐
|
|
227
|
+
1 │▓▒▓▓▒▒▓░ ▒▒▓▒▒█▒▒▓▒ │ sin
|
|
228
|
+
│ ▒▒▒ ▒▒ ▒░ ▒▒▒ ▒░ │ cos
|
|
229
|
+
│▒ ░▒ ░▒ ▒░ ░▒ ░▒ ▒░ │
|
|
230
|
+
│░ ░▒ ▒░ ▒░ ▒ ░▒ ▒░│
|
|
231
|
+
│ ▓ ▒▒▓ ░▒ ▒▒ ▒│
|
|
232
|
+
-1 │ ▒▒▓▒▓▓▒▒▓▒ ░▒▓▒▓│
|
|
233
|
+
└──────────────────────────────┘
|
|
234
|
+
0 10
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### bar
|
|
238
|
+
|
|
239
|
+
One bar per row, labelled on the left, with its value after it.
|
|
240
|
+
|
|
241
|
+
```text
|
|
242
|
+
$ tessella chart --kind bar --width 30 langs.csv
|
|
243
|
+
┌ ┐
|
|
244
|
+
ruby ┤██████████▍··············· 12
|
|
245
|
+
c ┤██████████████████████████ 30
|
|
246
|
+
rust ┤██████▌··················· 7.5
|
|
247
|
+
└ ┘
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
The default look draws the last, fractional cell in eighths
|
|
251
|
+
(`▏▎▍▌▋▊▉`) and fills the rest of each bar's width with a `·` track,
|
|
252
|
+
so a bar shows both its fraction and its share. Three options change
|
|
253
|
+
it: `--fill G` the bar glyph, `--no-eighths` whole cells only, and
|
|
254
|
+
`--track G` the track glyph (`--track none` for no track):
|
|
255
|
+
|
|
256
|
+
```text
|
|
257
|
+
$ tessella chart --kind bar --width 30 \
|
|
258
|
+
--fill ■ --no-eighths --track none langs.csv
|
|
259
|
+
┌ ┐
|
|
260
|
+
ruby ┤■■■■■■■■■■ 12
|
|
261
|
+
c ┤■■■■■■■■■■■■■■■■■■■■■■■■■■ 30
|
|
262
|
+
rust ┤■■■■■■■ 7.5
|
|
263
|
+
└ ┘
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Values may be negative. The bar area then splits at a zero column,
|
|
267
|
+
each side as wide as its share of the values' span; negative bars
|
|
268
|
+
grow left, and a negative bar's fractional end is a half cell (`▐`):
|
|
269
|
+
|
|
270
|
+
```text
|
|
271
|
+
$ tessella chart --kind bar --width 30 neg.csv
|
|
272
|
+
┌ ┐
|
|
273
|
+
a ┤█████████████████········· -6
|
|
274
|
+
b ┤·················█████████ 3
|
|
275
|
+
c ┤·························· 0
|
|
276
|
+
└ ┘
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
#### Several series
|
|
280
|
+
|
|
281
|
+
A row with more than one value draws one bar per series; the header
|
|
282
|
+
names the series, and a legend right of the frame shows each one's
|
|
283
|
+
fill. `hosts.csv` holds a load per host for three resources:
|
|
284
|
+
|
|
285
|
+
```text
|
|
286
|
+
$ cat hosts.csv
|
|
287
|
+
host,cpu,io,net
|
|
288
|
+
web,40,15,20
|
|
289
|
+
db,25,50,5
|
|
290
|
+
cache,10,5,30
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
By default the bars are grouped: each label gets one bar per series,
|
|
294
|
+
with a blank row between labels.
|
|
295
|
+
|
|
296
|
+
```text
|
|
297
|
+
$ tessella chart --kind bar --width 30 hosts.csv
|
|
298
|
+
┌ ┐
|
|
299
|
+
web ┤████████████████████▊····· 40 █ cpu
|
|
300
|
+
┤▓▓▓▓▓▓▓▓·················· 15 ▓ io
|
|
301
|
+
┤▒▒▒▒▒▒▒▒▒▒················ 20 ▒ net
|
|
302
|
+
┤
|
|
303
|
+
db ┤█████████████············· 25
|
|
304
|
+
┤▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 50
|
|
305
|
+
┤▒▒▒······················· 5
|
|
306
|
+
┤
|
|
307
|
+
cache ┤█████▎···················· 10
|
|
308
|
+
┤▓▓▓······················· 5
|
|
309
|
+
┤▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒·········· 30
|
|
310
|
+
└ ┘
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
`--stacked` (`stacked: true`) sets them end to end in one bar, its
|
|
314
|
+
total as the label:
|
|
315
|
+
|
|
316
|
+
```text
|
|
317
|
+
$ tessella chart --kind bar --stacked --width 30 hosts.csv
|
|
318
|
+
┌ ┐
|
|
319
|
+
web ┤█████████████▓▓▓▓▓▒▒▒▒▒▒·· 75 █ cpu
|
|
320
|
+
db ┤████████▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒ 80 ▓ io
|
|
321
|
+
cache ┤███▓▓▒▒▒▒▒▒▒▒▒▒··········· 45 ▒ net
|
|
322
|
+
└ ┘
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Both stand upright with `--orientation vertical`:
|
|
326
|
+
|
|
327
|
+
```text
|
|
328
|
+
$ tessella chart --kind bar --stacked --orientation vertical \
|
|
329
|
+
--width 20 --height 6 hosts.csv
|
|
330
|
+
┌────────────────────┐
|
|
331
|
+
80 │▒▒▒▒▒▒ ▓▓▓▓▓▓ │ █ cpu
|
|
332
|
+
│▒▒▒▒▒▒ ▓▓▓▓▓▓ │ ▓ io
|
|
333
|
+
│▓▓▓▓▓▓ ▓▓▓▓▓▓ │ ▒ net
|
|
334
|
+
│██████ ▓▓▓▓▓▓ ▒▒▒▒▒▒│
|
|
335
|
+
│██████ ██████ ▒▒▒▒▒▒│
|
|
336
|
+
0 │██████ ██████ ██████│
|
|
337
|
+
└────────────────────┘
|
|
338
|
+
web db cache
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
With more series than labels the legend no longer fits beside the
|
|
342
|
+
bars, so it goes under the frame, wrapped to the plot's width (for
|
|
343
|
+
upright columns,
|
|
344
|
+
whose names take that line, on the x-label line, unless `--xlabel`
|
|
345
|
+
is given). Here the first two hosts only:
|
|
346
|
+
|
|
347
|
+
```text
|
|
348
|
+
$ head -3 hosts.csv | tessella chart --kind bar --stacked --width 30
|
|
349
|
+
┌ ┐
|
|
350
|
+
web ┤█████████████▓▓▓▓▓▒▒▒▒▒▒·· 75
|
|
351
|
+
db ┤████████▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒ 80
|
|
352
|
+
└ ┘
|
|
353
|
+
█ cpu ▓ io ▒ net
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
Each series has a fill of its own, from twelve: `█ ▓ ▒ ░ ╳ ╱ ╲ ∴ ● ○
|
|
357
|
+
◆ ·`, or `# = + @ * : . o % & ~ x` under `--ascii`. So a chart holds
|
|
358
|
+
at most 12 series; a 13th is refused. Only a `█` series ends in an
|
|
359
|
+
eighth. Bars of several series need values of 0 or more.
|
|
360
|
+
|
|
361
|
+
Under `--color`, where two stacked series meet inside a cell, that
|
|
362
|
+
cell is split to the eighth: an eighths glyph in the first series'
|
|
363
|
+
colour on the second's as background, so the boundary falls exactly
|
|
364
|
+
where the values put it. Without colour the cell keeps the plain
|
|
365
|
+
glyph of one series.
|
|
366
|
+
|
|
367
|
+
```text
|
|
368
|
+
$ tessella chart --kind bar --stacked --ascii --width 30 hosts.csv
|
|
369
|
+
+ +
|
|
370
|
+
web |#############=====++++++.. 75 # cpu
|
|
371
|
+
db |########================++ 80 = io
|
|
372
|
+
cache |###==++++++++++........... 45 + net
|
|
373
|
+
+ +
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
In Ruby, the values are an Array of Arrays, one per label, and
|
|
377
|
+
`series:` names them:
|
|
378
|
+
|
|
379
|
+
```ruby
|
|
380
|
+
Tessella.bar(%w[web db cache], [[40, 15, 20], [25, 50, 5], [10, 5, 30]],
|
|
381
|
+
series: %w[cpu io net], stacked: true, width: 30)
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### histogram
|
|
385
|
+
|
|
386
|
+
`histogram` bins one column of samples and draws the counts as bars,
|
|
387
|
+
with the same bar options. `--bins N` sets the number of bins (by
|
|
388
|
+
default Sturges' rule, ⌈log₂ n⌉ + 1, as unicode_plot picks it);
|
|
389
|
+
`--closed left` (the default) bins as `[a, b)`, `--closed right` as
|
|
390
|
+
`(a, b]`. Every sample lands in exactly one bin.
|
|
391
|
+
|
|
392
|
+
```text
|
|
393
|
+
$ tessella chart --kind histogram --width 30 --bins 8 normal.txt
|
|
394
|
+
┌ ┐
|
|
395
|
+
[-3.0, -2.0) ┤██▉······················· 8
|
|
396
|
+
[-2.0, -1.0) ┤██████████▏··············· 28
|
|
397
|
+
[-1.0, 0.0) ┤██████████████████████████ 72
|
|
398
|
+
[ 0.0, 1.0) ┤██████████████████████···· 61
|
|
399
|
+
[ 1.0, 2.0) ┤██████████▏··············· 28
|
|
400
|
+
[ 2.0, 3.0) ┤█▏························ 3
|
|
401
|
+
└ ┘
|
|
402
|
+
Frequency
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
`--bins` is a request: the edges are rounded to nice values, which
|
|
406
|
+
can give fewer bins than asked, as here.
|
|
407
|
+
|
|
408
|
+
### box
|
|
409
|
+
|
|
410
|
+
One box per column: whiskers from minimum to maximum, the box from
|
|
411
|
+
the first to the third quartile, the median inside it. The axis under
|
|
412
|
+
the boxes shows the minimum, the middle and the maximum of the range.
|
|
413
|
+
|
|
414
|
+
```text
|
|
415
|
+
$ tessella chart --kind box --width 40 samples.txt
|
|
416
|
+
┌ ┐
|
|
417
|
+
╷ ┬─┐ ╷
|
|
418
|
+
a ├─│ ├─┤
|
|
419
|
+
╵ ┴─┘ ╵
|
|
420
|
+
╷┌┬┐ ╷
|
|
421
|
+
b ├┤│├─────┤
|
|
422
|
+
╵└┴┘ ╵
|
|
423
|
+
╷ ┌┬┐ ╷
|
|
424
|
+
c ├──┤│├──────────────────────────────┤
|
|
425
|
+
╵ └┴┘ ╵
|
|
426
|
+
└ ┘
|
|
427
|
+
0 15 30
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
The box draws its own open frame; it takes no `border:`.
|
|
431
|
+
|
|
432
|
+
### stem
|
|
433
|
+
|
|
434
|
+
A stem-and-leaf plot is text, not a canvas: one line per stem, its
|
|
435
|
+
leaves after the bar, and a key under it. `--scale N` sets what one
|
|
436
|
+
stem step is worth (10 by default): at scale 10, `2 | 37` reads 23
|
|
437
|
+
and 27.
|
|
438
|
+
|
|
439
|
+
```text
|
|
440
|
+
$ tessella chart --kind stem stem.txt
|
|
441
|
+
1 | 25
|
|
442
|
+
2 | 1337
|
|
443
|
+
3 | 148
|
|
444
|
+
4 | 57
|
|
445
|
+
5 | 2
|
|
446
|
+
Key: 1|0 = 10
|
|
447
|
+
The decimal is 1 digit(s) to the right of |
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
Two columns give the back-to-back form, the first column's leaves
|
|
451
|
+
read leftwards:
|
|
452
|
+
|
|
453
|
+
```text
|
|
454
|
+
$ tessella chart --kind stem ages.txt
|
|
455
|
+
52 | 1 | 8
|
|
456
|
+
731 | 2 | 25
|
|
457
|
+
84 | 3 | 136
|
|
458
|
+
5 | 4 | 14
|
|
459
|
+
Key: 1|0 = 10
|
|
460
|
+
The decimal is 1 digit(s) to the right of |
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
A plot that would need more than 1000 stems is refused: raise
|
|
464
|
+
`--scale`.
|
|
465
|
+
|
|
466
|
+
### heatmap
|
|
467
|
+
|
|
468
|
+
A heatmap draws a matrix as a grid of cells, each shaded by its value
|
|
469
|
+
along ` ░▒▓█`, with the row names on the left and a key on the right
|
|
470
|
+
giving the range. `week.txt` is a load per day and per three hours.
|
|
471
|
+
Its first row names the columns because `0h`, `3h` are not numbers;
|
|
472
|
+
a header of `00 03 06` would be read as a row of data, by the rule of
|
|
473
|
+
[the input format](#the-input-format):
|
|
474
|
+
|
|
475
|
+
```text
|
|
476
|
+
$ head -3 week.txt
|
|
477
|
+
day 0h 3h 6h 9h 12h 15h 18h 21h
|
|
478
|
+
mon 10 14 18 72 76 63 67 21
|
|
479
|
+
tue 23 10 14 68 72 76 63 17
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
```text
|
|
483
|
+
$ tessella chart --kind heatmap week.txt
|
|
484
|
+
┌────────────────┐
|
|
485
|
+
mon │░░░░░░████▓▓██░░│ █ 76
|
|
486
|
+
tue │░░░░░░██████▓▓░░│
|
|
487
|
+
wed │░░░░░░▓▓██████░░│
|
|
488
|
+
thu │░░░░░░▓▓▓▓████░░│
|
|
489
|
+
fri │░░░░░░██▓▓▓▓██░░│
|
|
490
|
+
sat │ ▒▒▒▒▒▒▒▒ │
|
|
491
|
+
sun │ ▒▒▒▒▒▒▒▒ │ 0
|
|
492
|
+
└────────────────┘
|
|
493
|
+
0h 21h
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
A cell is `--cell-width` columns wide, 2 by default (near square in a
|
|
497
|
+
terminal). The column names go under the frame when each is narrower
|
|
498
|
+
than a cell, else only the first and last, at the two ends, as in
|
|
499
|
+
the map above. At four columns a cell, every name fits:
|
|
500
|
+
|
|
501
|
+
```text
|
|
502
|
+
$ tessella chart --kind heatmap --cell-width 4 week.txt
|
|
503
|
+
┌────────────────────────────────┐
|
|
504
|
+
mon │░░░░░░░░░░░░████████▓▓▓▓████░░░░│ █ 76
|
|
505
|
+
tue │░░░░░░░░░░░░████████████▓▓▓▓░░░░│
|
|
506
|
+
wed │░░░░░░░░░░░░▓▓▓▓████████████░░░░│
|
|
507
|
+
thu │░░░░░░░░░░░░▓▓▓▓▓▓▓▓████████░░░░│
|
|
508
|
+
fri │░░░░░░░░░░░░████▓▓▓▓▓▓▓▓████░░░░│
|
|
509
|
+
sat │ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ │
|
|
510
|
+
sun │ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ │ 0
|
|
511
|
+
└────────────────────────────────┘
|
|
512
|
+
0h 3h 6h 9h 12h 15h 18h 21h
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
Under `--ascii` the ramp is ` .:-=+*#%@`. Under `--color` each cell is
|
|
516
|
+
a `█` coloured along a colormap, a viridis-like blend by default, or
|
|
517
|
+
`--colormap C,C,...` stops in any [colour form](#colour); the key then
|
|
518
|
+
says "max" and "min" in words. `--min` and `--max` fix the range, so
|
|
519
|
+
maps drawn apart share one scale. A map of one row gives its key as
|
|
520
|
+
`lo..hi`:
|
|
521
|
+
|
|
522
|
+
```text
|
|
523
|
+
$ printf 'x 1 2 3 4\n' | tessella chart --kind heatmap
|
|
524
|
+
┌────────┐
|
|
525
|
+
x │ ░░▓▓██│ 1..4
|
|
526
|
+
└────────┘
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
The matrix sets the size, so `--width` and `--height` are refused. In
|
|
530
|
+
Ruby:
|
|
531
|
+
|
|
532
|
+
```ruby
|
|
533
|
+
Tessella.heatmap(matrix, xlabels: nil, ylabels: nil, cell_width: 2,
|
|
534
|
+
colormap: nil, min: nil, max: nil, **opts)
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
### candlestick
|
|
538
|
+
|
|
539
|
+
A candlestick chart draws, per x, the range a price moved in (the
|
|
540
|
+
wick, `│`, from low to high) and where it opened and closed (the
|
|
541
|
+
body). An up candle, closing at or above its open, is `█`; a down
|
|
542
|
+
one `▒`; one that closes where it opened, `─`. Under `--color` up is
|
|
543
|
+
green and down red. `ohlc.txt` is a week of prices, x as ISO dates:
|
|
544
|
+
|
|
545
|
+
```text
|
|
546
|
+
$ cat ohlc.txt
|
|
547
|
+
date open high low close
|
|
548
|
+
2026-11-02 100 104 98 103
|
|
549
|
+
2026-11-03 103 107 101 102
|
|
550
|
+
2026-11-04 102 103 95 96
|
|
551
|
+
2026-11-05 96 99 94 98
|
|
552
|
+
2026-11-06 98 105 97 104
|
|
553
|
+
2026-11-09 104 106 102 104
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
```text
|
|
557
|
+
$ tessella chart --kind candlestick --xdate --width 30 --height 8 ohlc.txt
|
|
558
|
+
┌─────────────────────────────┐
|
|
559
|
+
110 │ │
|
|
560
|
+
│ │ │ │
|
|
561
|
+
│████ ▒▒▒▒ │ ████ ────│
|
|
562
|
+
│████ ▒▒▒▒ ▒▒▒▒ ████ │ │
|
|
563
|
+
│████ ▒▒▒▒ ████ ████ │
|
|
564
|
+
│ ▒▒▒▒ ████ │ │
|
|
565
|
+
│ │ │
|
|
566
|
+
90 │ │
|
|
567
|
+
└─────────────────────────────┘
|
|
568
|
+
2026-11-02 2026-11-09
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
The candles share the width, each as wide as its share allows with a
|
|
572
|
+
blank column between (one column each and no gap when they do not
|
|
573
|
+
fit), the wick in the middle column. The first and last x go under
|
|
574
|
+
the frame, as dates with `--xdate` (formatted as on a
|
|
575
|
+
[date axis](#dates-on-the-x-axis)). Under `--ascii` an up candle is
|
|
576
|
+
`#`, a down one `=`:
|
|
577
|
+
|
|
578
|
+
```text
|
|
579
|
+
$ tessella chart --kind candlestick --xdate --ascii \
|
|
580
|
+
--width 30 --height 8 ohlc.txt
|
|
581
|
+
+-----------------------------+
|
|
582
|
+
110 | |
|
|
583
|
+
| | | |
|
|
584
|
+
|#### ==== | #### ----|
|
|
585
|
+
|#### ==== ==== #### | |
|
|
586
|
+
|#### ==== #### #### |
|
|
587
|
+
| ==== #### | |
|
|
588
|
+
| | |
|
|
589
|
+
90 | |
|
|
590
|
+
+-----------------------------+
|
|
591
|
+
2026-11-02 2026-11-09
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
A low above the open or the close, or a high below them, is refused.
|
|
595
|
+
In Ruby:
|
|
596
|
+
|
|
597
|
+
```ruby
|
|
598
|
+
Tessella.candlestick(x, open:, high:, low:, close:, **opts)
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
### pie
|
|
602
|
+
|
|
603
|
+
A pie draws each value as a slice of a disc, clockwise from the top,
|
|
604
|
+
with a legend giving each label's share in whole percents that add
|
|
605
|
+
up to 100. It has no frame and no axes.
|
|
606
|
+
|
|
607
|
+
```text
|
|
608
|
+
$ tessella chart --kind pie langs.csv
|
|
609
|
+
▒▒▒▒▒█████
|
|
610
|
+
▒▒▒▒▒▒▒▒████████
|
|
611
|
+
▒▒▒▒▒▒▒▒▒▒██████████
|
|
612
|
+
▓▓▓▓▒▒▒▒▒▒▒███████████
|
|
613
|
+
▓▓▓▓▓▓▓▓▒▒▒▒████████████ █ ruby 24 %
|
|
614
|
+
▓▓▓▓▓▓▓▓▓▓▓▒████████████ ▓ c 61 %
|
|
615
|
+
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▒ rust 15 %
|
|
616
|
+
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
|
|
617
|
+
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
|
|
618
|
+
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
|
|
619
|
+
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
|
|
620
|
+
▓▓▓▓▓▓▓▓▓▓
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
`--donut` (`donut: true`) cuts out the middle:
|
|
624
|
+
|
|
625
|
+
```text
|
|
626
|
+
$ tessella chart --kind pie --donut langs.csv
|
|
627
|
+
▒▒▒▒▒█████
|
|
628
|
+
▒▒▒▒▒▒▒▒████████
|
|
629
|
+
▒▒▒▒▒▒▒▒▒▒██████████
|
|
630
|
+
▓▓▓▓▒▒▒▒ ████████
|
|
631
|
+
▓▓▓▓▓▓▓ ███████ █ ruby 24 %
|
|
632
|
+
▓▓▓▓▓▓ ██████ ▓ c 61 %
|
|
633
|
+
▓▓▓▓▓▓ ▓▓▓▓▓▓ ▒ rust 15 %
|
|
634
|
+
▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓
|
|
635
|
+
▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓
|
|
636
|
+
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
|
|
637
|
+
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
|
|
638
|
+
▓▓▓▓▓▓▓▓▓▓
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
Each slice has a fill of its own, the twelve bars use (`█ ▓ ▒ ░ ╳ ╱
|
|
642
|
+
╲ ∴ ● ○ ◆ ·`, or `# = + @ * : . o % & ~ x` under `--ascii`), and a
|
|
643
|
+
colour under `--color`; a 13th slice is refused. `--height` sizes
|
|
644
|
+
the disc, 12 rows by default; its width follows, a cell being about
|
|
645
|
+
twice as tall as wide. With more slices than the disc has rows, the
|
|
646
|
+
legend goes under it, wrapped to the disc's width or 40 columns,
|
|
647
|
+
whichever is wider. `os.csv` has nine slices:
|
|
648
|
+
|
|
649
|
+
```text
|
|
650
|
+
$ tessella chart --kind pie --height 6 os.csv
|
|
651
|
+
╳╱∴███
|
|
652
|
+
░░░╳╲█████
|
|
653
|
+
▒▒▒░░╳██████
|
|
654
|
+
▒▒▒▒▒▓▓█████
|
|
655
|
+
▒▒▓▓▓▓▓███
|
|
656
|
+
▓▓▓▓▓▓
|
|
657
|
+
█ linux 41 % ▓ macos 22 %
|
|
658
|
+
▒ windows 18 % ░ freebsd 9 %
|
|
659
|
+
╳ openbsd 4 % ╱ netbsd 2 % ╲ haiku 2 %
|
|
660
|
+
∴ plan9 1 % ● qnx 1 %
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
```text
|
|
664
|
+
$ tessella chart --kind pie --ascii --height 8 langs.csv
|
|
665
|
+
++++####
|
|
666
|
+
++++++######
|
|
667
|
+
===++++####### # ruby 24 %
|
|
668
|
+
=======+######## = c 61 %
|
|
669
|
+
================ + rust 15 %
|
|
670
|
+
==============
|
|
671
|
+
============
|
|
672
|
+
========
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
By default a cell belongs whole to one slice, so the disc's edge is
|
|
676
|
+
stepped. `--rim smooth` (`rim: :smooth`) draws each cell the disc, or
|
|
677
|
+
a donut's hole, only partly covers as the shape glyph that fits it
|
|
678
|
+
best (`◢◣◤◥`, halves, quadrants, quarter blocks), in its slice's
|
|
679
|
+
colour:
|
|
680
|
+
|
|
681
|
+
```text
|
|
682
|
+
$ tessella chart --kind pie --donut --rim smooth --height 8 langs.csv
|
|
683
|
+
▁▂▄▆█▒██▆▄▂▁
|
|
684
|
+
▗█▒▒▒▒▒██████▖
|
|
685
|
+
◢▓▓▓█▀▔ ▔▀████◣ █ ruby 24 %
|
|
686
|
+
█▓▓▓▘ ▝████ ▓ c 61 %
|
|
687
|
+
█▓▓▓▖ ▗▓▓▓█ ▒ rust 15 %
|
|
688
|
+
◥▓▓▓█▄▁ ▁▄█▓▓▓◤
|
|
689
|
+
▝█▓▓▓▓▓▓▓▓▓▓█▘
|
|
690
|
+
▔🮂▀🮅█▓▓█🮅▀🮂▔
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
The rim glyphs are solid, so without colour they draw the edge as an
|
|
694
|
+
outline in the nearest slice's fill. `--rim basic` leaves out `🮊 🮂
|
|
695
|
+
🮅`, which older fonts lack. `--rim cells` is the default; `--ascii`
|
|
696
|
+
refuses the other two, and only a pie takes `--rim`.
|
|
697
|
+
|
|
698
|
+
A pie takes no `--width`, `--xlim`, `--ylim`, `--canvas` or
|
|
699
|
+
`--xscale` (usage errors, exit 2), and reads exactly a label and a
|
|
700
|
+
value a row:
|
|
701
|
+
|
|
702
|
+
```text
|
|
703
|
+
$ tessella chart --kind pie hosts.csv
|
|
704
|
+
tessella chart: row 1 has 4 columns: pie reads label value
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
In Ruby:
|
|
708
|
+
|
|
709
|
+
```ruby
|
|
710
|
+
Tessella.pie(labels, values, donut: false, rim: :cells, **opts)
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
## Orientation
|
|
714
|
+
|
|
715
|
+
`--orientation horizontal|vertical` (`orientation:`) is the direction
|
|
716
|
+
the value axis runs. Every kind but stem takes it; bar, histogram and
|
|
717
|
+
box are horizontal by default, the plotted kinds vertical.
|
|
718
|
+
|
|
719
|
+
### Upright bars
|
|
720
|
+
|
|
721
|
+
`--orientation vertical` draws a bar chart as columns rising from a
|
|
722
|
+
floor, the value axis on the left from 0 to the largest value. The
|
|
723
|
+
names go under their columns when each fits, else the first and last
|
|
724
|
+
name go at the two ends:
|
|
725
|
+
|
|
726
|
+
```text
|
|
727
|
+
$ tessella chart --kind bar --orientation vertical --width 20 --height 5 \
|
|
728
|
+
langs.csv
|
|
729
|
+
┌────────────────────┐
|
|
730
|
+
30 │ ██████ │
|
|
731
|
+
│ ██████ │
|
|
732
|
+
│ ██████ │
|
|
733
|
+
│██████ ██████ ▂▂▂▂▂▂│
|
|
734
|
+
0 │██████ ██████ ██████│
|
|
735
|
+
└────────────────────┘
|
|
736
|
+
ruby c rust
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
A histogram stands its bins up the same way, with its axis's two ends
|
|
740
|
+
under them:
|
|
741
|
+
|
|
742
|
+
```text
|
|
743
|
+
$ tessella chart --kind histogram --orientation vertical \
|
|
744
|
+
--width 24 --height 6 normal.txt
|
|
745
|
+
┌───────────────────────┐
|
|
746
|
+
72 │ ███ ▁▁▁ │
|
|
747
|
+
│ ███ ███ │
|
|
748
|
+
Frequency │ ███ ███ │
|
|
749
|
+
│ ▃▃▃ ███ ███ ▃▃▃ │
|
|
750
|
+
│ ███ ███ ███ ███ │
|
|
751
|
+
0 │▅▅▅ ███ ███ ███ ███ ▂▂▂│
|
|
752
|
+
└───────────────────────┘
|
|
753
|
+
-3.0 3.0
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
Upright bars need values of 0 or more. `--fill` sets the glyph of
|
|
757
|
+
their full cells; `--track` is for bars across only, and is refused
|
|
758
|
+
here. A value above 0 always draws at least one step, so a bin that
|
|
759
|
+
holds anything never looks empty, even in ASCII, where a step is a
|
|
760
|
+
whole row:
|
|
761
|
+
|
|
762
|
+
```text
|
|
763
|
+
$ tessella chart --kind histogram --orientation vertical --ascii \
|
|
764
|
+
--width 18 --height 4 normal.txt
|
|
765
|
+
+-----------------+
|
|
766
|
+
72 | ## |
|
|
767
|
+
Frequency | ## ## |
|
|
768
|
+
| ## ## ## ## |
|
|
769
|
+
0 |## ## ## ## ## ##|
|
|
770
|
+
+-----------------+
|
|
771
|
+
-3.0 3.0
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
```text
|
|
775
|
+
$ tessella chart --kind bar --orientation vertical neg.csv
|
|
776
|
+
tessella chart: a vertical eighths bar chart needs values of 0 or more
|
|
777
|
+
Usage: tessella chart [options] [file]
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
### Upright boxes
|
|
781
|
+
|
|
782
|
+
A vertical box stands three columns wide, its whiskers running up and
|
|
783
|
+
down: `╶┬╴` at the maximum, `┌┴┐` at the third quartile, `├─┤` at the
|
|
784
|
+
median, `└┬┘` at the first quartile, `╶┴╴` at the minimum. The value
|
|
785
|
+
axis on the left shows its two ends and middle (`--ylim` sets the
|
|
786
|
+
range), the names go under the boxes, and where the median shares a
|
|
787
|
+
row with an edge of the box, the median is drawn.
|
|
788
|
+
|
|
789
|
+
```text
|
|
790
|
+
$ tessella chart --kind box --orientation vertical --height 10 samples.txt
|
|
791
|
+
┌────────────┐
|
|
792
|
+
30 │ ╶┬╴ │
|
|
793
|
+
│ │ │
|
|
794
|
+
│ │ │
|
|
795
|
+
│ │ │
|
|
796
|
+
15 │ │ │
|
|
797
|
+
│ │ │
|
|
798
|
+
│ ╶┬╴ │ │
|
|
799
|
+
│ │ ├─┤ │
|
|
800
|
+
│├─┤ ├─┤ ╶┴╴ │
|
|
801
|
+
0 │╶┴╴ │
|
|
802
|
+
└────────────┘
|
|
803
|
+
a b c
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
### Sideways plots
|
|
807
|
+
|
|
808
|
+
For line, scatter, stairs and density, `--orientation horizontal`
|
|
809
|
+
swaps the axes: values run along the horizontal axis and x runs up,
|
|
810
|
+
so a horizontal chart of (x, y) is the vertical chart of (y, x).
|
|
811
|
+
`--xlim`, `--ylim`, `--xlabel` and `--ylabel` keep their meaning and
|
|
812
|
+
move with their axis; an area fills from the left edge, its gradient
|
|
813
|
+
running left to right.
|
|
814
|
+
|
|
815
|
+
```text
|
|
816
|
+
$ tessella --target web chart --orientation horizontal --area \
|
|
817
|
+
--width 24 --height 8 cpu.txt
|
|
818
|
+
┌────────────────────────┐
|
|
819
|
+
60 │██████████████▙▄▄▄▄▄▄ │
|
|
820
|
+
│████████████████████████│
|
|
821
|
+
│█████████████████▛▀▀▀▀▘ │
|
|
822
|
+
│████▛▀▀▀▀▀▘ │
|
|
823
|
+
│███▙▄▄▄▄ │
|
|
824
|
+
│███████████████▄▄▄▄▖ │
|
|
825
|
+
│███████████████████████▙│
|
|
826
|
+
0 │█████████████████▀▀▀▀▀▘ │
|
|
827
|
+
└────────────────────────┘
|
|
828
|
+
0 90
|
|
829
|
+
```
|
|
830
|
+
|
|
831
|
+
## Bar glyphs
|
|
832
|
+
|
|
833
|
+
`--blocks` (`blocks:`) picks the glyphs bars and histograms are built
|
|
834
|
+
of:
|
|
835
|
+
|
|
836
|
+
| Blocks | Upright | Across |
|
|
837
|
+
|-----------|------------------------------------|------------------------------------|
|
|
838
|
+
| `eighths` | `▁`…`█`, 8 steps a cell (default) | `▏`…`█`, 8 steps a cell (default) |
|
|
839
|
+
| `half` | `▄` `█`, one bar a column | `▌` `█`, one bar a row |
|
|
840
|
+
| `block` | quadrants, two bars a column | quadrants, two bars a row |
|
|
841
|
+
| `braille` | dots, two bars a column | dots, four bars a row |
|
|
842
|
+
| `sextant` | sextants, two bars a column | sextants, three bars a row |
|
|
843
|
+
| `octant` | octants, two bars a column | octants, four bars a row |
|
|
844
|
+
|
|
845
|
+
`quadrant` is another name for `block`. The finer glyphs pack more
|
|
846
|
+
bars into the same width; across, a text row holds as many bars as
|
|
847
|
+
its cell has pixel rows, and is named by its first and last bar,
|
|
848
|
+
`ruby..c`. (The braille example below is aligned only in a
|
|
849
|
+
terminal.) Every glyph set but `eighths` draws one series only (bars
|
|
850
|
+
of [several series](#several-series) need `eighths`), and `sextant`
|
|
851
|
+
and `octant` need a font that has them (see [canvases](#canvases)).
|
|
852
|
+
|
|
853
|
+
```text
|
|
854
|
+
$ tessella chart --kind bar --orientation vertical --blocks braille \
|
|
855
|
+
--width 20 --height 5 langs.csv
|
|
856
|
+
┌────────────────────┐
|
|
857
|
+
30 │ ⢸⣿⣿⣿⣿⣿⡇ │
|
|
858
|
+
│ ⢸⣿⣿⣿⣿⣿⡇ │
|
|
859
|
+
│ ⢸⣿⣿⣿⣿⣿⡇ │
|
|
860
|
+
│⣿⣿⣿⣿⣿⣿⢸⣿⣿⣿⣿⣿⡇⣀⣀⣀⣀⣀⣀ │
|
|
861
|
+
0 │⣿⣿⣿⣿⣿⣿⢸⣿⣿⣿⣿⣿⡇⣿⣿⣿⣿⣿⣿ │
|
|
862
|
+
└────────────────────┘
|
|
863
|
+
ruby rust
|
|
864
|
+
```
|
|
865
|
+
|
|
866
|
+
```text
|
|
867
|
+
$ tessella chart --kind bar --blocks block --width 30 langs.csv
|
|
868
|
+
┌──────────────────────────────┐
|
|
869
|
+
ruby..c │████████████▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│
|
|
870
|
+
rust │▀▀▀▀▀▀▀▘ │
|
|
871
|
+
└──────────────────────────────┘
|
|
872
|
+
0 30
|
|
873
|
+
```
|
|
874
|
+
|
|
875
|
+
```text
|
|
876
|
+
$ tessella chart --kind histogram --blocks half --width 24 normal.txt
|
|
877
|
+
┌────────────────────────┐
|
|
878
|
+
-3.0..-2.0 │██▌ │
|
|
879
|
+
-2.0..-1.0 │█████████▌ │
|
|
880
|
+
-1.0..0.0 │████████████████████████│
|
|
881
|
+
0.0..1.0 │████████████████████▌ │
|
|
882
|
+
1.0..2.0 │█████████▌ │
|
|
883
|
+
2.0..3.0 │█ │
|
|
884
|
+
└────────────────────────┘
|
|
885
|
+
0 72
|
|
886
|
+
Frequency
|
|
887
|
+
```
|
|
888
|
+
|
|
889
|
+
Every glyph set but the default `eighths` needs values of 0 or more,
|
|
890
|
+
and `braille` and `block` take no `--ascii`, `--fill`,
|
|
891
|
+
`--no-eighths` or `--track`. As upright, a value above 0 draws at
|
|
892
|
+
least one step (a dot, a quadrant, a half cell); only the default
|
|
893
|
+
eighths bars across round as unicode_plot does, so a small value can
|
|
894
|
+
draw nothing there.
|
|
895
|
+
|
|
896
|
+
A refused combination is a usage error:
|
|
897
|
+
|
|
898
|
+
```text
|
|
899
|
+
$ tessella chart --kind bar --blocks braille --ascii langs.csv
|
|
900
|
+
tessella chart: blocks: braille conflicts with ascii: true
|
|
901
|
+
Usage: tessella chart [options] [file]
|
|
902
|
+
```
|
|
903
|
+
|
|
904
|
+
## Canvases
|
|
905
|
+
|
|
906
|
+
The line, scatter and stairs kinds draw on a canvas, a grid of cells
|
|
907
|
+
each holding a few pixels. `--canvas` picks it:
|
|
908
|
+
|
|
909
|
+
| Canvas | Pixels per cell | Glyphs |
|
|
910
|
+
|-----------|-----------------|------------------------------|
|
|
911
|
+
| `braille` | 2 × 4 | braille patterns (default) |
|
|
912
|
+
| `block` | 2 × 2 | quadrant blocks `▘▝▀▖▌▞▛…` (also named `quadrant`) |
|
|
913
|
+
| `half` | 1 × 2 | half blocks `▀ ▄ █` |
|
|
914
|
+
| `sextant` | 2 × 3 | teletext sextants (Unicode 13) |
|
|
915
|
+
| `octant` | 2 × 4 | octants (Unicode 16) |
|
|
916
|
+
| `eighths` | 1 × 8 | `▁`…`█`, for `--area` only |
|
|
917
|
+
| `dot` | 1 × 2 | `'` `.` `:` |
|
|
918
|
+
| `ascii` | 3 × 3 | ASCII strokes `- \| / \ "`… |
|
|
919
|
+
| `density` | 1 × 2 | shades by hit count |
|
|
920
|
+
|
|
921
|
+
`sextant` and `octant` draw solid blocks where braille draws dots.
|
|
922
|
+
Their glyphs are recent: sextants are Unicode 13 (2020), octants
|
|
923
|
+
Unicode 16 (2024), drawn only by the newest terminals (Ghostty and its
|
|
924
|
+
like), so this page shows no octant render. Check the reader's font
|
|
925
|
+
before using either.
|
|
926
|
+
|
|
927
|
+
```text
|
|
928
|
+
$ tessella chart --canvas sextant --width 24 --height 5 trig.txt
|
|
929
|
+
┌────────────────────────┐
|
|
930
|
+
1 │🬂🬪🬔🬂🬂🬩 🬞🬜🬂🬂🬧🬜🬂🬂🬩 │ sin
|
|
931
|
+
│🬦🬀🬈🬏 🬪 🬕 🬞🬆🬉🬓 🬧🬏 │ cos
|
|
932
|
+
│🬌🬋🬋🬎🬚🬋🬋🬪🬋🬋🬋🬜🬋🬋🬩🬌🬋🬋🬌🬚🬋🬋🬪🬚│
|
|
933
|
+
│ 🬊🬏 🬪🬞🬔 🬦🬄 🬈🬏 🬈│
|
|
934
|
+
-1 │ 🬉🬱🬭🬵🬎🬭🬭🬖🬀 🬊🬢🬭🬭│
|
|
935
|
+
└────────────────────────┘
|
|
936
|
+
0 10
|
|
937
|
+
```
|
|
938
|
+
|
|
939
|
+
Braille gives the finest line, but only a terminal keeps it aligned;
|
|
940
|
+
block lines up on the web too; ASCII survives any font:
|
|
941
|
+
|
|
942
|
+
```text
|
|
943
|
+
$ tessella chart --canvas braille --width 24 --height 5 trig.txt
|
|
944
|
+
┌────────────────────────┐
|
|
945
|
+
1 │⠉⢢⡞⠉⠉⢢ ⢀⠔⠉⠉⢳⡔⠉⠉⢦ │ sin
|
|
946
|
+
│⢠⠃⠱⡀ ⢣ ⡎ ⢠⠊⠘⡄ ⠱⡀ │ cos
|
|
947
|
+
│⠧⠤⠤⠵⡤⠤⠤⢧⠤⠤⠤⡼⠤⠤⢤⠧⠤⠤⠵⡤⠤⠤⠵⡤│
|
|
948
|
+
│ ⠱⡀ ⢣⢀⠜ ⢠⠃ ⠱⡀ ⠱│
|
|
949
|
+
-1 │ ⠘⣄⣀⡠⠻⣄⣀⡴⠃ ⠙⢄⣀⣠│
|
|
950
|
+
└────────────────────────┘
|
|
951
|
+
0 10
|
|
952
|
+
```
|
|
953
|
+
|
|
954
|
+
|
|
955
|
+
```text
|
|
956
|
+
$ tessella chart --canvas block --width 24 --height 5 trig.txt
|
|
957
|
+
┌────────────────────────┐
|
|
958
|
+
1 │▀▚▛▀▀▚ ▗▞▀▀▜▞▀▀▙ │ sin
|
|
959
|
+
│▗▘▜▖ ▚ ▛ ▗▀▝▖ ▜▖ │ cos
|
|
960
|
+
│▙▄▄█▄▄▄▙▄▄▄▟▄▄▄▙▄▄█▄▄▄█▄│
|
|
961
|
+
│ ▜▖ ▚▗▞ ▗▘ ▜▖ ▜│
|
|
962
|
+
-1 │ ▝▄▄▄▜▄▄▟▘ ▀▄▄▄│
|
|
963
|
+
└────────────────────────┘
|
|
964
|
+
0 10
|
|
965
|
+
```
|
|
966
|
+
|
|
967
|
+
<!-- tessella: allow-mixed -->
|
|
968
|
+
```text
|
|
969
|
+
$ tessella chart --canvas ascii --width 24 --height 5 trig.txt
|
|
970
|
+
┌────────────────────────┐
|
|
971
|
+
1 │"\/""\ ./""\/""\ │ sin
|
|
972
|
+
│|"-. \ / _--| \. │ cos
|
|
973
|
+
│------------------------│
|
|
974
|
+
│ -. \./ |- -. \│
|
|
975
|
+
-1 │ --_--__-" -\__│
|
|
976
|
+
└────────────────────────┘
|
|
977
|
+
0 10
|
|
978
|
+
```
|
|
979
|
+
|
|
980
|
+
A blank cell is always a space (U+0020), never the empty braille
|
|
981
|
+
pattern U+2800, which some fonts draw as dots and which is not
|
|
982
|
+
whitespace to a text tool.
|
|
983
|
+
|
|
984
|
+
## Common options
|
|
985
|
+
|
|
986
|
+
| CLI | Library | Default |
|
|
987
|
+
|---------------------|-----------------------|--------------------------------|
|
|
988
|
+
| `--width N` | `width: N` | 40 (plot area, in cells) |
|
|
989
|
+
| `--height N` | `height: N` | 15 (plot area, in cells) |
|
|
990
|
+
| `--title S` | `title: "S"` | none |
|
|
991
|
+
| `--xlabel S` | `xlabel: "S"` | none |
|
|
992
|
+
| `--ylabel S` | `ylabel: "S"` | none |
|
|
993
|
+
| `--xlim A,B` | `xlim: [a, b]` | the data's extent, rounded |
|
|
994
|
+
| `--ylim A,B` | `ylim: [a, b]` | the data's extent, rounded |
|
|
995
|
+
| `--canvas C` | `canvas: :c` | `braille` (`ascii` with ASCII) |
|
|
996
|
+
| `--xscale F` | `xscale: :f` | none |
|
|
997
|
+
| `--yscale F` | `yscale: :f` | none (plotted kinds only) |
|
|
998
|
+
| `--xdate [FMT]` | `xdate: "FMT"` | by span (plotted kinds only) |
|
|
999
|
+
| `--yerr` | `yerr: [...]` | none (line, scatter) |
|
|
1000
|
+
| `--threshold N` | `threshold: n` | none (line, scatter, stairs) |
|
|
1001
|
+
| `--above C`, `--below C` | `above:`, `below:` | red; the series' colour |
|
|
1002
|
+
| `--ascii` | `ascii: true` | off |
|
|
1003
|
+
| `--color` | `color: true` | off |
|
|
1004
|
+
| (none) | `border: :box` | by kind |
|
|
1005
|
+
|
|
1006
|
+
`--width` and `--height` size the plot area, not the whole figure:
|
|
1007
|
+
labels, frame and legend add to it. A limit of `0,0` means "from the
|
|
1008
|
+
data", as if none were given.
|
|
1009
|
+
|
|
1010
|
+
`--xscale ln|log2|log10` runs every x through the transform before
|
|
1011
|
+
limits and drawing, so the axis reads in the transformed unit (1 to
|
|
1012
|
+
1000 under `log10` reads 0 to 3, as unicode_plot's axes do).
|
|
1013
|
+
`--yscale` does the same to y, for line, scatter, stairs and density
|
|
1014
|
+
only:
|
|
1015
|
+
|
|
1016
|
+
```text
|
|
1017
|
+
$ tessella --target web chart --xscale log10 --width 30 --height 6 \
|
|
1018
|
+
--xlabel 'log10 n' growth.txt
|
|
1019
|
+
┌──────────────────────────────┐
|
|
1020
|
+
10 │ ▗▄▟│ t
|
|
1021
|
+
│ ▄▄▞▀▀▘ │
|
|
1022
|
+
│ ▗▄▄▀▀▀ │
|
|
1023
|
+
│ ▄▄▞▀▀▘ │
|
|
1024
|
+
│ ▗▄▄▄▀▀▀ │
|
|
1025
|
+
0 │▄▀▀▀▘ │
|
|
1026
|
+
└──────────────────────────────┘
|
|
1027
|
+
0 4
|
|
1028
|
+
log10 n
|
|
1029
|
+
```
|
|
1030
|
+
|
|
1031
|
+
`border:` (library only) is `:box` for a full frame, `:bar` for the
|
|
1032
|
+
corner-and-tick frame bar charts use, or `:none`.
|
|
1033
|
+
|
|
1034
|
+
### Options by kind
|
|
1035
|
+
|
|
1036
|
+
| CLI | Library | Kinds |
|
|
1037
|
+
|-----------------------------|--------------------|----------------------|
|
|
1038
|
+
| `--style post\|pre` | `style: :post` | stairs |
|
|
1039
|
+
| `--area` | `area: true` | line, stairs |
|
|
1040
|
+
| `--gradient C,C,...\|none` | `gradient: [...]` | line, stairs, with area |
|
|
1041
|
+
| `--bins N` | `bins: N` | histogram |
|
|
1042
|
+
| `--closed left\|right` | `closed: :left` | histogram |
|
|
1043
|
+
| `--scale N` | `scale: N` | stem |
|
|
1044
|
+
| `--fill G` | `fill: "G"` | bar, histogram |
|
|
1045
|
+
| `--no-eighths` | `eighths: false` | bar, histogram |
|
|
1046
|
+
| `--track G\|none` | `track: "G"`/`nil` | bar, histogram |
|
|
1047
|
+
| `--orientation O` | `orientation: :o` | all but stem |
|
|
1048
|
+
| `--blocks B` | `blocks: :b` | bar, histogram |
|
|
1049
|
+
| `--cell-width N` | `cell_width: N` | heatmap |
|
|
1050
|
+
| `--colormap C,C,...` | `colormap: [...]` | heatmap |
|
|
1051
|
+
| `--min A`, `--max B` | `min:`, `max:` | heatmap |
|
|
1052
|
+
| `--donut` | `donut: true` | pie |
|
|
1053
|
+
| `--rim cells\|smooth\|basic` | `rim: :cells` | pie |
|
|
1054
|
+
|
|
1055
|
+
The bar defaults are `fill: "█"`, `eighths: true`, `track: "·"`;
|
|
1056
|
+
under `ascii: true`, `#`, no eighths, and `.`.
|
|
1057
|
+
|
|
1058
|
+
Giving an option to a kind that does not take it is an error naming
|
|
1059
|
+
both, not something silently ignored:
|
|
1060
|
+
|
|
1061
|
+
```text
|
|
1062
|
+
$ tessella chart --kind bar --bins 3 langs.csv
|
|
1063
|
+
tessella chart: --bins is not valid with --kind bar
|
|
1064
|
+
Usage: tessella chart [options] [file]
|
|
1065
|
+
```
|
|
1066
|
+
|
|
1067
|
+
## Dates on the x axis
|
|
1068
|
+
|
|
1069
|
+
When x is a time, the axis is labelled with dates. On the command
|
|
1070
|
+
line `--xdate` reads the x column as ISO 8601: a date (`2026-11-05`),
|
|
1071
|
+
or a date and time (`2026-11-05T14:30`), with an offset (`Z`,
|
|
1072
|
+
`+01:00`) or none, which means UTC. `temps.txt` is a month of daily
|
|
1073
|
+
temperatures:
|
|
1074
|
+
|
|
1075
|
+
```text
|
|
1076
|
+
$ head -3 temps.txt
|
|
1077
|
+
date temp
|
|
1078
|
+
2026-10-01 12.0
|
|
1079
|
+
2026-10-02 13.5
|
|
1080
|
+
```
|
|
1081
|
+
|
|
1082
|
+
```text
|
|
1083
|
+
$ tessella --target web chart --xdate --width 40 --height 6 temps.txt
|
|
1084
|
+
┌────────────────────────────────────────┐
|
|
1085
|
+
20 │ ▄▄▄▄▄▄▄▖ │ temp
|
|
1086
|
+
│ ▄▄▀▀ ▝▀▚▄ ▄▞▀▀│
|
|
1087
|
+
│▀▘ ▀▜▄ ▄▛▀ │
|
|
1088
|
+
│ ▀▀▄▄▖ ▗▄▄▀▀ │
|
|
1089
|
+
│ ▀▀▀▀▀▀ │
|
|
1090
|
+
0 │ │
|
|
1091
|
+
└────────────────────────────────────────┘
|
|
1092
|
+
2026-10-01 2026-10-30
|
|
1093
|
+
```
|
|
1094
|
+
|
|
1095
|
+
The labels are in UTC, and their format follows the span: `%Y-%m-%d`
|
|
1096
|
+
for a day or more, `%m-%d %H:%M` for an hour or more, `%H:%M:%S`
|
|
1097
|
+
below. `--xdate FMT` sets it, in `strftime` form:
|
|
1098
|
+
|
|
1099
|
+
```text
|
|
1100
|
+
$ tessella --target web chart --xdate %d/%m --width 40 --height 6 temps.txt
|
|
1101
|
+
┌────────────────────────────────────────┐
|
|
1102
|
+
20 │ ▄▄▄▄▄▄▄▖ │ temp
|
|
1103
|
+
│ ▄▄▀▀ ▝▀▚▄ ▄▞▀▀│
|
|
1104
|
+
│▀▘ ▀▜▄ ▄▛▀ │
|
|
1105
|
+
│ ▀▀▄▄▖ ▗▄▄▀▀ │
|
|
1106
|
+
│ ▀▀▀▀▀▀ │
|
|
1107
|
+
0 │ │
|
|
1108
|
+
└────────────────────────────────────────┘
|
|
1109
|
+
01/10 30/10
|
|
1110
|
+
```
|
|
1111
|
+
|
|
1112
|
+
An offset is converted, so the last point here, 23:00 at `+01:00`,
|
|
1113
|
+
is 22:00 UTC:
|
|
1114
|
+
|
|
1115
|
+
```text
|
|
1116
|
+
$ printf '%s\n' 't v' '2026-11-05T14:00 1' '2026-11-05T18:30 3' \
|
|
1117
|
+
'2026-11-05T23:00+01:00 2' | \
|
|
1118
|
+
tessella --target web chart --xdate --width 30 --height 4
|
|
1119
|
+
┌──────────────────────────────┐
|
|
1120
|
+
3 │ ▄▄▀▀▀▀▀▄▄▄▖ │ v
|
|
1121
|
+
│ ▗▄▄▀▀ ▝▀▀▚▄▄▄│
|
|
1122
|
+
│ ▗▄▞▀▘ │
|
|
1123
|
+
1 │▄▄▞▀▘ │
|
|
1124
|
+
└──────────────────────────────┘
|
|
1125
|
+
11-05 14:00 11-05 22:00
|
|
1126
|
+
```
|
|
1127
|
+
|
|
1128
|
+
The axis spans the data exactly, unless `--xlim` says otherwise
|
|
1129
|
+
(given as dates too); a single date, or one date repeated, spans a
|
|
1130
|
+
day on either side. Under `--xdate` a first row holding a date and
|
|
1131
|
+
numbers is data, not a header. `--xdate` takes the word after it as
|
|
1132
|
+
a format only when it holds a `%`, so `--xdate temps.txt` reads the
|
|
1133
|
+
file. A date axis takes no `--xscale`; sideways
|
|
1134
|
+
(`--orientation horizontal`), the dates label the rows. A value that
|
|
1135
|
+
is not an ISO 8601 date is bad input, exit 1:
|
|
1136
|
+
|
|
1137
|
+
```text
|
|
1138
|
+
$ printf 'x v\n2026-13-01 1\n' | tessella chart --xdate
|
|
1139
|
+
tessella chart: row 1: x is not an ISO 8601 date: "2026-13-01"
|
|
1140
|
+
```
|
|
1141
|
+
|
|
1142
|
+
In Ruby the x values are `Time`s (or `Date`s, taken as midnight UTC,
|
|
1143
|
+
or `DateTime`s), and `xdate: "FMT"` sets the format:
|
|
1144
|
+
|
|
1145
|
+
```ruby
|
|
1146
|
+
Tessella.line(times, temps, xdate: "%b %d")
|
|
1147
|
+
```
|
|
1148
|
+
|
|
1149
|
+
## Error bars
|
|
1150
|
+
|
|
1151
|
+
`--yerr` (line and scatter) reads a third column as each point's
|
|
1152
|
+
error, and draws a bar from y − e to y + e along the value axis, after
|
|
1153
|
+
the line or the points. The axis limits take the bars in. `dose.txt`
|
|
1154
|
+
holds a measured effect and its error per dose:
|
|
1155
|
+
|
|
1156
|
+
```text
|
|
1157
|
+
$ cat dose.txt
|
|
1158
|
+
dose effect err
|
|
1159
|
+
1 2.1 0.4
|
|
1160
|
+
2 3.0 0.5
|
|
1161
|
+
3 4.6 0.3
|
|
1162
|
+
4 5.2 0.8
|
|
1163
|
+
5 6.9 0.6
|
|
1164
|
+
6 7.4 1.0
|
|
1165
|
+
```
|
|
1166
|
+
|
|
1167
|
+
```text
|
|
1168
|
+
$ tessella --target web chart --yerr --width 30 --height 8 dose.txt
|
|
1169
|
+
┌──────────────────────────────┐
|
|
1170
|
+
9 │ ▗│ effect
|
|
1171
|
+
│ ▖▗▄▄▄▟│
|
|
1172
|
+
│ ▄▄▀▛▘ ▐│
|
|
1173
|
+
│ ▗▄▙▞▀ │
|
|
1174
|
+
│ ▄▄▛▀▀▀▘ ▌ │
|
|
1175
|
+
│ ▄▄▀▀ │
|
|
1176
|
+
│▄▄▄▀▀▀▌ │
|
|
1177
|
+
1 │▘ │
|
|
1178
|
+
└──────────────────────────────┘
|
|
1179
|
+
1 6
|
|
1180
|
+
```
|
|
1181
|
+
|
|
1182
|
+
```text
|
|
1183
|
+
$ tessella chart --kind scatter --yerr --ascii --width 30 --height 8 dose.txt
|
|
1184
|
+
+------------------------------+
|
|
1185
|
+
9 | || effect
|
|
1186
|
+
| . ||
|
|
1187
|
+
| | ||
|
|
1188
|
+
| | |
|
|
1189
|
+
| | | |
|
|
1190
|
+
| | |
|
|
1191
|
+
|| | |
|
|
1192
|
+
1 |` |
|
|
1193
|
+
+------------------------------+
|
|
1194
|
+
1 6
|
|
1195
|
+
```
|
|
1196
|
+
|
|
1197
|
+
Sideways (`--orientation horizontal`) the bars run across. Errors are
|
|
1198
|
+
in data units, and go through `--yscale` with y. `--yerr` needs
|
|
1199
|
+
exactly three columns, x, y and the error:
|
|
1200
|
+
|
|
1201
|
+
```text
|
|
1202
|
+
$ printf 'x y e f\n1 2 1 1\n' | tessella chart --yerr
|
|
1203
|
+
tessella chart: --yerr reads x, y and the error: 4 columns
|
|
1204
|
+
```
|
|
1205
|
+
|
|
1206
|
+
In Ruby, `yerr:` on `Tessella.line`, `Tessella.scatter` and `add`
|
|
1207
|
+
takes one error a point, or `[lows, highs]` for bars that are not
|
|
1208
|
+
symmetric. An error list of the wrong length, or a negative error, is
|
|
1209
|
+
refused. With `mark:`, the point stays visible at the middle of its
|
|
1210
|
+
bar:
|
|
1211
|
+
|
|
1212
|
+
```ruby
|
|
1213
|
+
Tessella.scatter([1, 2, 3], [2, 3, 5], yerr: [[0.5, 0.2, 1], [1, 0.4, 0.5]],
|
|
1214
|
+
mark: "●", width: 20, height: 6)
|
|
1215
|
+
```
|
|
1216
|
+
|
|
1217
|
+
## Thresholds
|
|
1218
|
+
|
|
1219
|
+
`--threshold N` (line, scatter, stairs) draws a dashed rule at N
|
|
1220
|
+
across the plot, readable without colour, and the value axis takes N
|
|
1221
|
+
in. Under `--color` the cells beyond it take `--above C` (red by
|
|
1222
|
+
default) and the rest `--below C` (the series' own colour unless
|
|
1223
|
+
given), each in any [colour form](#colour). Sideways the rule runs
|
|
1224
|
+
down the plot.
|
|
1225
|
+
|
|
1226
|
+
```text
|
|
1227
|
+
$ tessella --target web chart --threshold 70 --width 30 --height 6 cpu.txt
|
|
1228
|
+
┌──────────────────────────────┐
|
|
1229
|
+
90 │ ▞▀▀▀▄ ▞▀▀▀▄ │
|
|
1230
|
+
│▖▖▞▖▖▖▖▖▙▖▖▖▖▖▖▖▖▖▖▖▄▛▖▖▖▖▖▙▖▄│
|
|
1231
|
+
│▗▀ ▚ ▟▘ ▚ │
|
|
1232
|
+
│▝ ▝▙ ▗▘ ▝▙│
|
|
1233
|
+
│ ▚▖ ▗▘ ▝│
|
|
1234
|
+
10 │ ▝▄▄▄▞▘ │
|
|
1235
|
+
└──────────────────────────────┘
|
|
1236
|
+
0 60
|
|
1237
|
+
```
|
|
1238
|
+
|
|
1239
|
+
On the braille canvas the rule is the row of single dots, `⠄`, at 70.
|
|
1240
|
+
In Ruby: `threshold: 70, above: :red, below: :green`.
|
|
1241
|
+
|
|
1242
|
+
## Several series, and marks
|
|
1243
|
+
|
|
1244
|
+
From the library, `chart.add` adds a series to a line, scatter,
|
|
1245
|
+
stairs or density chart. `mark:` draws a series as one glyph in the
|
|
1246
|
+
cell of each point, over whatever the cell holds, instead of the
|
|
1247
|
+
kind's own line or dots; the legend shows the glyph before the name.
|
|
1248
|
+
That is how measured points sit on a fitted curve:
|
|
1249
|
+
|
|
1250
|
+
```ruby
|
|
1251
|
+
# frozen_string_literal: true
|
|
1252
|
+
|
|
1253
|
+
# examples/calibration.rb: measured points marked on a fitted line.
|
|
1254
|
+
require "tessella"
|
|
1255
|
+
|
|
1256
|
+
xs = (0..20).map { it * 0.5 }
|
|
1257
|
+
fit = Tessella.line(xs, xs.map { (0.5 * it) + 1 },
|
|
1258
|
+
name: "fit", width: 30, height: 6, title: "calibration",
|
|
1259
|
+
canvas: :block)
|
|
1260
|
+
fit.add([1, 3, 4.5, 7, 9], [1.4, 2.7, 3.0, 4.9, 5.4],
|
|
1261
|
+
name: "measured", mark: "●")
|
|
1262
|
+
puts fit
|
|
1263
|
+
```
|
|
1264
|
+
|
|
1265
|
+
```text
|
|
1266
|
+
$ ruby calibration.rb
|
|
1267
|
+
calibration
|
|
1268
|
+
┌──────────────────────────────┐
|
|
1269
|
+
6 │ ▗▄●▀▀│ fit
|
|
1270
|
+
│ ▗●▟▀▀▘ │ ● measured
|
|
1271
|
+
│ ▄▄▄▀▀▘ │
|
|
1272
|
+
│ ●▗▄▞●▀▘ │
|
|
1273
|
+
│ ▗▄▄▀▀▘ │
|
|
1274
|
+
1 │▄▄▄●▀▘ │
|
|
1275
|
+
└──────────────────────────────┘
|
|
1276
|
+
0 10
|
|
1277
|
+
```
|
|
1278
|
+
|
|
1279
|
+
A mark is one character, and ASCII under `ascii: true`. Bar,
|
|
1280
|
+
histogram, box and stem take no mark.
|
|
1281
|
+
|
|
1282
|
+
## Colour
|
|
1283
|
+
|
|
1284
|
+
Colour is off by default, because a chart's first home is a document,
|
|
1285
|
+
where an escape code is garbage. `--color` (`color: true`) colours the
|
|
1286
|
+
plotted cells with ANSI escapes, one colour per series from the cycle
|
|
1287
|
+
red, green, yellow, blue, magenta, cyan, white; `add(..., color:
|
|
1288
|
+
:blue)` picks one. The frame, labels and legend stay plain. Where two
|
|
1289
|
+
series cross in a cell, the last one drawn colours it.
|
|
1290
|
+
|
|
1291
|
+
A colour, in `add(..., color:)` as in a gradient, is one of three
|
|
1292
|
+
forms: a name (`:red`, `:green`, `:yellow`, `:blue`, `:magenta`,
|
|
1293
|
+
`:cyan`, `:white`), a 256-colour index (`0..255`, `208` is orange),
|
|
1294
|
+
or a truecolor `"#rrggbb"`. On the command line, `--gradient` takes
|
|
1295
|
+
the same three forms, comma-separated: `--gradient
|
|
1296
|
+
'#2e7d32,#f9a825,#c62828'`. A filled area's colours are covered in
|
|
1297
|
+
[Filled areas](#filled-areas).
|
|
1298
|
+
|
|
1299
|
+
## ASCII
|
|
1300
|
+
|
|
1301
|
+
`--ascii` (`ascii: true`) makes the whole chart ASCII from the first
|
|
1302
|
+
byte (`--no-ascii` asks for Unicode, which matters only under the
|
|
1303
|
+
[cjk target](targets.md#cjk), where ASCII is the default): the frame is `+ - |`, the canvas is the ASCII one, bars are `#`
|
|
1304
|
+
on a `.` track. No part draws Unicode and lets a later pass rewrite
|
|
1305
|
+
it, so the output is safe in a man page, an RFC-style text or a
|
|
1306
|
+
source file kept to ASCII. A non-ASCII title, label, bar or series
|
|
1307
|
+
name is refused, not drawn: on the command line, a non-ASCII data
|
|
1308
|
+
row is bad input (exit 1) and a non-ASCII `--title`, `--xlabel` or
|
|
1309
|
+
`--ylabel` a usage error (exit 2).
|
|
1310
|
+
|
|
1311
|
+
```text
|
|
1312
|
+
$ tessella chart --kind histogram --width 30 --bins 8 --ascii normal.txt
|
|
1313
|
+
+ +
|
|
1314
|
+
[-3.0, -2.0) |###....................... 8
|
|
1315
|
+
[-2.0, -1.0) |##########................ 28
|
|
1316
|
+
[-1.0, 0.0) |########################## 72
|
|
1317
|
+
[ 0.0, 1.0) |######################.... 61
|
|
1318
|
+
[ 1.0, 2.0) |##########................ 28
|
|
1319
|
+
[ 2.0, 3.0) |#......................... 3
|
|
1320
|
+
+ +
|
|
1321
|
+
Frequency
|
|
1322
|
+
```
|
|
1323
|
+
|
|
1324
|
+
## What a chart refuses
|
|
1325
|
+
|
|
1326
|
+
A chart checks its input before drawing, and refuses it naming what
|
|
1327
|
+
is wrong. Two kinds of refusal:
|
|
1328
|
+
|
|
1329
|
+
- **A bad call** raises `ArgumentError`, exit 2 on the command line:
|
|
1330
|
+
an unknown option, kind, canvas, xscale, stairs style or closed
|
|
1331
|
+
side; a width or height that is not a positive Integer; x and y of
|
|
1332
|
+
different lengths; a stem scale that is not positive.
|
|
1333
|
+
- **A value it cannot draw** raises `Tessella::ValueError` (an
|
|
1334
|
+
`ArgumentError` too), exit 1: a value that is not a finite number
|
|
1335
|
+
(`nil`, a String, NaN, ±Infinity, or a number past Float's range),
|
|
1336
|
+
an x of 0 or less under a log `xscale`, a negative pie slice, a
|
|
1337
|
+
candle whose low and high do not hold its open and close, an empty
|
|
1338
|
+
sample.
|
|
1339
|
+
|
|
1340
|
+
```text
|
|
1341
|
+
$ printf '1\n1e400\n' | tessella chart
|
|
1342
|
+
tessella chart: y must be a finite number: Infinity
|
|
1343
|
+
```
|
|
1344
|
+
|
|
1345
|
+
A row that cannot be read is bad input too, exit 1, naming the row
|
|
1346
|
+
and the field, and so is invalid UTF-8, in every command:
|
|
1347
|
+
|
|
1348
|
+
```text
|
|
1349
|
+
$ printf '1\nx\n' | tessella chart
|
|
1350
|
+
tessella chart: row 2: y is not a number: "x"
|
|
1351
|
+
```
|
|
1352
|
+
|
|
1353
|
+
Every row of a bar chart must have as many columns as the first:
|
|
1354
|
+
|
|
1355
|
+
```text
|
|
1356
|
+
$ printf 'a,1,2\nb,3\n' | tessella chart --kind bar
|
|
1357
|
+
tessella chart: row 2 has 2 columns, row 1 has 3
|
|
1358
|
+
```
|
|
1359
|
+
|
|
1360
|
+
## How tessella differs from unicode_plot
|
|
1361
|
+
|
|
1362
|
+
tessella's chart kinds and canvases come from
|
|
1363
|
+
[unicode_plot](https://github.com/red-data-tools/unicode_plot), which
|
|
1364
|
+
the test suite uses as an oracle; with unicode_plot's own bar
|
|
1365
|
+
settings (`fill: "■"`, `"▇"` for histograms, `eighths: false`, `track:
|
|
1366
|
+
nil`) the output is identical. The departures — sizes below 5 on the
|
|
1367
|
+
density canvas, wide histogram bins, `10` not `10.0` on an axis,
|
|
1368
|
+
exact stem leaves, very large constant data, negative bars, CJK
|
|
1369
|
+
labels — are listed with their reasons in
|
|
1370
|
+
[DESIGN.md](../DESIGN.md#why-it-is-shaped-so).
|