Is there a standard way of building packages with graphical extension

Hi. I often bump into the following problem, related to graphics libraries. I have worked with Matlab for more than 20 years, so I had my habits (I nearly stopped since I adopted Julia, and have been all the more happy). The way figures are built in Matlab is imperative programming style, similar to what is done in matplotlib.

I have tested several graphics backends for Julia (Plots, Plotly, Makie, Gadfly), and I have settled with Makie (Cairo mainly, GL when I have to). I am very happy with it, but it cost me a bit to be fluent with Makie’s style (Figures, Axes, etc.). I could be using every graphics backend for some time every week so as to stay alert with each of them, but it’s too much of a workload. I stick with Makie, I can make beautiful (so I find) figures, and be efficient.

When I use a package for a computation in a given field (statistics, graphs, agent modelling, etc.), there usually are functions to plot the data types from the package. And there is a preferred backend: Plots, Makie, Matplotlib, Plotly, etc. It may take me some time to properly get to display the figures of interest using a different backend than my favorite (which is a subjective choice).

I reckon it would be interesting to put any graphics related functions/code in packages extensions only. For example, it would allow to extend the use of packages for other backends through Pull Requests and extensions. And it would make packages somewhat more generic… But maybe I am too rigid with my coding habits…

An other way would be going generic in some way, for example by defining generic recipes that can be implemented for every backend.

Is this a problem shared by some of you ? Or am I the only one complaining about that ?

I believe this is the current status quo in most packages. Perhaps you need to open issues in specific packages that you are currently using?

I think everyone using software has this problem. Libraries only support what their developers implemented, and it just takes work to add capability.

If you’re talking about the Pkg feature of package extensions, then it’s not a critical factor. Extensions add methods that mix names from its trigger packages, and the naive multimethod approach to distinguishing backend packages is to dispatch on a dedicated argument type mapped to the backend packages. A name related to such a type would need to be provided by the backend package for us to access; luckily dispatching on Val{module} is a feature.

Makie doesn’t put its backends in extensions, but in dependent packages of the same repository to import by name (import statements can’t name extensions, only packages), and calling an activate! function specifically changes Makie’s choice of backend package. Plots, or rather PlotsBase, does use extensions with backend plotting packages in separate repositories, and it also uses function calls to switch backends. If a library needs to plot but can’t reuse one of these backend-selecting plotting libraries, then it would need to implement its own complicated backend system, which is probably why it’s not that common.

One solution to this problem is plot recipes, which Makie supports (see Recipes | Makie). If you write recipes for the packages you use, then you could continue to use Makie and not depend on the (Plots.jl) recipes provided by each individual package.

I think that, at least in some cases, it makes sense to put recipes in separate packages. For example, I want to use Gaston for plotting, and I want to plot types from DSP. Since DSP is not likely to accept a dependency on GastonRecipes, I put together a separate package, GastonDSP with the recipes I need. If your recipes are likely to be of use only to you and a few other people, you don’t even have to register them.

Writing your own recipes can be a bit of extra work, but if you only need to plot a few types, it should not be too cumbersome.