Vindaar / ggplotnim

A port of ggplot2 for Nim
https://vindaar.github.io/ggplotnim
MIT License
177 stars 15 forks source link

Basic guidance on implementing new backend #148

Open curioussavage opened 2 years ago

curioussavage commented 2 years ago

Hi!

I've been looking through this codebase and the ginger lib trying to figure out how to write a new backend. It appears that I would need to fork ginger to do so but I'm not totally sure. I'm coming back to nim after a long break so still getting used to the language again.

I'm just hoping to get some high level guidance on what a new backend would require.

Vindaar commented 2 years ago

Hey!

Happy to hear there's interest in that! Indeed, this is technically more of a ginger issue / question, but it doesn't matter, as the use case is ggplotnim anyway.

On the ggplotnim side there isn't really much to do, indeed. The backend needs to be told to the ginger types in a few places , but this is either done via the backend argument in the ggplot procedure by the user when calling it: https://github.com/Vindaar/ggplotnim/blob/master/src/ggplotnim.nim#L257 or automatically (the default) by calling the toBackend procedure from ginger here: https://github.com/Vindaar/ggplotnim/blob/master/src/ggplotnim.nim#L3002 (based on the file type and some defaults chosen in ginger.

So, on the ginger side there is indeed a bit to do, but it's not actually all that much (well, technically it depends on how much work it is to implement the required primitives in the backend, but well).

Starting from adding a new BackendKind in the enum here: https://github.com/Vindaar/ginger/blob/master/src/ginger/types.nim#L30

After that, "all" that needs to be done is write a backendFoo.nim file similar to the backendCairo/Dummy/TikZ files. The backendDummy gives a good idea of what is required. These procedures to draw primitives need to be implemented: https://github.com/Vindaar/ginger/blob/master/src/ginger/backendDummy.nim#L6-L51 That means essentially 7 different basic primitives (text, rectangle, circle, line, multi line, extend of text on the backend, drawing a raster). Of course in theory if the backend is not suitable for any of these, in principle it can just not support any of them (which will result in certain plots not working correctly of course).

Once that is done, one simply needs to wrap that new backend in backends.nim here: https://github.com/Vindaar/ginger/blob/master/src/ginger/backends.nim by extending every case in each of the wrapper procedures of the primitive procedures. Note that every backend is imported as from X import nil to avoid ambiguous overload resolution problems, as of course the signature of every procedure in each backend is exactly the same.

Taking a look at how the implementation of the default Cairo backend is done for each of these procedures and to a lesser extent for the TikZ backend should give a good idea. Also, there is a (still open, sorry :( ) PR to add a pixie backend here: https://github.com/Vindaar/ginger/pull/28

Unfortunately, mainly because of lacking good font handling (in terms of finding fonts on the user's system etc.) in pixie the PR has been taking a long time (and also me often not responding quickly enough, I admit).

I hope this is enough to get you started. If you have further questions, just shoot. Also feel free to jump onto matrix / discord and ping me in the #science channel if you want more immediate feedback!

curioussavage commented 2 years ago

This is super helpful. Thank you!

I was able to get a small start but this will help me make some actual progress. I'll jump on matrix if I get stuck