thistogram
Version:
A simple text based histogram and chart generator
82 lines • 3.59 kB
JavaScript
import { BoxSymbol, boxSymbols, histoCharsBottomToTop, histoCharsLeftToRight } from './drawingCharacters.js';
/**
* Draw a simple histogram with a single line of characters.
* @param data - the data to draw
* @param min - optional minimum value, defaults to the minimum value in the data
* @param max - optional maximum value, defaults to the maximum value in the data
* @param barChars - the characters to use for the bar, defaults to `['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█']`
* @returns a string of the histogram
*/
export function simpleHistogram(data, min, max, barChars = histoCharsBottomToTop) {
const [minVal, maxVal] = minMaxRange(data, min, max);
const range = maxVal - minVal || 1;
const lenBarChars = barChars.length;
const scale = lenBarChars / range;
const scaled = data.map((v) => Math.ceil((Math.min(v, maxVal) - minVal) * scale));
return scaled.map((v) => (v > 0 ? barChars[v - 1] : ' ')).join('');
}
/**
* Generate a bar line for a value
* @param value - between 0 and 1 inclusive.
* @param width - the width of the bar in characters
* @param padding - optional padding character, defaults to space.
* @param barChars - the characters to use for the bar, defaults to `['▏', '▎', '▍', '▌', '▋', '▊', '▉', '█']`
* @returns a string of the bar
*/
export function barHorizontal(value, width, padding = ' ', barChars = histoCharsLeftToRight) {
value = Math.max(Math.min(value, 1), 0);
const histoFractions = barChars.length;
const barWidth = Math.floor(value * histoFractions * width);
const fullChar = barChars[histoFractions - 1];
if (barWidth === 0)
return barChars[0].padEnd(width, padding);
const rep = barWidth / histoFractions;
const fraction = barWidth % histoFractions;
return (fullChar.repeat(rep) + (fraction ? barChars[fraction - 1] : '')).padEnd(width, padding);
}
const stPlotChars = {
left2: boxSymbols[BoxSymbol.leftT],
left1: boxSymbols[BoxSymbol.bottomT],
middle: boxSymbols[BoxSymbol.horizontal],
center: boxSymbols[BoxSymbol.cross],
right1: boxSymbols[BoxSymbol.bottomT],
right2: boxSymbols[BoxSymbol.rightT],
point: '●',
};
/**
*
* @param point - the point to plot
* @param sd - the standard deviation
* @param mean - the mean
* @param width - the width of the plot in characters
* @param range - the +/- range to plot, defaults to 2.5 SD.
* A value of 1 would mean to show only the range of a single standard deviation.
* @returns a string representing the plot
*/
export function plotPointRelativeToStandardDeviation(point, sd, mean, width, range = 2.5) {
const plot = ' '.repeat(width).split('');
const scale = width / (2 * range * sd);
const diff = point - mean;
const mid = width >> 1;
const f = (v) => Math.min(Math.max(0, Math.floor(v * scale + mid + 0.5)), width - 1);
const leftMost = f(-2 * sd);
const rightMost = f(2 * sd);
for (let i = leftMost; i <= rightMost; i++) {
plot[i] = stPlotChars.middle;
}
plot[mid] = stPlotChars.center;
plot[f(-sd)] = stPlotChars.left1;
plot[f(sd)] = stPlotChars.right1;
plot[leftMost] = stPlotChars.left2;
plot[rightMost] = stPlotChars.right2;
plot[f(diff)] = stPlotChars.point;
return plot.join('');
}
function minMaxRange(values, min, max) {
const minVal = min ?? Math.min(...values);
const maxVal = max ?? Math.max(...values);
const adj = (maxVal - minVal) * 0.05;
const r = [min ?? minVal - adj, max ?? maxVal + adj];
return r;
}
//# sourceMappingURL=bars.js.map