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.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5MTMxNjQsIm5iZiI6MTczODkxMjg2NCwicGF0aCI6Ii8xMTk0MDU5LzI2MDA4NTY0MC1hNjhmNTE3NS0zNGRiLTQ0NjItOGRlMi02NDliNjBkZDM3NWIucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDdUMDcyMTA0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NzE1MGFmYjU4YWRkNTM4YmYwN2IzNDVkNTI4ZGEwYWE1ZmU1NDg2MDA1ODJjMzVhY2ZkNWQ2MmRkOWY3NWY1MCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.VkXL9DEaqfRPjKIJlwBP8Sz9ITxifIYGEJM-YD6rei4)
Source code: link
![](https://private-user-images.githubusercontent.com/1194059/260085110-725b01bb-2bdb-47b8-b8e2-2728059000b1.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5MTMxNjQsIm5iZiI6MTczODkxMjg2NCwicGF0aCI6Ii8xMTk0MDU5LzI2MDA4NTExMC03MjViMDFiYi0yYmRiLTQ3YjgtYjhlMi0yNzI4MDU5MDAwYjEucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDdUMDcyMTA0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZGFlM2NlYTBlY2MyMGU2MTM0NjYxNjFlODkzZmY2Yzg5MzQ2OGRlMGFkMjA3NWZhN2NiOGI0YTliZmFmNTdjYyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.Dd__X5ldtaXU9z6u3cmC5vxVUMhA4VhgCOnsbIm8UoY)
Source code: link
![](https://private-user-images.githubusercontent.com/1194059/260084589-483a9035-9ab2-4439-88eb-0a44171b0ebe.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5MTMxNjQsIm5iZiI6MTczODkxMjg2NCwicGF0aCI6Ii8xMTk0MDU5LzI2MDA4NDU4OS00ODNhOTAzNS05YWIyLTQ0MzktODhlYi0wYTQ0MTcxYjBlYmUucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDdUMDcyMTA0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MWZlMDBlYTA2ZjlhOTFkODVkNzM5ZGEzM2M4ZjE1YTI4NDY0ZDIxMzg4ZjBjYjEyMTVkODY2YzVjZjE5NDgzMiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.baGNFBgDmjzRMv5S8yjsNsATyw755TxhhnRcJ4E4y_g)
Source code: link
![](https://private-user-images.githubusercontent.com/1194059/260213220-5b5da127-4a32-4f88-9759-1bb796dda928.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5MTMxNjQsIm5iZiI6MTczODkxMjg2NCwicGF0aCI6Ii8xMTk0MDU5LzI2MDIxMzIyMC01YjVkYTEyNy00YTMyLTRmODgtOTc1OS0xYmI3OTZkZGE5MjgucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDdUMDcyMTA0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NzA1MzNhNDFjM2RmMjYxMTJiZDUxYWNhNjEyMTBlZTlmMzVkODQwNmU2ODQxMTVmMjA4ZmU2YTliMzJhYmQ3ZiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.ds3njMA9tcLiS2fopjT63mTkqzYuS9EiWjxfS-ZI3Sg)
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.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5MTMxNjQsIm5iZiI6MTczODkxMjg2NCwicGF0aCI6Ii8xMTk0MDU5LzI2MDEwNjM5My05NmYyMjFiNS03NTZiLTQ1NjgtYTU1YS04OWMyOThkN2Q3ZDUucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDdUMDcyMTA0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZWY2OGYwYzg3ZDU0ODk3YTg0MmI4NTQxMTljMTZhZDk1NmE5Mzc3MDUyNTg0MTZiZWQ3ODAyZDBlOGIxNGZiNSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.SkAiG6stb7vIEInPO8AFkXlfYsmWwWbhaZO_vLfbzi8)
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.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5MTMxNjQsIm5iZiI6MTczODkxMjg2NCwicGF0aCI6Ii8xMTk0MDU5LzI2MDEwNjQ2Ny01NmQ2MzZlYy1lMGVkLTQ3MWItODA4NC1mMDAzZjc0ZTlhYTEucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDdUMDcyMTA0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZTBjYzNmYzgxOGI0ZDk1YjQyOTIzMzQzNzAxZGZjZjc1NDZhZWU5N2RiOWZlZWQ5MzBmMmZhOWM3MmMyZDRjZCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.5u9qBmwDFLLg_wzJdiIzu5H2Ro5sakWNHlIUuDxsuMg)
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.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5MTMxNjQsIm5iZiI6MTczODkxMjg2NCwicGF0aCI6Ii8xMTk0MDU5LzI3MDYzNTk5Ni0zZDJiYTAxZi1jZDdjLTQwNmItODBlZS03MWM2ZDBlNjllZDkucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDdUMDcyMTA0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9M2YxNTdmNTQ2Mjk1M2QzODRiMzA3MjgzY2NiZWFiMGY5Yzc4M2ZmNTc0OGJhOGQwYWZkYThiOWU2ZWQzZjZhNSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.sjmdyXWsDY12YQvXHEu6N381k8N5BvB236bh2Ds7NUw)
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.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5MTMxNjQsIm5iZiI6MTczODkxMjg2NCwicGF0aCI6Ii8xMTk0MDU5LzI2MDEwNjUyOS0yNTIxMzlhNy0yNTAyLTRiNzEtYmE1Zi05MTdkOGZjZmViOWYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDdUMDcyMTA0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZDEzMzA3ZjcwMmIwZDVkNTk2MzFkYWU0NzU0MWFlNzgzNDIwYzNkMWU3NjViNTU1OWQzNWU0MzhiZTNjYTk3MSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.oiaUi7GyoVLzVtj7HQQpJ672Qj2S-D32iaGsot6wcj0)
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.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5MTMxNjQsIm5iZiI6MTczODkxMjg2NCwicGF0aCI6Ii8xMTk0MDU5LzI2MDEwNzE3Ni1mM2QxY2M4NS1kNTk1LTQyMzAtODE1MS1lNmFhZjliNzRhMmUucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDdUMDcyMTA0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9OTY1ZWM5NDc5YTM4NWY5NTc1YzVkOGQ3OWFiOGI5ZGExMTg5YzhhNWQwYjNlYzNjNDk5OWQwNjk3OGVmZWUwZCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.WKFnNZhKZvA3I6o7-PtaIbbOeBnvHTCVXtRcS7_fHRo)
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.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5MTMxNjQsIm5iZiI6MTczODkxMjg2NCwicGF0aCI6Ii8xMTk0MDU5LzI2MDEwNzMzMi00MTg5MTEyZi02NDk4LTQ4MmYtYTQ5MS1lM2YxNjFhMjg2M2EucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDdUMDcyMTA0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YWIxYjVlN2NhYmJmYmI2NjU3Nzg2ZDczMGZhYTQxZTQxMzRmMDBmNDU2MmJmMDc5ODhkYTYxZDk2MmQ5YjU3MSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.UH3RFFsrR460p-8vYcDlwX2bcr17kpGXKsOc5N3aWfA)
text-graph.js
is released under the BSD-3-Clause License.