simple-ascii-chart v4.0.6
Simple ascii chart
Simple ASCII Chart is a TypeScript package that allows you to create ASCII charts in your terminal. It operates on two-dimensional input data, supports multiple series, custom colors, and formatters to make your data visualization clear and customizable.
With colored multiline:
With colored area:
With axis:
Usage
Package can be imported via yarn (or npm):
yarn add simple-ascii-chart
And used like:
import plot from 'simple-ascii-chart';
const graph = plot(input, settings);
Playground
Alternatively, you can create a graph interactively in the playground.
API Endpoint
You can also use the API endpoint to generate charts by sending a POST request with your input data:
curl -d input='[[1,2],[2,3],[3,4]]' -G https://simple-ascii-chart.vercel.app/api
or as a URL parameter:
https://simple-ascii-chart.vercel.app/api?input=[[1,2],[2,3],[3,4]]&settings={%22width%22:50}
How to use it
When dependency is imported to project:
import plot from 'simple-ascii-chart';
console.log(
plot(
[
[1, 1],
[2, 4],
[3, 4],
[4, 2],
[5, -1],
[6, 3],
[7, -1],
[8, 9],
],
{ title: 'Important data', width: 20, height: 8 },
),
);
And π, chart appears in your terminal:
Important data
β²
9β€ ββ
β β
β β
4β€ ββββββ β
3β€ β β βββ β
2β€ β ββββ β β β
1β€βββ β β β β
-1β€ ββββ ββββ
ββ¬βββ¬ββ¬βββ¬βββ¬βββ¬ββ¬βββ¬βΆ
1 2 3 4 5 6 7 8
Input
Input has to be a two dimensional array or array of arrays for series:
Point = [x: number, y: number];
SingleLine = Point[];
MultiLine = SingleLine[];
Input = SingleLine | MultiLine;
Therefore input for a single series is:
const input = [
[1, 1],
[2, 4],
[3, 40],
];
Or for multi-series:
const input = [
[
[0, 18],
[1, 1],
[2, 3],
],
[
[4, 1],
[5, 0],
[6, 1],
],
];
Settings
Plot can be adjusted with a second parameter settings
.
color
Changes graph color. Possible values are:
color?:
| 'ansiRed'
| 'ansiGreen'
| 'ansiBlack'
| 'ansiYellow'
| 'ansiBlue'
| 'ansiMagenta'
| 'ansiCyan'
| 'ansiWhite'
Can be used to distinguish series like:
color: ['ansiGreen', 'ansiRed'];
width
Changes default width of the graph, can be used to scale up/down values:
width?: number
height
Changes default height of the graph, can be used to scale up/down values:
height?: number
axisCenter
Changes center of the axis, by default it's placed in the bottom-left:
axisCenter?: [x:number, y:number]
formatter
Transforms axis label:
formatter?: Formatter
Where
type FormatterHelpers = {
axis: 'x' | 'y';
xRange: number[];
yRange: number[];
};
type Formatter = (number: number, helpers: FormatterHelpers) => number | string;
Default formatter is:
defaultFormatter: Formatter = (value, { xRange, yRange }) => {
// Cut off small values
if (Math.abs(xRange[0]) < 1000 || Math.abs(yRange[0]) < 1000) {
return Number(value.toFixed(3));
}
// Adds XYZk to cut off large values
if (Math.abs(value) > 1000) return `${value / 1000}k`;
return value;
};
lineFormatter
Transforms line, allows to format graph style. Callback takes arguments:
LineFormatterArgs = {
x: number;
y: number;
plotX: number;
plotY: number;
input: SingleLine;
index: number;
};
plotX
and plotY
is coordinate of a point scaled to the plot. Callback has to return:
CustomSymbol = { x: number; y: number; symbol: string };
where x
and y
is also plot coordinate, symbol
is char to be displayed. If an array is returned, more points can be placed on the graph.
lineFormatter?: (args: LineFormatterArgs) => CustomSymbol | CustomSymbol[];
Check examples section for real world usage.
title
Adds title above the graph:
title?: string;
xLabel
Adds label to the x axis:
xLabe
l?: string;
yLabel
Adds label to the y axis:
yLabel?: string;
thresholds
Adds thresholds to plot:
thresholds?: {
x?: number;
y?: number;
color?: Color;
}[];
fillArea
Some graphs look better presented as a area, not lines. In order to use area chart, pass fillArea prop:
fillArea?: boolean;
hideXAxis
Hide X axis:
hideXAxis? boolean;
hideYAxis
Hide Y axis:
hideYAxis? boolean;
symbols
Overrides default symbols. Three independent sections are: empty
- background, axis
- symbols used to draw axis, chart
- symbols used to draw graph.
symbols: {
background: ' ',
border: undefined,
empty: ' ',
axis: {
n: 'β²',
ns: 'β',
y: 'β€',
nse: 'β',
x: 'β¬',
we: 'β',
e: 'βΆ',
},
chart: {
we: 'β',
wns: 'β',
ns: 'β',
nse: 'β',
wsn: 'β',
sne: 'β',
area: 'β'
}
Summary
Settings = {
color?: Color | Color[];
width?: number;
height?: number;
axisCenter?: [number, number];
formatter?: (number:number) => number;
lineFormatter?: (args: LineFormatterArgs) => CustomSymbol | CustomSymbol[];
hideXAxis?: boolean;
legend?: { position?: 'left' | 'right' | 'top' | 'bottom'; series: string | string[] };
title?: string;
xLabel?: string;
yLabel?: string;
fillArea?: boolean;
hideYAxis?: boolean;
thresholds?: {
x?: number;
y?: number;
color?: Color;
}[];
symbols?: {
background?: ' ',
border?: undefined,
empty?: ' ',
axis?: {
n: 'β²',
ns: 'β',
y: 'β€',
nse: 'β',
x: 'β¬',
we: 'β',
e: 'βΆ',
},
chart?: {
we: 'β',
wns: 'β',
ns: 'β',
nse: 'β',
wsn: 'β',
sne: 'β',
area: 'β',
}
}
};
Examples
Simple plot
Input:
plot(
[
[1, 1],
[2, 4],
[3, 4],
[4, 2],
[5, -1],
],
{ width: 9, height: 6 },
);
Output:
β²
4β€ βββββ
β β β
2β€ β βββ
1β€ββ β
β β
-1β€ ββ
ββ¬ββ¬ββ¬ββ¬ββ¬βΆ
1 2 3 4 5
Plot with title and defined size
Input:
plot(
[
[1, 1],
[2, 4],
[3, 4],
[4, 2],
[5, -1],
[6, 3],
[7, -1],
[8, 9],
],
{ title: 'Important data', width: 20, height: 8 },
);
Output:
Important data
β²
9β€ ββ
β β
β β
4β€ ββββββ β
3β€ β β βββ β
2β€ β ββββ β β β
1β€βββ β β β β
-1β€ ββββ ββββ
ββ¬βββ¬ββ¬βββ¬βββ¬βββ¬ββ¬βββ¬βΆ
1 2 3 4 5 6 7 8
Plot with axis labels
Input:
plot(
[
[1, 1],
[2, 4],
[3, 4],
[4, 2],
[5, -1],
[6, 3],
[7, -1],
[8, 9],
],
{ xLabel: 'x', yLabel: 'y', width: 20, height: 8 },
);
Output:
β²
9β€ ββ
β β
β β
4β€ ββββββ β
3β€ β β βββ β
y 2β€ β ββββ β β β
1β€βββ β β β β
-1β€ ββββ ββββ
ββ¬βββ¬ββ¬βββ¬βββ¬βββ¬ββ¬βββ¬βΆ
1 2 3 4 5 6 7 8
x
Plot with colors
Input:
plot(
[
[
[1, 1],
[2, 2],
[3, 4],
[4, 6],
],
[
[5, 4],
[6, 1],
[7, 2],
[8, 3],
],
],
{
width: 20,
fillArea: true,
color: ['ansiGreen', 'ansiBlue'],
legend: { position: 'bottom', series: ['first', 'second'] },
},
);
Output:
β²
6β€ ββ
β ββ
4β€ βββββ βββ
3β€ βββββ βββ ββ
2β€ βββββββ βββ βββββ
1β€βββββββββ βββββββββ
ββ¬βββ¬ββ¬βββ¬βββ¬βββ¬ββ¬βββ¬βΆ
1 2 3 4 5 6 7 8
β first
β second
Plot with borders
Input:
plot(
[
[1, 1],
[2, 4],
[3, 4],
[4, 2],
[5, -1],
[6, 3],
[7, -1],
[8, 9],
],
{ symbols: { border: 'β' }, xLabel: 'x', yLabel: 'y', width: 20, height: 8 },
);
Output:
βββββββββββββββββββββββββββ
β β² β
β 9β€ ββ β
β β β β
β β β β
β 4β€ ββββββ β β
β 3β€ β β βββ β β
βy 2β€ β ββββ β β β β
β 1β€βββ β β β β β
β -1β€ ββββ ββββ β
β ββ¬βββ¬ββ¬βββ¬βββ¬βββ¬ββ¬βββ¬βΆβ
β 1 2 3 4 5 6 7 8 β
β x β
βββββββββββββββββββββββββββ
Plot with filled area
Input:
plot(
[
[
[1, 1],
[2, 2],
[3, 4],
[4, 6],
],
[
[1, 4],
[2, 1],
[3, 2],
[4, 3],
],
],
{
fillArea: true,
color: ['ansiGreen', 'ansiBlue'],
},
);
Output:
β²
6β€ ββ
β ββ
4β€ββββ
3β€ββββ
2β€ββββ
1β€ββββ
ββ¬β¬β¬β¬βΆ
1234
Scaled up plot
Input:
plot(
[
[1, 1],
[2, 4],
[3, 40],
[4, 2],
[5, -1],
[6, 3],
[7, -1],
[8, -1],
[9, 9],
[10, 9],
],
{ width: 40, height: 10 },
);
Output:
β²
40β€ βββββ
β β β
β β β
β β β
β β β
β β β
β β β
9β€ β β ββββββ
3β€ ββββββ βββββ βββββ β
-1β€ββββ ββββββ ββββββββββ
ββ¬ββββ¬βββββ¬ββββ¬ββββ¬βββββ¬ββββ¬ββββ¬βββββ¬ββββ¬βΆ
1 2 3 4 5 6 7 8 9 10
Add thresholds
Input:
plot(
[
[1, 1],
[2, 4],
[3, 4],
[4, 2],
[5, -1],
[6, 3],
[7, -1],
[8, 9],
],
{
width: 40,
thresholds: [
{
y: 5,
x: 5,
},
{
x: 2,
},
],
},
);
Output:
β² β β
9β€ β β ββ
β β β β
β β β β
ββββββββββββββββββββββββββββββββββββββββββ
β β β β
4β€ ββββββββββββ β β
3β€ β β β ββββββ β
2β€ β ββββββ β β β
1β€ββββββ β β β β
β β β β β β
-1β€ β βββββββ βββββββ
ββ¬ββββββ¬βββββ¬ββββββ¬βββββ¬ββββββ¬βββββ¬ββββββ¬βΆ
1 2 3 4 5 6 7 8
Multi-series plot
Input:
plot(
[
[
[0, 18],
[1, 1],
[2, 3],
[3, 11],
[4, 5],
[5, 16],
[6, 17],
[7, 14],
[8, 7],
[9, 4],
],
[
[0, 0],
[1, 1],
[2, 1],
[3, 1],
[4, 1],
[5, 0],
[6, 1],
[7, 0],
[8, 1],
[9, 0],
],
],
{ width: 40, height: 10, color: ['ansiBlue', 'ansiGreen'] },
);
Output:
β²
17β€βββββ ββββββ
16β€ β βββββββ β
14β€ β β βββββββ
11β€ β βββββββ β β
β β β β β β
7β€ β β β β ββββββ
5β€ β β ββββββ β
4β€ β ββββββ ββ
1β€ βββββββββββββββββββββββ ββββββ ββββββ
0β€βββββ βββββββ βββββββ ββ
ββ¬βββββ¬ββββββ¬βββββ¬ββββββ¬βββββ¬ββββββ¬βββββ¬ββββββ¬βββββ¬βΆ
0 1 2 3 4 5 6 7 8 9
Plot with formatting applied
Input:
plot(
[
[
[0, -10],
[1, 0.001],
[2, 10],
[3, 200],
[4, 10000],
[5, 2000000],
[6, 50000000],
],
],
{
width: 30,
height: 20,
formatter: (n: number, { axis }: FormatterHelpers) => {
const labels = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
if (axis === 'y') return n;
return labels[n] || 'X';
},
},
);
Output:
β²
50000000β€ ββ
β β
β β
β β
β β
β β
β β
β β
β β
β β
β β
β β
β β
β β
β β
β β
β β
β β
2000000β€ ββββββ
-10β€ββββββββββββββββββββββββ
ββ¬βββββ¬βββββ¬βββββ¬ββββ¬βββββ¬βββββ¬βΆ
A B C D E F G
Plot with axis center
Input:
plot(
[
[
[-8, -8],
[-4, -4],
[-3, -3],
[-2, -2],
[-1, -1],
[0, 0],
[2, 2],
[3, 3],
[4, 4],
[8, 8],
],
],
{ width: 60, height: 20, axisCenter: [0, 0] },
);
Output:
β²
8β€ ββ
β β
β β
β β
β β
4β€ ββββββββββββββββ
3β€ ββββ
2β€ βββββ
β β
β¬βββββββββββββββ¬βββ¬ββββ¬ββββ¬βββ0βββββββββββ¬βββ¬βββββββββββββββ¬ββΆ
-8 -4 -3 -2 -1 0β 2 3 4 8
βββ-1β€
βββββ -2β€
βββββ -3β€
ββββ -4β€
β β
β β
β β
β β
βββββββββββββββ -8β€
β
Plot with custom symbols
Input:
plot(
[
[1, 2],
[2, 0],
[3, 5],
[4, 2],
[5, -2],
[6, 3],
],
{
symbols: {
empty: 'x',
empty: '-',
axis: {
n: 'A',
ns: 'i',
y: 't',
nse: 'o',
x: 'j',
we: 'm',
e: 'B',
},
chart: {
we: '1',
wns: '2',
ns: '3',
nse: '4',
wsn: '5',
sne: '6',
},
},
width: 40,
height: 10,
},
);
Output:
xxA-----------------------------------------
x5t---------------61111112------------------
xxi---------------3------3------------------
xxi---------------3------3------------------
x3t---------------3------3---------------61-
x2t11111112-------3------411111112-------3--
xxi-------3-------3--------------3-------3--
x0t-------411111115--------------3-------3--
xxi------------------------------3-------3--
xxi------------------------------3-------3--
-2t------------------------------411111115--
xxojmmmmmmmjmmmmmmmjmmmmmmjmmmmmmmjmmmmmmmjB
xxx1xxxxxxx2xxxxxxx3xxxxxx4xxxxxxx5xxxxxxx6x
Plot without axis
Input:
plot(
[
[-5, 2],
[2, -3],
[13, 0.1],
[4, 2],
[5, -2],
[6, 12],
],
{
width: 40,
height: 10,
hideYAxis: true,
hideXAxis: true,
},
);
Output:
ββββββββββββββββ
β β
β β
β β
β β
β β
βββββββββββββββ βββ β β
β β β β ββ
β β βββ
ββββββ
Plot with with large numbers
Input:
plot(
[
[-9000, 2000],
[-8000, -3000],
[-2000, -2000],
[2000, 2000],
[3000, 1500],
[4000, 5000],
[10000, 1400],
[11000, 20000],
[12000, 30000],
],
{
width: 60,
height: 20,
},
);
Output:
β²
30kβ€ ββ
β β
β β
β β
β β
β β
20kβ€ ββββ
β β
β β
β β
β β
β β
β β
β β
5kβ€ βββββββββββββββββ β
β β β β
1.4kβ€βββ βββββββ ββββ
β β β
-2kβ€ β ββββββββββββ
-3kβ€ ββββββββββββββββββ
ββ¬βββ¬βββββββββββββββββ¬βββββββββββ¬βββ¬βββ¬ββββββββββββββββ¬βββ¬βββ¬βΆ
-8k 2k 4k 11k
-9k -2k 3k 10k 12k
Plot with custom line format
Input:
plot(
[
[1, 0],
[2, 20],
[3, 29],
[4, 10],
[5, 3],
[6, 40],
[7, 0],
[8, 20],
],
{
height: 10,
width: 30,
lineFormatter: ({ y, plotX, plotY, input, index }) => {
const output = [{ x: plotX, y: plotY, symbol: 'β' }];
if (input[index - 1]?.[1] < y) {
return [...output, { x: plotX, y: plotY - 1, symbol: 'β²' }];
}
return [...output, { x: plotX, y: plotY + 1, symbol: 'βΌ' }];
},
},
);
Output:
β² β²
40β€ β
β β²
29β€ β
β β² β²
20β€ β β
β
β
10β€ β
3β€ βΌ β
0β€β βΌ β
ββ¬ββββ¬ββββ¬ββββ¬βββββ¬ββββ¬ββββ¬ββββ¬βΆ
1 2 3 4 5 6 7 8
8 months ago
11 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago