Hi,
Is there a recommended plotting library for nim? I found nim-plotly which is pretty nice but feels not very heavily maintained. It has a few small issues which might be fixed by a pending pull request from 2 years ago which has not been merged yet and the GitHub repo hasn’t had any activity in the last year so.
Would you recommend that I use plotly or is there a better, more active library that people use nowadays?
Thanks!
Sorry, the somewhat "unmaintained state" of plotly is partially my fault. Since I got ggplotnim into a state that works for all use cases for which I used plotly before, I have only used it infrequently. An important point on the other hand is that the existing functionality just works. The plotly API doesn't really change and the main features people seem to care about are implemented, hence little change (we could always polish, certainly!).
But if issues pop up in plotly I still pay attention and if possible try to fix them. I'm not sure what PR you're referring to. The one by Timothee? We were waiting on his input and at some point I simply forgot about it.
I'm of course biased, but ggplotnim serves me very well nowadays.
Whichever plotting library you wish to use, feel free to ping me (on Matrix / Discord) and I'll try to help. At least between the two I'd make it dependent on your use case:
Check out the (much too long nowadays...) list of example plots for ggplotnim here:
https://github.com/Vindaar/ggplotnim/blob/master/recipes.org
I use Nim for some financial computations and built visualisation library http://pl0t.com you can see some examples example notebook and its Nim sources.
It's kinda similar to Python Altair (internally it uses same Vega Plots) and in addition to plotting also supports Notebooks and Tables.
It's available not only in Nim, but in other languages too, with almost same API, so it's easy to use in multi-language project.
If you already have experience with matplotlib in python, it may be convenient to transfer the knowledge to nim via nimpy. The usage is almost the same.
As an example:
import std/[math, sequtils]
import nimpy
let xs = toSeq(1..1000).mapIt(it/10)
let ys = xs.mapIt(sin(it))
let zs = xs.mapIt(cos(it))
let plt = pyImport("matplotlib.pyplot")
let res = plt.subplots(figsize=(25,10))
let fig = res[0]
let ax1 = res[1]
discard ax1.set_title("Demo")
discard ax1.set_xlabel("x")
discard ax1.set_ylabel("y")
discard ax1.plot(xs, ys, label="sin(x)")
discard ax1.plot(xs, zs, label="cos(x)")
discard ax1.legend(loc="upper right")
discard plt.savefig("chart.png")
discard plt.close()
Thanks a lot for all the replies!
@Vindaar, yes the plotly pull request that I am referring to is the one from Timothee in which he (I think!) fixes the problem with the show function, which always reuses the x.html file. This causes frequent problems when you show multiple plots in a row.
I did try ggplotnim, but I was unable to make it work. It seems to depend on libcairo-2.dll and I did not find a simple way to install it on Windows. To be fair I did not try very hard because I found plotly and that worked on my first try. I have a strong preference for making self-contained, single file executables, and nim is usually excellent for that so that extra dependency is a minus compared to plotly. I also need interactivity, so it seems plotly is the better fit for my use case?
I was very impressed with plotly. The API is pretty simple and easy to use. I could make a plot really easily and it does not increase the size of the executable much (~500 KB in debug mode) considering the functionality it brings. I'd say that it has only 3 gaps for my use case:
@alexeypetrushin, your library sounds interesting. I'll give it a try! Since you mention a notebook, I guess it is interactive? Can you make it part of a single file nim executable?
@jackhftang, I did try nimpy recently and I also had some trouble making it work. It could not find the lib python dll. I suspect it was because I have a 32 bit python installed whereas nim complies to 64 bit? I also do not really know how you can deploy a nim program that uses nimpy. Do you need to deploy the complied executable and the python dll? Is there something else that needs to be deployed? Is there a way to make a single file executable that uses nimpy? The other problem that I suspect this will create is that the output executable plus all the dependencies will be huge as it is the case when you bundle matplotlib in a python program (e.g. with pyinstaller).
@Vindaar, yes the plotly pull request that I am referring to is the one from Timothee in which he (I think!) fixes the problem with the show function, which always reuses the x.html file. This causes frequent problems when you show multiple plots in a row.
Yeah, that's indeed an annoyance. I can take over that PR and finish it later / latest tomorrow if that helps.
I did try ggplotnim, but I was unable to make it work. It seems to depend on libcairo-2.dll and I did not find a simple way to install it on Windows. To be fair I did not try very hard
The README does indeed show a couple of ways of installing Cairo on Windows:
https://github.com/Vindaar/ggplotnim#windows
I agree that having an external dependency is not ideal. Unfortunately, a library with the functionality of Cairo is not exactly trivial to write. The closest we have in Nim is @treeform's and @guzba's great Pixie:
https://github.com/treeform/pixie
But even that cannot exactly replace Cairo (it's missing an SVG / PDF backend + a few text related features). However, a Pixie backend for ggplotnim is indeed almost ready, done by @zetashift:
https://github.com/Vindaar/ginger/pull/28
(see the second to last comment for a Pixie generated plot).
I have a strong preference for making self-contained, single file executables, and nim is usually excellent for that so that extra dependency is a minus compared to plotly.
This is a bit of a question what is meant by a "dependency". ggplotnim relies on cairo, a shared library that is ubiquitous at least on Linux and OSX. The other relies on plotly, a not exactly slim JS library. If the requirement of a browser is not a hindrance, than certainly plotly can be seen as having less dependencies.
On this note though:
ggplotnim has 2 other backends: A TikZ backend to generate pure TikZ code, i.e. to generate a native LaTeX plot. In principle this is completely independent on Cairo. On the other hand it has a Vega-Lite backend (another JS visualizaton library), which in the end provides similar functionality as plotly. At this time the Vega-Lite backend still pulls in a Cairo dependency, as it uses webview to display the plots.
I also need interactivity, so it seems plotly is the better fit for my use case?
Yeah, in that case at least it's a bit more straight forward (ggplotnim's Vega-Lite backend is still missing the required pieces to make the resulting graphs interactive).
I was very impressed with plotly. The API is pretty simple and easy to use. I could make a plot really easily and it does not increase the size of the executable much (~500 KB in debug mode) considering the functionality it brings.
Keep in mind that this is simply because the only thing nim-plotly actually does is to generate JSON. The hard work is all done via JS.
The fact that it always use a file called x.html which makes it a bit unreliable.
As mentioned above, I'll try to get this fixed soon.
The fact that there is no way to reuse / update an existing plot. I guess that is a generic problem with all browsers, but it would be nice to be able to open a window that embeds a webview in it or something like that.
There is, but thanks to plotly being a JS library this means you need to write JS to get this to work (great, huh?). It can be done, but is a bit annoying. You can find an example for such a thing here:
https://github.com/brentp/nim-plotly/blob/master/examples/fig8_js_interactive.nim
(this needs to be compiled with Nim's JS backend).
If one needs both a C backend and still interactivity, an example is here:
https://github.com/Vindaar/NeuralNetworkLiveDemo
Contains a "server" written using the C backend and a JS "client".
The fact that it does not support "linking" the X-axis of all (or some of) the subplots in a subplot group. I find that this is often what I want to do when I plot related views of the same time data. This is supported by plotly itself but not by the library.
Feel free to open an issue about this on the plotly repository with a reference to how this is done in plotly. I suppose it should be easy to add.
But even that cannot exactly replace Cairo (it's missing an SVG / PDF backend + a few text related features). However, a Pixie backend for ggplotnim is indeed almost ready, done by @zetashift:
Fantastic! I've been thinking Pixie would be awesome for plotting.
Ggplotnim sounds excellent. I look forward to giving it a go sometime.
Just to add to the mix...
I'm interested in an interactive plotting library that uses an opengl backend. There is a simple interactive plotting example done by @SSPkrolik for nimx. I fixed it up here: https://github.com/quantimnot/nimxplot
nimble install
nim r nimxplot
# should give you an example
I would love a backend for ggplotnim using one of the opengl based graphics ui/games libraries. I am willing to contribute. I'm looking at either nodesnim, paranim, or nimx. I still haven't settled on a gui library. I'm currently working on tools for building, bundling and testing such libraries on various platforms.
Updated nim-plotly PR with the aforementioned fixes is here:
https://github.com/brentp/nim-plotly/pull/72
Indeed there already was the option to override the /tmp/x.html default before. That was the purpose of the path argument (indeed the name might have been unclear). And given that the file was removed by default, not super helpful either.
@quantimnot: Indeed, a backend for some GUI toolkit would be nice. Interactive even better. We have an issue about this here:
https://github.com/Vindaar/ggplotnim/issues/126
The reason I didn't tackle it so far is mainly that the interactive part would be quite a bit of work. The static solution of just embedding a cairo surface into a SDL / ... window is rather straight forward, but also not the main use case I imagine. Help would certainly be welcome.
The thing to keep in mind is that as an interactive plotting library ggplotnim would also not be insanely fast. Even on an OpenGL backend we wouldn't suddenly be able to plot 1M data points at 60fps or something. The ginger logic is just not designed for that. For more regular plots it'd be fast enough for sure though (i.e. < 10,000 points). For point clouds and these kind of things we could add an additional GraphObject to avoid huge chunks of overhead to improve performance for this kind of stuff though. It'd always be a "depends on your usage" if performance would be good.
This is awesome @Vindaar, thank you! Looking forward to the PR being merged and available as a new version of the library.
As you requested, I've also created a new issue requesting adding support for shared X-Axes (https://github.com/brentp/nim-plotly/issues/73). In the issue description I added a link to the corresponding plotly doc page (https://plotly.com/python/subplots/#subplots-with-shared-xaxes). I hope you can find a way to add it since it would be very useful when creating subplots that share the same time axis.
Looking forward to the PR being merged and available as a new version of the library.
Just a heads up, that I've tagged a new version with the changes.
The shared axes feature should be rather simple to implement. Regarding the sugar feature, for the time being simply use scatterPlot(toSeq(0 ..< y.len), y). Almost as concise and does exactly what you want. Not sure if it's worth it to add such an extra overload. Will think about it.
Thank you @Vindaar. It works perfectly. I’ve opened a new issue because when compiling with nim 1.6.0 there is a deprecation warning.
It’s true that it’s fairly easy to provide the x sequence but it’d be nice if it weren’t necessary. It’s not super important but a lot of plotting libraries (e.g. matplotlib) make it possible to just plot a sequence.