How customizable is Makie?

Since the announcement of the new makie website popped up on Slack and HN: Makie starts looking more and more polished, to the point where I’m considering giving it a serious try for publications.

Until now, I’m using matplotlib for pub-ready figures (and Plots.jl for day-to-day exploratory visualization in Jupyter notebooks). So far, I’ve found matplotlib to be the only plotting system that provides the kind of extreme customization that I need for most of the plots that I’d put in a publication, and I wonder to what extent Makie has comparable capabilities yet.

These would be recent examples of the kind of figures I’m talking about:

Fig1:

Fig 2:

Fig 3:

Some of the customizations in these are:

  • absolute figure width and the ability to place all axes at specific positions and sizes to align them with other axes or even axes in other figures
  • Matching the exact font and font size of the LaTeX document where these figures will be embedded
  • LaTeX math (subscript/superscripts, properly formatted log-scale labels)
  • Place text annotation at arbitrary positions in “mixed coordinates”, e.g., “left baseline” should be 2pt left and 3pt above the data point with x=x₀ and at 0.5 of the height of the axes.
  • arrows to/from arbitrary points, with customizable arrowheads and padding, specified in arbitrary “mixed coordinates”
  • Specify an arbitrary bounding box for any text labels with custom shape (rounded corners), background color, padding, transparency
  • Choose which spines are shown for any given axes
  • Control the position/padding of axis labels in absolute pt
  • Place legends for any subset of lines at arbitrary absolute positions
  • Match the color of text labels to a particular line
  • Place colorbars at arbitrary absolute positions with absolute width/height
  • Manually choose all major and minor ticks and their tick labels
  • Control the zorder of any element in the plot
  • For every line, choose whether it should clip or not clip to the axes
  • Rasterize a plot while keeping the axes/annotations as vector graphics
  • Modify e.g. the background color or alignment of just one particular tick mark
  • Place insets at arbitrary positions and indicate the inset origin
  • Unusual axes like a polar plot, with the ability to place annotations/arrows in polar coordinates

There’s probably more. Ultimately, I find that matplotlib allows me to customize pretty much every aspect of any line, patch, or letter that appears anywhere in the figure (although I admit that the process is rather laborious and time-consuming, and I only do this for publication figures).

How close is Makie to being able to handle these and similar customization needs?

2 Likes

absolute figure width and the ability to place all axes at specific positions and sizes to align them with other axes or even axes in other figures

Yes definitely.

Matching the exact font and font size of the LaTeX document where these figures will be embedded
LaTeX math (subscript/superscripts, properly formatted log-scale labels)

You can use any font you like in any size you like, so yes. LaTeX math is MathTeXEngine.jl based, so it’s not real LaTeX but close enough for the most common scenarios. There are attempts to include real, arbitrary latex in CairoMakie figures GitHub - JuliaPlots/MakieTeX.jl: TeX integration in Makie

Place text annotation at arbitrary positions in “mixed coordinates”, e.g., “left baseline” should be 2pt left and 3pt above the data point with x=x₀ and at 0.5 of the height of the axes.

In principle yes, although mixed coordinate spaces currently require some manual projection work and should be simplified.

arrows to/from arbitrary points, with customizable arrowheads and padding, specified in arbitrary “mixed coordinates”

I still want to add more convenient annotation arrows. In principle already possible. I did this with brackets recently, you don’t want to use arrows! as it’s meant for vector fields.

Specify an arbitrary bounding box for any text labels with custom shape (rounded corners), background color, padding, transparency

backgrounds with rounded corners for text are still missing. I know it’s a thing people like to do, it’s just a bit annoying to implement nicely. You can already plot a rounded-rect poly behind text, using the text’s boundingbox, just not with a convenience method.

Choose which spines are shown for any given axes

Yes

Control the position/padding of axis labels in absolute pt

Yes

Place legends for any subset of lines at arbitrary absolute positions

Yes

Match the color of text labels to a particular line

Yes

Place colorbars at arbitrary absolute positions with absolute width/height

Yes

Manually choose all major and minor ticks and their tick labels

Yes, although minor ticks have no labels (that’s why they’re minor in my opinion :slight_smile: )

Control the zorder of any element in the plot

In CairoMakie, drawing order looks at z translation, so it’s kind of true that you can control it. It’s just that the output in GLMakie might differ a bit as it has real z-buffering, and we usually consider it the ground truth because of that. For practical purposes, yeah you can shift stuff back and forth as needed.

For every line, choose whether it should clip or not clip to the axes

No, currently everything clips at the scene rectangle boundary. There are plans to add this (polar plots!), complicated by the fact it needs to work in GLMakie (clipping paths in Cairo are easy).

Rasterize a plot while keeping the axes/annotations as vector graphics

Yes

Modify e.g. the background color or alignment of just one particular tick mark

