-
Notifications
You must be signed in to change notification settings - Fork 96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Way of labeling x axis #56
Comments
Technically, since it's x-aligned, you can do that after plotting out the series. Also, those labels can vary a lot, could be dates, or timeframes, or arbitrary non-time units... So, it can be easily added in the userland. Since there's so much variation in horizontal labels, we would leave it to the user for now. If you can suggest a good compact way of plotting arbitrary horizontal labels, we will consider adding it. Maybe some kind of a |
I like that labels idea. Perhaps usage would look like so: var s = []
for (var i = 0; i < 120; i++)
s[i] = 15 * Math.cos (i * ((Math.PI * 8) / 120))
// If labels returns undefined or false, the label is skipped. Otherwise plots.
console.log (asciichart.plot (s, { labels: (index) => index % 10 === 0 ? index: false })) |
Hey 👋 For those interested, I wrote a helper function for adding (numeric) x-labels to an asciichart: I guess it's not polished enough to do a PR, but maybe it's still useful for anyone looking for that functionality! |
@chrispahm thanks so much for your involvement! This is really cool! I will try to add that to the master in a generalized way ) Thx again! |
Any update on this implementation? |
FWIW, I took @chrispahm 's work (thanks!) and extended it a bit, so that it supports:
Here is an example screenshot: Example config for the screenshot above (I just replaced the data with simpler arrays): const plotConfig = {
title: "this is an interesting graph",
height: 15,
width: 100,
colors: [
plot.blue,
plot.green,
],
lineLabels: [
"precision",
"recall"
],
xLabel: "threshold",
yLabel: "percent"
};
console.log(plot.plot([[ 1, 2, 3], [ 4, 5, 6]], plotConfig)); Code - just use the const asciichart = require ('asciichart');
const stripAnsi = require('strip-ansi');
const assert = require('assert');
function plot(yArray,config = {}) {
yArray = Array.isArray(yArray[0]) ? yArray : [yArray];
yArray.forEach(a => assert(a.length > 0, "Cannot plot empty array"));
const originalWidth = yArray[0].length;
if (config.width) {
yArray = yArray.map((arr) => {
const newArr = [];
for (let i = 0; i < config.width; i++) {
newArr.push(arr[Math.floor(i * arr.length/config.width)]);
}
return newArr;
});
}
const plot = asciichart.plot(yArray, config);
const xArray = config.xArray || (Array.isArray(yArray[0]) ? yArray[0] : yArray).map((v,i) => i);
// determine the overall width of the plot (in characters)
const plotFirstLine = stripAnsi(plot).split('\n')[0];
const fullWidth = plotFirstLine.length;
// get the number of characters reserved for the y-axis legend
const leftMargin = plotFirstLine.split(/┤|┼╮|┼/)[0].length + 1;
// the difference between the two is the actual width of the x axis
const widthXaxis = fullWidth - leftMargin;
// get the number of characters of the longest x-axis label
const longestXLabel = xArray.map(l => l.toString().length).sort((a,b) => b - a)[0]
const tickDistance = longestXLabel + 2;
let ticks = ' '.repeat(leftMargin-1);
for (let i = 0; i < widthXaxis; i++) {
if ((i % tickDistance === 0 && (i + tickDistance) < widthXaxis) || i === (widthXaxis-1)) {
ticks += "┬";
} else {
ticks += "─";
}
}
const lastTickValue = originalWidth - 1;
let tickLabels = ' '.repeat(leftMargin-1);
if (widthXaxis <= tickDistance) {
// too short, just last tick
tickLabels += (lastTickValue.toFixed()).padStart(widthXaxis - (tickLabels.length - leftMargin + 1));
} else {
for (let i = 0; i < widthXaxis; i++) {
const tickValue = Math.round(i/widthXaxis * originalWidth);
if ((i % tickDistance === 0 && (i + tickDistance) < widthXaxis)) {
tickLabels += tickValue.toFixed().padEnd(tickDistance);
// final tick
if (i >= (widthXaxis - 2 * tickDistance)) {
if (widthXaxis % tickDistance === 0) {
tickLabels += (lastTickValue.toFixed()).padStart(widthXaxis - (tickLabels.length - leftMargin + 1));
} else {
tickLabels += (lastTickValue.toFixed()).padStart(widthXaxis - (tickLabels.length - leftMargin + 1));
}
}
}
}
}
const title = config.title ? `${' '.repeat(leftMargin + (widthXaxis - config.title.length)/2)}${config.title}\n` : '';
let yLabel = '';
if (config.yLabel || Array.isArray(config.lineLabels)) {
if (config.yLabel) {
yLabel += `${asciichart.darkgray}${config.yLabel.padStart(leftMargin + config.yLabel.length/2)}${asciichart.reset}`;
}
if (Array.isArray(config.lineLabels)) {
let legend = '';
for (let i = 0; i < Math.min(yArray.length, config.lineLabels.length); i++) {
const color = Array.isArray(config.colors) ? config.colors[i] : asciichart.default;
legend += ` ${color}─── ${config.lineLabels[i]}${asciichart.reset}`;
}
yLabel += ' ' .repeat(fullWidth - 1 - stripAnsi(legend).length - stripAnsi(yLabel).length) + legend;
}
yLabel += `\n${'╷'.padStart(leftMargin)}\n`;
}
const xLabel = config.xLabel ? `\n${asciichart.darkgray}${config.xLabel.padStart(fullWidth - 1)}${asciichart.reset}` : '';
return `\n${title}${yLabel}${plot}\n${ticks}\n${tickLabels}${xLabel}\n`;
} Feel free to use or extend this! EDIT 1: added optional |
@alexkli thank you for sharing it! |
Hey!
I think it would be really awesome to be able to label the x axis. Are there any plans of supporting this?
The text was updated successfully, but these errors were encountered: