Package: charts - uhop/console-toolkit GitHub Wiki
The charts
package provides bar/column charts for displaying data. The charts can be classified
into several types:
- Orientation:
- Bar charts: horizontal rectangles.
- Column charts: vertical rectangles.
- Comparative drawing:
- Stacked: all values are stacked on top of each other.
- Grouped: all values are grouped together in a cluster.
- Drawing elements:
- Plain: each series is drawn with characters.
- Frac: each series is draw as a rectangle with fractional width or height.
- Uses
drawRealWidthBlock()
ordrawRealHeightBlock()
function of Module: draw-block-frac.
- Uses
- Block: each series is drawn as a rectangle.
- Uses
drawBlock()
function of Module: draw-block.
- Uses
- Block-frac: each series is drawn as a rectangle with fractional width or height to provide visual gaps between series.
Charts are drawn using numeric data and a theme.
Logically data is a 2D array of non-negative numbers. Data is represented as an array of series.
Series is an array of non-negative numbers, null
(no data), or objects with the following properties:
value
— a non-negative number. All other values will be replaced with0
.
The rest of properties are optional:
label
— a string that labels the value.colorState
— a state object. See Package: ansi for details.state
— a state object.symbol
— a character that will be used to draw the rectangle.
If a series has only one element in the array, it can be used directly as is. If a data
object has just value
, it can be represented by the value itself. For example: [1, 2]
instead of [1], [2](/uhop/console-toolkit/wiki/1],-[2)
or [{value: 1}], [{value: 2}](/uhop/console-toolkit/wiki/{value:-1}],-[{value:-2})
.
Not all charts can use all properties. See the documentation of the chart type for details.
For example, column charts don't use label
property, while block-based charts don't use
symbol
property.
colorState
and state
are combined together to form the final state object in this order.
All bar charts can be found in bars/. All column charts can be found in columns/.
All charts are represented by drawing functions, which return strings and look like this: drawBarChart(values, width, options)
.
The arguments values
and width
are required. The options
argument is optional. values
is the data
array described above. width
is the width (or height for column charts) of the chart in characters.
The options
argument is an object with the following properties:
theme
— a chart theme object. It is described below.maxValue
— an optional maximum value. If not specified, the maximum value is calculated from the data. If it is value is-1
, the data series will fit intowidth
.gap
— an optional gap between series in characters. If not specified, the gap is 0.groupGap
— an optional gap between groups in characters. If not specified, the gap is 1. This property is used only for grouped charts.initState
— an optional initial state object.reverse
— an optional flag that reverses the order of the series. This flag is used to draw charts in an alternative order: from right to left or top to bottom.- Bar charts always produce strings. Strings produced with
{reverse: true}
are meant to be aligned to the right. It can be done withBox.make(strings, {align: 'right'})
.
- Bar charts always produce strings. Strings produced with
rectSize
— an optional height of a bar (width of a column) in characters. Defaults to 1.blockTheme
— an optional block theme object. See block themes for details. This property is used only for block-based charts.- Additionally:
t
,l
,r
andb
flags are used to draw (if set) the top, left, right and bottom borders.
- Additionally:
drawEmptyBorder
— an optional flag that draws an empty border. This property is used only for block-frac-based charts. See Module: draw-block-frac for details.drawItem()
— an optional function that draws an item. This property is used only bybars/plain.js
charts. It overlays thelabel
property over an item.truncate
— an optional flag that truncates the label if it is too long.useEllipsis
— an optional flag that uses ellipsis if the label is too long.
Example:
import drawChart from 'console-toolkit/charts/bars/plain.js';
console.log('Stacked bars:');
const chart = drawChart(
[
[2, 1, 2],
[5, 1, 4],
[1, 1],
[3, 1, 3]
],
50
);
for (const line of chart) console.log(line);
All chart modules export drawChart()
function by name and as the default export.
charts/bars/plain.js
The charts/bars/plain.js module draws a chart with stacked bars.
The module exports two functions used to draw individual items: defaultDrawItem()
and drawItemLabel()
.
The former is used as the default for drawItem
option. The latter is used when we want to overlay
a label over an item. See how to use it in the example below.
defaultDrawItem()
uses the 7/8th block symbol if no symbol
is inherited from a data item or its
themes. It creates a nice separation line between series. drawItemLabel()
uses the label
property
to draw the label. It converts colors to background colors to create its effect.
Example
import drawChart, {drawItemLabel} from 'console-toolkit/charts/bars/plain.js';
import style from 'console-toolkit/style.js';
import Box from 'console-toolkit/box.js';
const data = [
[2, 1, 2],
[5, 1, 4],
[1, 1],
[3, 1, 3]
];
console.log('Stacked bars: {}');
const chart1 = drawChart(data, 50);
for (const line of chart1) console.log(line);
console.log('\nStacked bars: {maxValue: -1}');
const chart2 = drawChart(data, 50, {maxValue: -1});
for (const line of chart2) console.log(line);
const labels = ['zero', 'one', 'two', 'three', 'four', 'five'];
const dataWithLabels = data.map(series =>
series.map(datum => ({value: datum, label: labels[datum]})));
console.log('\nStacked bars with labels:');
const chart3 = drawChart(dataWithLabels, 50,
{drawItem: drawItemLabel, initState: style.black});
for (const line of chart3) console.log(line);
console.log('\nStacked bars with labels and reversed:');
const chart4 = drawChart(dataWithLabels, 50,
{drawItem: drawItemLabel, initState: style.black, reverse: true});
const box = Box.make(chart4, {align: 'right'});
for (const line of box.box) console.log(line);
It produces the following output:
charts/bars/plain-grouped.js
The charts/bars/plain-grouped.js
module draws a chart with grouped bars. See charts/bars/plain.js
for details.
Example
import drawChart from 'console-toolkit/charts/bars/plain-grouped.js';
import Box from 'console-toolkit/box.js';
const data = [
[2.1, 1.9, 2.2],
[1.1, 1.2]
];
console.log('Grouped bars: {}');
const chart1 = drawChart(data, 50);
for (const line of chart1) console.log(line);
console.log('\nGrouped bars: {reverse: true}');
const chart2 = drawChart(data, 50, {reverse: true});
const box = Box.make(chart2, {align: 'right'});
for (const line of box.box) console.log(line);
It produces the following output:
charts/bars/frac-grouped.js
The charts/bars/frac-grouped.js module draws a chart with grouped fractional bars. The width of each bar is accurate up to 1/8th of a character.
This chart ignores the symbol
and label
properties because it uses special symbols to represent bars.
Currently it doesn't support reverse
option.
Example
import drawChart from 'console-toolkit/charts/bars/frac-grouped.js';
const data = [
[2.1, 1.9, 2.2],
[1.1, 1.2]
];
console.log('Grouped bars: {maxValue: 10}');
const chart1 = drawChart(data, 50, {maxValue: 10});
for (const line of chart1) console.log(line);
It produces the following output:
charts/bars/block.js
The charts/bars/block.js module draws a chart with block-based bars.
Such bars consists of two major parts: a frame and a body. The body is filled with solid full blocks.
The frame is drawn with fractional blocks. In order to avoid visual gaps between bars, the frame is
not drawn on certain sides. It can be forced with the t
, l
, r
and b
flags. If a flag is falsy,
the corresponding part is not drawn.
This chart ignores the symbol
and label
properties because it uses special symbols to represent bars.
These symbols can be specified in the blockTheme
option. See Module: draw-block.
Example
import drawChart from 'console-toolkit/charts/bars/block.js';
import Box from 'console-toolkit/box.js';
const data = [
[2, 1, 2],
[5, 1, 4],
[1, 1],
[3, 1, 3]
];
console.log('Stacked bars (no bottom border):');
const chart1 = drawChart(data, 50, {b: false});
for (const line of chart1) console.log(line);
console.log('\nStacked bars (no top border): {maxValue: -1, t: false}');
const chart2 = drawChart(data, 50, {maxValue: -1, t: false});
for (const line of chart2) console.log(line);
console.log('\nStacked bars (no bottom border): {reverse: true, b: false}');
const chart3 = drawChart(data, 50, {b: false, reverse: true});
const box = Box.make(chart3, {align: 'right'});
for (const line of box.box) console.log(line);
It produces the following output:
charts/bars/block-grouped.js
The charts/bars/block-grouped.js
module draws a chart with grouped block-based bars. See charts/bars/block.js
for details.
Example
import drawChart from 'console-toolkit/charts/bars/block-grouped.js';
import Box from 'console-toolkit/box.js';
const data = [
[2.1, 1.9, 2.2],
[1.1, 1.2]
];
console.log('Grouped bars: {t: false}');
const chart1 = drawChart(data, 50, {t: false});
for (const line of chart1) console.log(line);
console.log('Grouped bars: {t: false, reverse: true}');
const chart2 = drawChart(data, 50, {t: false, reverse: true});
const box = Box.make(chart2, {align: 'right'});
for (const line of box.box) console.log(line);
It produces the following output:
charts/bars/block-frac.js
The charts/bars/block-frac.js
module draws a chart with block-based fractional bars. This chart can use a fractional height for bars
specified by the rectSize
option. See charts/bars/block.js
for details.
Example
import drawChart from 'console-toolkit/charts/bars/block-frac.js';
import Box from 'console-toolkit/box.js';
const data = [
[2, 1, 2],
[5, 1, 4],
[1, 1],
[3, 1, 3]
];
console.log('Stacked bars: {rectSize: 0.75}');
const chart1 = drawChart(data, 50, {rectSize: 0.75});
for (const line of chart1) console.log(line);
console.log('\nStacked bars: {rectSize: 0.5, maxValue: -1}');
const chart2 = drawChart(data, 50, {maxValue: -1, rectSize: 0.5});
for (const line of chart2) console.log(line);
console.log('\nStacked bars: {rectSize: 0.875,reverse: true}');
const chart3 = drawChart(data, 50, {rectSize: 0.875, reverse: true});
const box = Box.make(chart3, {align: 'right'});
for (const line of box.box) console.log(line);
It produces the following output:
charts/bars/block-frac-grouped.js
The charts/bars/block-frac-grouped.js
module draws a chart with grouped block-based fractional bars. See charts/bars/block-frac.js
for details.
Example
import drawChart from 'console-toolkit/charts/bars/block-frac-grouped.js';
import Box from 'console-toolkit/box.js';
const data = [
[2.1, 1.9, 2.2],
[1.1, 1.2]
];
console.log('Grouped bars: {rectSize: 0.9}');
const chart1 = drawChart(data, 50, {rectSize: 0.9});
for (const line of chart1) console.log(line);
console.log('Grouped bars: {rectSize: 0.1, reverse: true}');
const chart2 = drawChart(data, 50, {rectSize: 0.1, reverse: true});
const box = Box.make(chart2, {align: 'right'});
for (const line of box.box) console.log(line);
It produces the following output:
charts/columns/plain.js
The charts/columns/plain.js module draws a chart with stacked columns.
Example
import drawChart from 'console-toolkit/charts/columns/plain.js';
const data = [
[2, 1, 2],
[5, 1, 4],
[1, 1],
[3, 1, 3]
];
console.log('Stacked columns: {}');
const chart1 = drawChart(data, 8);
for (const line of chart1) console.log(line);
console.log('\nStacked columns: {maxValue: -1}');
const chart2 = drawChart(data, 8, {maxValue: -1});
for (const line of chart2) console.log(line);
console.log('\nStacked columns: {reverse: true}');
const chart3 = drawChart(data, 8, {reverse: true});
for (const line of chart3) console.log(line);
It produces the following output:
charts/columns/plain-grouped.js
The charts/columns/plain-grouped.js
module draws a chart with grouped columns. See charts/columns/plain.js
for details.
Example
import drawChart from 'console-toolkit/charts/columns/plain-grouped.js';
const data = [
[2.1, 1.9, 2.2],
[1.1, 1.2]
];
console.log('Grouped columns: {}');
const chart1 = drawChart(data, 8);
for (const line of chart1) console.log(line);
console.log('\nGrouped columns: {reverse: true}');
const chart2 = drawChart(data, 8, {reverse: true});
for (const line of chart2) console.log(line);
It produces the following output:
charts/columns/frac-grouped.js
The charts/columns/frac-grouped.js
module draws a chart with grouped fractional columns. The width of each column is accurate up to 1/8th of
a character. See its sister module charts/bars/frac-grouped.js
for details.
Example
import drawChart from 'console-toolkit/charts/columns/frac-grouped.js';
const data = [
[2.1, 1.9, 2.2],
[1.1, 1.2]
];
console.log('Grouped columns: {maxValue: 5}');
const chart1 = drawChart(data, 8, {maxValue: 5});
for (const line of chart1) console.log(line);
It produces the following output:
charts/columns/block.js
The charts/columns/block.js
module draws a chart with block-based columns. See its sister module charts/bars/block.js
for details.
Example
import drawChart from 'console-toolkit/charts/columns/block.js';
const data = [
[2, 1, 2],
[5, 1, 4],
[1, 1],
[3, 1, 3]
];
console.log('Stacked columns (no right border):');
const chart1 = drawChart(data, 8, {r: false});
for (const line of chart1) console.log(line);
console.log('\nStacked columns (no left border): {maxValue: -1, l: false}');
const chart2 = drawChart(data, 8, {maxValue: -1, l: false});
for (const line of chart2) console.log(line);
console.log('\nStacked columns (no right border): {reverse: true, r: false}');
const chart3 = drawChart(data, 8, {r: false, reverse: true});
for (const line of chart3) console.log(line);
It produces the following output:
charts/columns/block-grouped.js
The charts/columns/block-grouped.js
module draws a chart with grouped block-based columns. See charts/columns/block.js
for details.
Example
import drawChart from 'console-toolkit/charts/columns/block-grouped.js';
const data = [
[2.1, 1.9, 2.2],
[1.1, 1.2]
];
console.log('Grouped columns: {r: false}');
const chart1 = drawChart(data, 8, {r: false});
for (const line of chart1) console.log(line);
console.log('\nGrouped columns: {l: false, reverse: true}');
const chart2 = drawChart(data, 8, {l: false, reverse: true});
for (const line of chart2) console.log(line);
It produces the following output:
charts/columns/block-frac.js
The charts/columns/block-frac.js
module draws a chart with block-based fractional columns. See its sister module charts/bars/block-frac.js
for details.
Example
import drawChart from 'console-toolkit/charts/columns/block-frac.js';
import Box from 'console-toolkit/box.js';
const data = [
[2, 1, 2],
[5, 1, 4],
[1, 1],
[3, 1, 3]
];
console.log('Stacked columns: {rectSize: 0.75}');
const chart1 = drawChart(data, 8, {rectSize: 0.75});
for (const line of chart1) console.log(line);
console.log('\nStacked columns: {rectSize: 0.5, maxValue: -1}');
const chart2 = drawChart(data, 8, {maxValue: -1, rectSize: 0.5});
for (const line of chart2) console.log(line);
console.log('\nStacked columns: {rectSize: 0.875,reverse: true}');
const chart3 = drawChart(data, 8, {rectSize: 0.875, reverse: true});
const box = Box.make(chart3, {align: 'right'});
for (const line of box.box) console.log(line);
It produces the following output:
charts/columns/block-frac-grouped.js
The charts/columns/block-frac-grouped.js
module draws a chart with grouped block-based fractional columns. See charts/columns/block-frac.js
for details.
Example
import drawChart from 'console-toolkit/charts/columns/block-frac-grouped.js';
import Box from 'console-toolkit/box.js';
const data = [
[2.1, 1.9, 2.2],
[1.1, 1.2]
];
console.log('Grouped columns: {rectSize: 0.9}');
const chart1 = drawChart(data, 8, {rectSize: 0.9});
for (const line of chart1) console.log(line);
console.log('\nGrouped columns: {rectSize: 0.1, reverse: true}');
const chart2 = drawChart(data, 8, {rectSize: 0.1, reverse: true});
const box = Box.make(chart2, {align: 'right'});
for (const line of box.box) console.log(line);
It produces the following output:
charts/themes/default.js
The charts/themes/default.js module contains the default chart theme. It will be used if no other theme is specified.
A theme is defined by an array of objects, which mixed in with data objects defined above.
Typically it defines colorState
, state
and/or symbol
properties. These objects are
selected in the order they appear in the array.
The empty part of a chart is defined in the empty
property of the theme object (the array)
with the same structure. Bar charts produce strings, which should be properly aligned. They
don't use empty parts. But column charts use Box
instances and have to fill empty parts.
The default theme uses the following colors in this order:
- Bright versions of colors as
colorState
: cyan, magenta, blue, yellow, green, red. - Dark versions of the same colors in the same order.
The default empty
property defined as follows:
symbol
— a space character (' '
).state
— a "reset all" state object.
The default theme serves as a foundation for other themes. Its elements are copied into a data object initially, then a custom theme is merged, then a custom data object is merged.
Example
import drawChart from 'console-toolkit/charts/bars/plain.js';
import style from 'console-toolkit/style.js';
import {shades} from 'console-toolkit/symbols.js';
const data = [
[2, 1, 2],
[5, 1, 4],
[1, 1],
[3, 1, 3]
];
console.log('Custom theme: ASCII');
const customTheme1 = [...'#=o'].
map(symbol => ({state: style.reset.all, symbol}));
const chart1 = drawChart(data, 50, {theme: customTheme1});
for (const line of chart1) console.log(line);
console.log('\nCustom theme: shades');
const customTheme2 = shades.toReversed().
map(symbol => ({state: style.reset.all.bright.yellow, symbol}));
const chart2 = drawChart(data, 50, {theme: customTheme2});
for (const line of chart2) console.log(line);
console.log('\nCustom theme: rainbow');
const customTheme3 = [
{colorState: style.hex(0xee82ee)}, // violet
{colorState: style.hex(0x4b0082)}, // indigo
{colorState: style.hex(0x0000ff)}, // blue
{colorState: style.hex(0x008000)}, // green
{colorState: style.hex(0xffff00)}, // yellow
{colorState: style.hex(0xffa500)}, // orange
{colorState: style.hex(0xff0000)} // red
];
const chart3 = drawChart(data, 50, {theme: customTheme3});
for (const line of chart3) console.log(line);
It produces the following output: