 # Break axis in Makie

Hi, I am pretty new to Makie, but I am loving the package so far! Is it possible to have a broken y-axis in Makie? E.g. I want to plot:

``````xs1 = randn(10)
ys1 = randn(10)

xs2 = randn(10) .+ 3
ys2 = randn(10) .+ 10

fig = Figure()
ax = fig[1,1] = Axis(fig)
scatter!(ax, xs1, ys1)
scatter!(ax, xs2, ys2)
fig
``````

without resorting to a log scale and have the clusters on the same height. Any help would be much appreciated!

So I asked about this on the Makie Slack channel and apparently this is not implemented yet. However, Julius Krumbiegel suggested I try the following to manually implement what I want:

possible manually, yes, but there’s no premade function for it. you would currently have to make two axes, plot the same thing in them, set limits how you want, hide the adjacent spines so it looks like one axis, then the only “tricky” thing is adding diagonal lines at the spine ends. this is best made dependent on the axis position, so that it stays correct

you can grab the ends of the spines from the lineaxis objects in `ax.elements` , they have an attribute called `endpoints` . grab the correct points and calculate your diagonals in figure space, then plot the lines into `figure.scene`

For anyone else who needs to implement this manually, here is the code. This does everything except add that “broken” y axis. I could not manage to implement those diagonal “broken axis indicator” lines. However, if you are in a pinch for time, just add them manually using Inkscape If anyone figures out how to add them, please reply to this topic.

``````using CairoMakie

xs1 = randn(10)
ys1 = randn(10)

xs2 = randn(10) .+ 3
ys2 = randn(10) .+ 10

fig = Figure();
ax1 = fig[1,1] = Axis(fig)
scatter!(ax1, [xs1; xs2], [ys1; ys2])
hidexdecorations!(ax1)
hideydecorations!(ax1, ticklabels=false)
ylims!(ax1, 8.5, 11.0)
ax1.yticks = 9:1:11

ax2 = fig[2,1] = Axis(fig)
scatter!(ax2, [xs1; xs2], [ys1; ys2])
hideydecorations!(ax2, ticklabels=false)
hidexdecorations!(ax2, ticklabels=false)
ylims!(ax2, 0.0, 2.5)
ax2.yticks = 0:1:2

rowsize!(fig.layout, 2, Relative(2/3))
rowgap!(fig.layout, 1, Relative(0.0))
ax2.topspinevisible=false
ax1.bottomspinevisible=false

Label(fig[:, 0], "Manually broken y", rotation=pi/2)

fig
``````

@Elmo, you could draw a horizontal grey line where the axis is broken, with an annotation of the gap used. E.g., `y = (2.5, 8.5)`

it looks like your y-scale changes, say 0-1 versus 10-11, is that desired?

Yes, so the type of figure I was going for looks like this:

Do you mean a horizontal line spanning the entire figure? If so, yes that would be a programmatic way of indicating where it breaks, however it would not look as pretty as e.g. the matplotlib version (see here)

I mean that the distance between 0 and 1 and between 10 and 11, along the y axis, does not look the same. The distance between 0 and 1 looks bigger. The image you showed with the squiggly broken axis has the same metric near 0 and near 1. Some problem when creating your figure maybe?

Ah, now I see what you mean. Nope, that is not desired, but I suppose it could be fixed by just setting the y limits and the y ticks of both figures?

You could fix the relative scaling by giving both rows an `Auto(ratio)` size where ratio is the relative length of each axis. For the diagonal lines, you just need to do `linesegments!(fig.scene, diagonal_points)`. The points you have to calculate given the endpoints of the axis lines, an angle that you like, and a line length that you like. You should calculate the points using `lift(endpoints) do points...` etc so that they update whenever the axis shifts.

2 Likes