[ANN] New package GRUtils

Hi, I would like to announce the release of version 0.1.0 of GRUtils, an experimental package that provides yet another interface to plot with GR in Julia.

Why on earth would anyone need it? - you may ask. Plots is already there: a very powerful interface that you can use with GR as back end to produce nearly any kind of plot. And if you don’t want to pay the performance overhead of using Plots, GR provides its own “matplotlib-like” interface for the most usual kinds of plots.

Well, in fact I do love how GR works on its own! I think that its balance between productivity, speed, and ease of installation and usage is excellent. Its high-level interface (coded in the module jlgr inside GR) still shows some limitations, bugs and other issues, but I consider that many can be solved with a reasonable amount of effort, which is well deserved.

In the last few months I have made some small contributions for the easiest issues, but the more I delved into the code of jlgr, the more I felt like making bigger changes. I’m aware that @jheinen also has plans for important changes in that module, although as he commented, they are more on the C-side than in the Julia-side of the package. On the other hand, I think that there is a lot of nice things that could be made with purely “Julian” features like multiple dispatch, meta-programming, etc. to improve the code, in a more accessible way for C-hopeless users (like me).

I couldn’t help the temptation of exploring that venue, and GRUtils is an experiment in that direction. If you know the code of GR you may find a big deal of copy-and-paste from jlgr, but heavily restructured. Actually GRUtils does little that GR cannot already do, and the interface for the end user is nearly the same as the one provided by jlgr. In most cases, you can use the documentation on the API of jlgr to use GRUtils as well.

The main objective of restructuring the code that way is to make it easier to read and contribute to, fixing or extending it with new functionalities. When I started this, I also fancied that GRUtils might produce even faster plots than GR; for the time being I have the impression that both packages have about the same performance (both loading and using the package, including the time to the first plot), although I have not made a systematic benchmark, and I’m sure that there is a lot of room for improvement in that regard. I hope that the structure of the package is agreeable enough to encourage other users to extend it and improve it.

I have published GRUtils as a separate package, instead of producing pull requests to GR, because this way it is faster and easier to develop and test, without disturbing the ongoing development of GR. Whether this should stay like that, or this code might be eventually integrated in GR, I don’t still know. It may even happen that GRUtils becomes obsolete when Josef’s plans for GR progress further. In the meanwhile, I hope GRUtils to be a helpful resource to improve the experience of the community in plotting with GR.

10 Likes

I tried this example and got the meshgrid error.

using GRUtils

# Create example point data
   x = 8 .* rand(100) .- 4
   y = 8 .* rand(100) .- 4
   z = sin.(x) .+ cos.(y)
   # Draw the surface plot
   surface(x, y, z)
   # Create example grid data
   X = LinRange(-2, 2, 40)
   Y = LinRange(0, pi, 20)
   x, y = meshgrid(X, Y)
   z = sin.(x) .+ cos.(y)
   # Draw the surface plot
   surface(x, y, z)
   # Draw the surface plot using a callable
   surface(x, y, (x,y) -  sin(x) + cos(y))

UndefVarError: meshgrid not defined

Stacktrace:
[1] top-level scope at In[7]:10

You are right: GRUtils does not incorporate the function meshgrid that is in jlgr, thus the example in the GR documentation does not work properly.

Not including mesghrid was a deliberate decision, since it is not strictly a graphics-related function. It is just an array manipulation operation that may come in handy for creating the data of some graphics, used in Matlab and matplotlib, although some people have argued with good reasons against it.

I’m not totally against using mesghrid (or ngrid). Efficiency aside, I acknowledge its utility, but I’m not sure if it should belong in GRUtils, or rather in another package. (E.g. it was proposed to include it in MatlabCompat.jl, although that package seems abandoned.) I have opened an issue to discuss this:

In the meanwhile, it should be mentioned that surface etc. does not need that meshgrid is used at all. For a more efficient way of making the surface plot of the example, you can try:

x = LinRange(-2, 2, 40)
y = LinRange(0, pi, 20)
z = sin.(x') .+ cos.(y)
surface(x, y, z)

(Notice that the way that X and Y axes are treated in that and other functions of GRUtils is the one I proposed in this PR to GR, but in this moment differs from the behavior of the original package:)

1 Like

Thanks

This looks nice. @oschulz also experimented with having support for a recipe system built more directly into GR.

Yes, that was more of an attempt at a new recipe system, though, with GR as the testing backend. Unfortunately I never found the time to get that off the ground, and I think the opportunity has passed by now.

Well, the macro @plotfunction included in GRUtils is much simpler than the framework for recipes provided in Plots, if you are referring to that.

Actually, stretching the metaphor a bit, I’d say that such macro it is not a system for recipes, but rather like a form to write the ingredients of a single recipe, which is followed by many commonplace plots. But with that macro you’ll never make something like the marginal histogram you can do with Plots and RecipesBase!

I’m curious anyway. Where could I find that attempt for GR recipes?

I’m afraid it’s not worth looking at. I worked on it during our plotting meeting in Berlin, but it never got a a point where it was even partially functioning.

I finally found the time to really test GRUtils - great job!!!

I started to integrate it into GR and it seems to work fine. There are only a few open questions.

6 Likes

Great. I’ll put my hands on it tomorrow evening.

Once the integration into GR is done, the GRUtils won’t be needed anymore as a separate package, so it will not require further maintenance. But since I’m following the policy of declaring upper compat bounds, this means that having GRUtils installed in the default environment will preclude further updates of GR, until GRUtils is uninstalled.

I want to avoid this, so perhaps I could create a last minimal release without dependencies, which will do nothing except showing a warning that suggests installing the new version of GR.

But before doing that, I would like to know the opinion of the Registry maintainers: is this a sensible way to deprecate an obsolete registered package?

I don’t think this is something that should be done via the registry. Also, the package should be kept around as all other registered packages. For example, imagine a project (not a package, just code for a research paper etc) that uses GRUtils for plotting. Having it in the manifest makes sure that code will work in the future, even if the package is no longer maintained or relevant.

Since it was an experimental package that is no longer needed, you could just make an announcement on this forum, and/or in a blog post, and clarify the status in the package readme.

2 Likes

Fine. Thanks for the advice.

Thanks for the great work.

One of the drawbacks of GR backend in plots is that it is very slow, and therefore making it not suitable when needed to plot hundreds of plots. Is GRUtils considerably faster than the GR backend in plots?

In general, all backends are considerably faster when they are used without the Plots.jl front end. In my opinión, GR has a very good balance between functionality and performance. GRUtils has similar performance (faster for some operations, slower for others, but the same order of magnitude).

If it fits your workflow, GRUtils is even faster when you don’t draw the plots until you really need to (e.g. while you are adding data, subplots, labels…)

1 Like

This is correct - Plots first does some processing, then passes the plot to the backend, so Plots will always be an added overhead to plotting time. Most simple plots take around 50 milliseconds, whether that is very slow is probably a question of the use case. Saving plots as pngs to file may take longer, but that shouldn’t be related to Plots.

1 Like