Yes

Place insets at arbitrary positions and indicate the inset origin

Yes but needs more convenience which I’ve already written for users asking questions, but never PRed in.

Unusual axes like a polar plot, with the ability to place annotations/arrows in polar coordinates

Not yet, there’s a PR adding polar axis, but it needs some more work. Also, how you render data with nonlinear transformations is a bit complex (for example do you curve lines between points or not) and this would need more time to make good decisions.

15 Likes

I couldn’t find something that matches this on MATLAB:

mI = imread('https://i.imgur.com/gx7rrPS.png');
numRows = size(mI, 1);
numCols = size(mI, 2);

marginSize = 50;

hF = figure('Position', [50, 50, numCols + 2 * marginSize, numRows + 2 * marginSize]); %<! Position in pixels
%  Creating axes with the size of the image (Inner space) Margins of `marginSize` pixels in each direction
hA = axes(hF, 'Units', 'pixels', 'Position', [marginSize, marginSize, numCols, numRows]); %<! Drawing axes inside the figure
image(hA, repmat(mI, 1, 1, 3)); %<! Displayed within the axes

With the above I get 1:1 mapping between the matrix elements and the displayed data.

How can it be done in Makie.jl?
I could find how to define the figure but not the axis (Inner) to draw on.

Either by using the bbox argument

f = Figure(resolution = (450, 450))
ax = Axis(f, bbox = Rect2i((25, 25), (400, 400)))
image!(ax, rand(400, 400))
f

Of course the decorations clip with this setting, I guess you’d hide them. So in that case you could also go bare-bones and directly plot the image to a Scene with pixel-camera. The Figure happens to have one so we can also do:

f = Figure(resolution = (450, 450))
image!(f.scene, 25..425, 25..425, rand(400, 400))
f

Or you use the padding option of the Figure layout, set that to 25, then let the Axis fill the available space without decorations. That has the same result:

f = Figure(resolution = (450, 450), figure_padding = 25)
ax = Axis(f[1, 1])
hidedecorations!(ax)
hidespines!(ax)
image!(ax, rand(400, 400))
f

2 Likes

Thanks! That’s really great, and more than I was expecting! It definitely puts Makie high on the list of things to explore when I have some time…

mixed coordinate spaces currently require some manual projection work and should be simplified.

I don’t mind writing some helper functions, so as long as it’s possible, I’d count that as a yes!

backgrounds with rounded corners for text are still missing. I know it’s a thing people like to do, it’s just a bit annoying to implement nicely. You can already plot a rounded-rect poly behind text, using the text’s boundingbox, just not with a convenience method.

Mostly I use this to make labels/tickmarks more readable when they’re on top of plotted data, e.g., the “R” in Fig 2(b). The rounded corners are just a little more aesthetically pleasing. On the other hand, defining these with matplotlib is also extremely verbose, so having to write a helper function isn’t the end of the world.

Currently everything clips at the scene rectangle boundary.

This seems like the only limitation that could potentially be a show-stopper. For data, especially for something like a “Tufte-style” plot where the limits of the axes are exactly the range of the data, but the spines are moved out a bit, clipping can lead to a very weird look. For example, in Fig 2 (c), the initial part of the plot (up to r ≈ 15μm) would have the line width cut in half with clipping, which would look odd. On the other hand, in the inset of Fig 2 (c), I would want the clipping, as it indicates that the blue curve exactly goes to zero in the middle.

Also, I frequently have annotations that extend to the outside of the axes, and thus I routinely have to pass the keyword argument to matplotlib to disable “clipping” these (where “clipping” in this case tends to be “don’t show up at all”).

So, I hope that you can add an option to switch clipping on or off for any particular element.

Not yet, there’s a PR adding polar axis, but it needs some more work.

Ok, this still has plenty of rough edges even in matplotlib.

Ah that one I’d usually do by using the trimspine attributes, then you don’t have to do it via clipping (but clipping control is still useful for other things of course)

f, ax, l = lines(0..10, sin; axis = (; xtrimspine = true, ytrimspine = true,
    xgridvisible = false, ygridvisible = false, xtickalign = 0.5, ytickalign = 0.5))
hidespines!(ax, :t, :r)
f

2 Likes

Can you elaborate on how this is done? I normaly write some helper function to reduce the number of plot points in a given axis to avoid vector graphics of several megabytes. Partial rasterizing would be great for that!

https://docs.makie.org/stable/documentation/backends/cairomakie/index.html#selective_rasterization

2 Likes

Could you explain the closed interval?
I’d expect them to be 25..424?
Also, how come the image is 90 [Deg] rotated?

I looked at Scene and image!() in the documentation and could not find an explanation.

Update: Could it be as the canvas is continuous?

Thank you for helping me out as well, you saved my day :slight_smile: