kroitor / asciichart Goto Github PK
View Code? Open in Web Editor NEWNice-looking lightweight console ASCII line charts ╭┈╯ for NodeJS, browsers and terminal, no dependencies
License: MIT License
Nice-looking lightweight console ASCII line charts ╭┈╯ for NodeJS, browsers and terminal, no dependencies
License: MIT License
When I try to plot a chart with an array of values such as [100, 100, 100]
, eg.
var asciichart = require('asciichart');
asciichart.plot([100, 100, 100], {
height: 10,
});
I get the following error
/Users/pghalliday/projects/github/pghalliday/metriculator/node_modules/asciichart/asciichart.js:29
let result = new Array (rows + 1) // empty space
^
RangeError: Invalid array length
at Object.exports.plot (/Users/pghalliday/projects/github/pghalliday/metriculator/node_modules/asciichart/asciichart.js:29:22)
at Object.<anonymous> (/Users/pghalliday/projects/github/pghalliday/metriculator/test.js:2:12)
at Module._compile (module.js:662:30)
at Object.Module._extensions..js (module.js:673:10)
at Module.load (module.js:575:32)
at tryModuleLoad (module.js:515:12)
at Function.Module._load (module.js:507:3)
at Function.Module.runMain (module.js:703:10)
at startup (bootstrap_node.js:193:16)
at bootstrap_node.js:660:3
This seems to be due to the way the number of rows are calculated based on the range (which in this case I presume is calculated to zero). The same error occurs if I supply an empty array or an array with just 1 value. I think a possible fix would be to define a default range if one cannot be sensibly calculated. This should probably be added to the options in some way.
This impacts me as I'm starting with an empty chart and adding values over time. For now I have worked around it by ensuring that the range is non-zero before plotting. However this leads to an odd corner case where the last n
entries for a chart that only plots n
entries (due to screen width) are all equal (even if previous entries are not) then the chart cannot be updated.
Since version 1.5.10 the following fails:
asciiplot([1.]*1000, 80, 15)
With the following error:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
I guess the char should be selected depending on derivative
https://github.com/mfouesneau/asciiplot/blob/master/ap.py may be useful
Trying to chart with an empty list shouldn't crash.
import asciichartpy
asciichartpy.plot([])
Causes this:
Traceback (most recent call last):
File "terminal_chart.py", line 18, in <module>
print(asciichartpy.plot(losses, chart_config))
File "/Users/lib/python3.7/site-packages/asciichartpy/__init__.py", line 25, in plot
ratio = height / interval
ZeroDivisionError: float division by zero
Hello,
The package usage in pypi is written using node, not python.
Hey, I extended this thing to allow a fixed y-axis, instead of computing the bounds automatically. Just add min- and max fields to the config object. The data will be clamped in case it goes out of bounds. Feel free to commit.
"use strict";
(function (exports) {
exports.plot = function (series, cfg = undefined) {
cfg = (typeof cfg !== 'undefined') ? cfg : {}
let min = cfg.min;
let max = cfg.max;
if (min === undefined || max === undefined) {
min = series[0]
max = series[0]
for (let i = 1; i < series.length; i++) {
min = Math.min (min, series[i])
max = Math.max (max, series[i])
}
} else {
// clamp values to min, max
for (let i = 0; i < series.length; i++) {
series[i] = Math.max(min, Math.min(max, series[i]))
}
}
let range = Math.abs (max - min)
let offset = (typeof cfg.offset !== 'undefined') ? cfg.offset : 3
let padding = (typeof cfg.padding !== 'undefined') ? cfg.padding : ' '
let height = (typeof cfg.height !== 'undefined') ? cfg.height : range
let ratio = range !== 0 ? height / range : 1;
let min2 = Math.round (min * ratio)
let max2 = Math.round (max * ratio)
let rows = Math.abs (max2 - min2)
let width = series.length + offset
let format = (typeof cfg.format !== 'undefined') ? cfg.format : function (x) {
return (padding + x.toFixed (2)).slice (-padding.length)
}
let result = new Array (rows + 1) // empty space
for (let i = 0; i <= rows; i++) {
result[i] = new Array (width)
for (let j = 0; j < width; j++) {
result[i][j] = ' '
}
}
for (let y = min2; y <= max2; ++y) { // axis + labels
let label = format (rows > 0 ? max - (y - min2) * range / rows : y, y - min2)
result[y - min2][Math.max (offset - label.length, 0)] = label
result[y - min2][offset - 1] = (y == 0) ? '┼' : '┤'
}
let y0 = Math.round (series[0] * ratio) - min2
result[rows - y0][offset - 1] = '┼' // first value
for (let x = 0; x < series.length - 1; x++) { // plot the line
let y0 = Math.round((series[x + 0] * ratio) - min2)
let y1 = Math.round((series[x + 1] * ratio) - min2)
if (y0 == y1) {
result[rows - y0][x + offset] = '─'
} else {
result[rows - y1][x + offset] = (y0 > y1) ? '╰' : '╭'
result[rows - y0][x + offset] = (y0 > y1) ? '╮' : '╯'
let from = Math.min (y0, y1)
let to = Math.max (y0, y1)
for (let y = from + 1; y < to; y++) {
result[rows - y][x + offset] = '│'
}
}
}
return result.map (function (x) { return x.join ('') }).join ('\n')
}
}) (typeof exports === 'undefined' ? /* istanbul ignore next */ this['asciichart'] = {} : exports);
Hello guys
Great project. This is not an issue is a question. I'm interested to use renko charts. Renko is a simple chart where if value increased on a specific amounts for example +20 it will create a upper box/brick and if after it it reduce to -20 the current value then it will show the brick/box down.
I wanted to know if there is a workaround to do it using this lib or if it could be easy to modify and some suggestions for me to do it. On other canvas based chart projects it can be done using range bars. Thanks.
Check the screenshot. And ignore the bars ar the bottom edge also ignore the lines/wicks coming out the bricks.
Can i use this chart for displaying 2 lines, for comparison?
This looks like an off-by-one bug for height — can you confirm?
In [9]: print(asciichartpy.plot([0, 0, 1, 2], {'height': 1}))
2.00 ┼ ╭
0.00 ┼──╯
In [10]: print(asciichartpy.plot([0, 0, 1, 2], {'height': 2}))
2.00 ┼ ╭
1.00 ┤ ╭╯
0.00 ┼─╯
In [11]: print(asciichartpy.plot([0, 0, 1, 2], {'height': 5}))
2.00 ┼ ╭
1.60 ┤ │
1.20 ┤ │
0.80 ┤ ╭╯
0.40 ┤ │
0.00 ┼─╯
The README says:
This code is absolutely free for any usage, you just do whatever the fuck you want.
Yet since 70179e1 this doesn't seem to be true anymore.
This isn't an issue, but I wanted to let you know that I ported this library to Java. Thanks for being open source!
Python output looks terrible in a terminal, and there isn't any documentation on python support.
Also, I keep getting 0 division errors trying to plot floats.
Help?
Just to let you know, there's an Elixir port now =]
Link: https://github.com/sndnv/asciichart
I like this simple, easy to use package that I use for node statistic clis.
I'm missing some nice to have options though:
Multiple series
Ability to see more than one series on the same chart
Colors
Ability to affect colors to lines. npm's colors
may be used there
Max width
Some charts can be way larger than a terminal. Detecting the terminal length and sub-setting the series sent may be a good way to tackle this issue
I really like ascii art, so i port it to Ruby, source code at https://github.com/zhustec/ascii_chart
Wow u too good...this is very nice
Hiya,
Please add the Python port docs.
Cheers,
Jonny
Hi, just wanted to tell you that I ported this awesome library to Go.
Link: https://github.com/guptarohit/asciigraph
Question:
Is there a python method to convert the final print out to png ?
Hey!
I think it would be really awesome to be able to label the x axis. Are there any plans of supporting this?
Haxe is a ECMAScript implementation transpiled into a variety of languages including python, C++ and Java. I guess porting the lib into haxe should allow it to be used from them all.
Depending on the height set for a chart (even if the y-axis labels are exactly the same), the appropriate values are not always reached (at least when these are the max / min values; I haven't tested enough to check others yet). E.g., using the Python version, everything looks fine in this first plot:
$ pplot 1 10 --height 9
10.00 ┤╭
9.00 ┤│
8.00 ┤│
7.00 ┤│
6.00 ┤│
5.00 ┤│
4.00 ┤│
3.00 ┤│
2.00 ┤│
1.00 ┼╯
but if we change the height to 8, even though we still achieve exactly the first and last values on the y-axis, it's shown that the first point is 2 instead of 1:
$ pplot 1 10 --height 8
10.00 ┼╭
9.00 ┤│
8.00 ┤│
7.00 ┤│
6.00 ┤│
5.00 ┤│
4.00 ┤│
3.00 ┤│
2.00 ┤╯
1.00 ┼
If we increase the height, then we don't reach the max value anymore:
$ pplot 1 10 --height 10
10.00 ┤
9.18 ┤╭
8.36 ┤│
7.55 ┤│
6.73 ┤│
5.91 ┤│
5.09 ┤│
4.27 ┤│
3.45 ┤│
2.64 ┤│
1.82 ┤│
1.00 ┼╯
I didn't seem to have this problem with a previous version, but since dropping in 1.5.12 (thank you for reimplementing the user specification of characters!), I've got this issue where the graph doesn't clear adjacent rows when it shifts; see screenshot.
When the graph is at its max width and redrawing over a previous graph, it no longer clears these characters when scrolling. I looked at the commit history, and determined this bug is caused by commit e9adb0d, with the addition of the .rstrip()
call; when I edited my init.py and removed .rstrip()
the graph behaves as it used to.
Though there is a height parameter for the plotting function, this only roughly controls the height. It would be nicer to be able to exactly set the height. This is even more of an issue because the height isn't always off of the requested height by the same value, so it's not trivial to correct for this. Here are a couple of examples:
Requested height: 9; actual height: 10
$ pplot 1 10 --height 9
10.00 ┤╭
9.00 ┤│
8.00 ┤│
7.00 ┤│
6.00 ┤│
5.00 ┤│
4.00 ┤│
3.00 ┤│
2.00 ┤│
1.00 ┼╯
Requested height: 8; actual height: 10
$ pplot 1 10 --height 8
10.00 ┼╭
9.00 ┤│
8.00 ┤│
7.00 ┤│
6.00 ┤│
5.00 ┤│
4.00 ┤│
3.00 ┤│
2.00 ┤╯
1.00 ┼
The issue is with the floor
and ceil
operators that are used in computing the actual number of rows.
Here's a quick fix for this in the Python version:
target_height = cfg['height'] if 'height' in cfg else interval
actual_height = float("inf")
i = 0
while actual_height > target_height:
ratio = (target_height - i) / interval
min2 = floor(minimum * ratio)
max2 = ceil(maximum * ratio)
actual_height = max2 - min2 + 1
i += 1
assert actual_height == target_height
I just keep decreasing the height value used by 1 until the actual height matches the target height. This has always given me an actual height that's exactly the target height in the quick tests I've done, but there's probably a better way to do this. I also considered decreasing max2
or increasing min2
by 1 directly, but then we'd also need to set a new value for ratio
, at least to keep the current behavior, and I'm not sure what the appropriate way to do that would be.
characters from base ASCII table range from 0 to 127 and those from extended ASCII table are within 0 to 255.
the characters used in the project fall outside of either of the two ranges.
$ node -v
v10.2.1
$ yarn add asciichart --dev
error [email protected]: The engine "node" is incompatible with this module. Expected version ">=4 <=9".
error Found incompatible module
reproducing:
const chart = require("asciichart")
const data = [
[0, 0.1, 0.2, 0.3]
]
console.log('raw')
console.log(chart.plot(data))
console.log('turn into percents')
console.log(chart.plot(data.map(s=>s.map(v=>v*100 |0))))
hm, bit steep
suggestion/request: setting the step size (or better automatic detection)
Im testing ascii chart with some long data array and when I console.log on terminal everything get broken, it doesnt look good
[ 968, 969, 968, 967, 967, 967, 967, 966, 966, 964, 964, 966, ... 21499 more items ]
Basically it start printing a lot of lines, this screenshot its only a snapshot of the long print
The code im using is this. and the array result is the printed above.
const data = require('../data/1m/bitmex_BTCUSD_1m-15d.json');
const pricesData = data.map(tick => Math.round(tick.close));
console.log (asciichart.plot(pricesData));
It would be nice to be able to specify the maximum width of a plot as well as the height. The width is determined by both the data given and the y axis (which depends on the format string used). Though this could be handled externally, by only passing in the appropriate amount of data, I think it might be nice to do this internally so that users don't have to factor in the offset + axis when determining how much data to pass in. I think the simplest approach would be to just keep the last n
data points where n
is the largest number such that the plot isn't too wide. One could also think of trying to plot every k
th point where k
is as small as possible such that the plot isn't too wide, but that's more complicated, so I wouldn't bother unless somebody cares enough to submit a PR for it. I can go ahead and do a PR for this in Python if you're interested.
Hello,
First of all, thank you for your wonderful job. This is a very good library.
I am trying to graph a stream of data, can you help to point me in the right direction.
Thanks
for example ,I want to show cpu useage real-time,how can I do it?
madnight/bitcoin-chart-cli#9 (comment)
The y-axis only shows four digits of precision, so you can't see the tens of thousands.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.