text-graph.js
is a compact and easy-to-use JavaScript/TypeScript library. It lets you create charts in the terminal and browser console. You can make line charts and build a dashboard with multiple charts, all without any extarnal dependencies. It has features for different axis and data scaling methods. Plus, it supports adding colors to your charts.
- Create line charts
- Drawing multiple series on one plot
- Creating dashboards with multiple charts
- Colors for chart elements
- Built-in axis scale functions (i.e. log)
- Built-in different data overflow handling functions (i.e. linear scale, clapm, etc)
- Built-in different data compression functions (i.e. mean, max, etc)
npm install text-graph.js
# clone repo
git clone https://github.com/DrA1ex/text-graph.js.git
cd ./text-graph.js
# install dependencies
npm install
# Run example
npx tsx ./examples/dashboard.ts
// Importing the Plot class
import {Plot} from 'text-graph.js';
// Creating a new instance of the Plot class with a width of 80 characters and height of 20 characters
const plot = new Plot(80, 20);
// Adding a new series to the plot and storing its ID
const id = plot.addSeries();
// Defining a function that takes a number "x" as input and calculates a mathematical expression
const fn = (x) => Math.pow(Math.sin(x), 3) + Math.pow(Math.cos(x), 3) - 1.5 * Math.sin(x) * Math.cos(x);
// Iterating over a range of values from -2 to just below 2, incrementing by 0.05 at each step
for (let x = -2; x < 2; x += 0.05) {
// Adding an entry to the series with the given ID, calculated using the function "fn"
plot.addSeriesEntry(id, fn(x));
}
// Printing the chart output to the console
console.log(plot.paint());
Source code: link
To use text-graph.js
, follow these steps:
- Import the necessary classes and enums:
import {
Plot, LabelPositionFlags, PlotAxisScale, PlotSeriesAggregationFn, PlotSeriesOverflow, Color, BackgroundColor
} from 'text-graph.js';
- Define the plot options:
const plotOptions = {
showAxis: true,
title: 'Chart Title',
horizontalBoundary: 1,
verticalBoundary: 2,
titlePosition: LabelPositionFlags.top,
titleForeground: Color.blue,
titleBackground: BackgroundColor.black,
axisLabelsFraction: 4,
axisScale: PlotAxisScale.linear,
aggregation: PlotSeriesAggregationFn.mean,
zoom: false,
}
- Create a plot instance:
const width = 60;
const height = 20;
const plot = new Plot(width, height, plotOptions);
- Define the series configurations:
const plotSeriesConfig1 = {
color: Color.cyan,
overflow: PlotSeriesOverflow.logScale
};
const plotSeriesConfig2 = {
color: Color.magenta,
overflow: PlotSeriesOverflow.clamp
};
- Add plot series to the plot:
const seriesId1 = plot.addSeries(plotSeriesConfig1);
const seriesId2 = plot.addSeries(plotSeriesConfig2);
- Option 1: Iterate over your data and update the plot:
const data1 = [1, 2, 3];
for (const value of data1) {
plot.addSeriesEntry(seriesId1, value);
}
const data2 = [0, -1, -2];
for (const value of data2) {
plot.addSeriesEntry(seriesId2, value);
}
- Option 2: Populate all data to the plot:
plot.addSeriesRange(seriesId1, [1, 2, 3]);
plot.addSeriesRange(seriesId2, [0, -1, -2]);
- Display the plot:
const chartData = plot.paint();
console.log(chartData);
![](https://private-user-images.githubusercontent.com/1194059/260085640-a68f5175-34db-4462-8de2-649b60dd375b.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkxMDE5NDIsIm5iZiI6MTczOTEwMTY0MiwicGF0aCI6Ii8xMTk0MDU5LzI2MDA4NTY0MC1hNjhmNTE3NS0zNGRiLTQ0NjItOGRlMi02NDliNjBkZDM3NWIucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwOSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDlUMTE0NzIyWiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NDNhNjNmZDQ5YjE0ZmZhYWNiMzkwNGQ2OTk2ZWQyYjA0NTc0NjQ3OWJhNzUzN2M0MTlhMGI1ZDE0NGU5ZjlhOSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.kZMy6BAlVIga6DdLhmnUA3mko3jsZz57okDzLmU58lw)
Source code: link
![](https://private-user-images.githubusercontent.com/1194059/260085110-725b01bb-2bdb-47b8-b8e2-2728059000b1.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkxMDE5NDIsIm5iZiI6MTczOTEwMTY0MiwicGF0aCI6Ii8xMTk0MDU5LzI2MDA4NTExMC03MjViMDFiYi0yYmRiLTQ3YjgtYjhlMi0yNzI4MDU5MDAwYjEucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwOSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDlUMTE0NzIyWiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NTMxNDk4N2U0NTMzYjE0NmNlNzgwMzk5MDhmYjY3MWUzMmVkYzg2YmZhMDA3NjE3YjgyMjNiN2Q4MjgzYzA2YyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.UrE6k_H4924QJpkeOFyUo8b67jW7YeaNIc1a5Ze_TBg)
Source code: link
![](https://private-user-images.githubusercontent.com/1194059/260084589-483a9035-9ab2-4439-88eb-0a44171b0ebe.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkxMDE5NDIsIm5iZiI6MTczOTEwMTY0MiwicGF0aCI6Ii8xMTk0MDU5LzI2MDA4NDU4OS00ODNhOTAzNS05YWIyLTQ0MzktODhlYi0wYTQ0MTcxYjBlYmUucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwOSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDlUMTE0NzIyWiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MTlkNGVhOTA2NGJmYmY0MThjMzAxZWEzNTdmYjk0MzgxYmEyZjMzMmQ0ZWE5MGFlNDNiNDA3ZmQxZDA4NGZlMiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.bC60f8sFhy7KtkTuEK84U35LaQZFOjNYhA3rRWfIfmk)
Source code: link
![](https://private-user-images.githubusercontent.com/1194059/260213220-5b5da127-4a32-4f88-9759-1bb796dda928.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkxMDE5NDIsIm5iZiI6MTczOTEwMTY0MiwicGF0aCI6Ii8xMTk0MDU5LzI2MDIxMzIyMC01YjVkYTEyNy00YTMyLTRmODgtOTc1OS0xYmI3OTZkZGE5MjgucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwOSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDlUMTE0NzIyWiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9N2ZkM2E3MzAxOWJiY2NlYzQ0ZDdhNjQ3ZDRlZDJiOGE0OGU5ZjdhMWQwY2QyN2Y2NmU1ZTFiYzdhNzcwNmZhNSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.QOnxfEQZ2c4Yd1dAvSH-wXI57WJEy44lWe7eEL3SJz4)
Project: link
const data = new Array(200);
for (let i = 0; i < data.length; i++) {
data[i] = Math.sin(0.3 * i) * Math.cos(0.6 * i) - Math.sin(i * Math.PI / 50) * Math.abs(i - 100) / 30
}
console.log(Plot.plot(data));
![](https://private-user-images.githubusercontent.com/1194059/260106393-96f221b5-756b-4568-a55a-89c298d7d7d5.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkxMDE5NDIsIm5iZiI6MTczOTEwMTY0MiwicGF0aCI6Ii8xMTk0MDU5LzI2MDEwNjM5My05NmYyMjFiNS03NTZiLTQ1NjgtYTU1YS04OWMyOThkN2Q3ZDUucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwOSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDlUMTE0NzIyWiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YWY2OTRmOTVmZjk2NmU4ZGZlM2MyMDVjOTUzY2Q5ZGI3M2IwMmI2YmY0OTkxNjg0YTk4M2U2NzRiNWViZDVhNCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.ZoltHeh8RjZ2KgoHO9ehEFfskQUzsa3mBVoWg-X19d0)
const data = new Array(300);
for (let i = 0; i < data.length; i++) {
data[i] = Math.sin(0.3 * i) * Math.cos(0.6 * i) - Math.sin(i * Math.PI / 50) * Math.abs(i - 100) / 30
}
console.log(Plot.plot(data, {axisScale: PlotAxisScale.log}));
![](https://private-user-images.githubusercontent.com/1194059/260106467-56d636ec-e0ed-471b-8084-f003f74e9aa1.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkxMDE5NDIsIm5iZiI6MTczOTEwMTY0MiwicGF0aCI6Ii8xMTk0MDU5LzI2MDEwNjQ2Ny01NmQ2MzZlYy1lMGVkLTQ3MWItODA4NC1mMDAzZjc0ZTlhYTEucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwOSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDlUMTE0NzIyWiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NDhiZWE1MjIxODA2OTUyZTFlZTQ2ZmU5Nzg1OWUzN2IzN2Q1ZTM2ODhhN2Y0MzU4YmM2ZjY1NDczZWVmNWE3YiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.4qEupYpfpPEVOuzTq6k99fOqf5jWbVt00hJvTXb7B0g)
const data = [1, 2, 3]
console.log(Plot.plot(data, {zoom: true}));
![](https://private-user-images.githubusercontent.com/1194059/270635996-3d2ba01f-cd7c-406b-80ee-71c6d0e69ed9.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkxMDE5NDIsIm5iZiI6MTczOTEwMTY0MiwicGF0aCI6Ii8xMTk0MDU5LzI3MDYzNTk5Ni0zZDJiYTAxZi1jZDdjLTQwNmItODBlZS03MWM2ZDBlNjllZDkucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwOSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDlUMTE0NzIyWiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NTk3YTdlZDc4OWYyYzI0YzQxZDFlYWFhNGQwYzljODhhNjg0MjY5ODkzNTdjODc5NjdiZmRlNjJhYjQ4MzU3ZSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.FLRnEGRvAoOAXAZXRM2_Ml1GZTEGdALGOTsPY3PYNFU)
const data = new Array(300);
for (let i = 0; i < data.length; i++) {
data[i] = Math.sin(0.3 * i) * Math.cos(0.6 * i) - Math.sin(i * Math.PI / 50) * Math.abs(i - 100) / 30
}
console.log(Plot.plot(data, {}, {overflow: PlotSeriesOverflow.logScale}));
![](https://private-user-images.githubusercontent.com/1194059/260106529-252139a7-2502-4b71-ba5f-917d8fcfeb9f.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkxMDE5NDIsIm5iZiI6MTczOTEwMTY0MiwicGF0aCI6Ii8xMTk0MDU5LzI2MDEwNjUyOS0yNTIxMzlhNy0yNTAyLTRiNzEtYmE1Zi05MTdkOGZjZmViOWYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwOSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDlUMTE0NzIyWiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MjU0YTFmNjg1MmY1ODc5MzE5YTRmNzUwMjY2ZDYzMDUwYmY5YmNmYzUyM2I5Mzg5YjhkMWQyNTNmNWMzZGNkYSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.MmXUwCB1GhU1lnh4gKOgRqrhj0CyhUJcHOV1HXpGegQ)
const data = new Array(300);
for (let i = 0; i < data.length; i++) {
data[i] = Math.sin(0.3 * i) * Math.cos(0.6 * i) - Math.sin(i * Math.PI / 50) * Math.abs(i - 100) / 30
}
console.log(Plot.plot(data, {}, {color: Color.green}));
![](https://private-user-images.githubusercontent.com/1194059/260107176-f3d1cc85-d595-4230-8151-e6aaf9b74a2e.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkxMDE5NDIsIm5iZiI6MTczOTEwMTY0MiwicGF0aCI6Ii8xMTk0MDU5LzI2MDEwNzE3Ni1mM2QxY2M4NS1kNTk1LTQyMzAtODE1MS1lNmFhZjliNzRhMmUucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwOSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDlUMTE0NzIyWiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZjFiMTExYmMyNDVhNDU3NmU4NjBjZWFlOTIwMzU5NTQwN2Y5NTFiMWQwMWE2MmFiZDM4ZWZjYzk0NWQ3ZTdjYyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.wSxYCTi3hWCzsMmqO2gVxV0l1ZHUU8YbUuSs650MnN0)
const data = new Array(200);
for (let i = 0; i < data.length; i++) {
data[i] = Math.sin(0.3 * i) * Math.cos(0.6 * i) - Math.sin(i * Math.PI / 50) * Math.abs(i - 100) / 30
}
console.log(Plot.plot(data, {height: 5}));
![](https://private-user-images.githubusercontent.com/1194059/260107332-4189112f-6498-482f-a491-e3f161a2863a.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkxMDE5NDIsIm5iZiI6MTczOTEwMTY0MiwicGF0aCI6Ii8xMTk0MDU5LzI2MDEwNzMzMi00MTg5MTEyZi02NDk4LTQ4MmYtYTQ5MS1lM2YxNjFhMjg2M2EucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwOSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDlUMTE0NzIyWiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9OWExYWU1N2VjMTliY2NhOGNmYThiODczZDRmNDAzNGNjMGY4NWUwYzQ3ZjEzZDNmZmNjNzNhNjAxNzcwOTZlYiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.vQoQQsrjb3oTPM56N-BA6mBYPVmmZ87dpqEos45-zME)
text-graph.js
is released under the BSD-3-Clause License.