Announcing a package I released recently, MakieExtra.jl.
It includes a bunch of new stuff for plotting that is either:
can only be implemented with some “hacks” at the current state of Makie,
or not fleshed out enough to be included into Makie itself,
or may be considered too opinionated.
Still, I believe the features in MakieExtra are generally useful and worth packaging to make them readily available for use in both scripts and other packages.
See the documentation for a list of what’s available in MakieExtra.
Below are a few highlights of visual functionality that I consider stable. There’s more – check out docs with examples! MakieExtra also has some less stable experimental functionality. I’ll probably add separate posts about it, asking for feedback.
Additionally, this is a Request For Collaboration: if you have recipes/tweaks/utilities of reasonably-general use that are unlikely to get into Makie, feel free to contribute to MakieExtra!
It’s intended to have a lower barrier for entry than Makie itself.
Examples
Automatic scalebar and zoom lines
Lines with arrows at either end
Glowing lines and text
Markers with adjustable linewidth
Symlog scale variants
Figure from SkyImages.jl docs using several MakieExtra features
It’s unexpectedly difficult to handle all edgecases btw, especially for the locator. Most of rough edges are already smoothed out during my own usage, but some may still remain.
Here’s the first post about more experimental features (:
Very often, I find myself plotting the exact same arguments with two or more recipes – either different recipes like Lines + Band, or the same recipe with different option. MakieExtra.jl provides simple multiplot() and multiplot!() functions to make this convenient. multiplot() passes its positional arguments to all requested recipes as-is, and can either pass the same or different kwargs/attributes to each recipe.
I’ve been using multiplot() recently, and found it quite convenient. It’s considered experimental for now mostly because I’m not sure whether the current interface is clean and understandable enough. The general concept of multiplot is definitely there to stay though (:
Let me know if you have any thoughts on this!
As far as I am concenred, I am happy to put all functionality from MakieForProjects.jl to another project such as MakieExtras.jl. It appears similar in their type of convenience functionalities they provide, beyond the additional themeing I have, which I can add by itself to MakieThemeing.jl (provided that MakieThemeing.jl is improved in terms of modularity for its themeing; I find the possibility of themeing Axis color, background color, and color cycle all independently to be very nice for my work).
As discussed on Zulip, it would be even more useful if some of these recipes were shipped with Makie.jl itself instead of extra packages. Otherwise it becomes difficult to ensure long-term availability and automatic loading with package extensions.
Re long-term availability: there’s no magic in including more stuff into Julia Base, Makie, or whatever, it doesn’t automatically make that stuff easier to maintain. Instead, it increases load on maintainers, and Makie is a large complex project already. Of course, if Makie devs want to upstream something from MakieExtra, they are always free to do so.
Thanks for pointing this out, I haven’t seen your MakieForProjects!
I agree with you in that whenever possible those features should go into focused packages, like MakieThemeing. Or Colors for these functions: MakieForProjects.jl/src/colormanip.jl at main · Datseris/MakieForProjects.jl · GitHub.
If there remain some Makie-specific functions that are of a general use, they could indeed be put into MakieExtra.jl.
In my view such functions are on the same level of functions like your axis zoomin. They aren’t opinionated, but are convenience tools.
Would be good if we can agree on where all such things should be. I think they should be in Makie directly. But another solution Im happy with. What I would prefer is that the final solution is in the Makie github org instead of an individual.
I think it’s easiest to include features into Base Makie that are relatively simple and can be composed well with others. A lot of convenience functions people build are somewhere above that, in the composition zone, and the problem is that this space is much larger than the basic component space.
Basically Makie gives you so many possibilities that it’s difficult to decide on “canonical” ones. So that’s why a function like axesgrid is a bit more difficult for me to integrate, it’s no doubt useful but there’s a ton of other ways to assemble axes into grids, so I ask what makes this specific one worth being integrated. If we find however that 90% of users always try to build the same thing manually, then it’d be worth using it to reduce that complexity.
@jules what do you think of the scalebar recipe above? Would it be ok to port it to Makie.jl? Displaying the true scale of physical objects in 2D and 3D is really useful (e.g., 3D digital rock models, 2D maps).
Another benefit of having things in a separate package is that it makes it easier to see how these features work / lets them evolve. It also makes it easier for the developer to work on the features instead of being stuck in a PR where it can take ages / demotivate the effort depending on how the PR goes (not that PRs taking time is bad thing, for a project like Makie it should definitely require more care / a higher barrier).
I think it is easier for those not doing the work/maintenace to suggest more work to do and go through that process, but I imagine for example it is easier for @aplavin to make this package and have the features they want in a registered package that is immediately available.
Maybe as the methods mature they could be incorporated into Makie directly but as @jules mentions in some cases it’s not obvious the best way forward anyway.
Anyway: Really nice package! The features are great.
I didn’t know indeed, thanks! This is a cleaner way to implement changes() under the hood, will switch in the next version.
Still, as the user-facing interface, changes(obs) is typically cleaner anyway. For me, a common usage of changes() looks like
all_vals = [...]
x = Observable(0.)
xi = changes(@lift findfirst(>=($x), all_vals))
... use x and xi ...
Record(...) do x_
x[] = x_
end
which doesn’t have an explicit Observable() call for xi where one could put ignore_equal_values=true.