# Break axis in Makie

**URL:** <https://discourse.julialang.org/t/break-axis-in-makie/62729>\
**Category:** Visualization\
**Tags:** question, makie\
**Created:** [June 11, 2021, 10:56am UTC](https://discourse.julialang.org/t/break-axis-in-makie/62729 "2021-06-11T10:56:23Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![Elmo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elmo/32/17979_2.png) [@Elmo](https://discourse.julialang.org/u/Elmo)\
**Post date:** [June 11, 2021, 10:56am UTC](https://discourse.julialang.org/t/break-axis-in-makie/62729/1 "2021-06-11T10:56:23Z")

</div>

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:

```julia
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!

---

<div class="post-metadata">

**Author:** ![Elmo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elmo/32/17979_2.png) [@Elmo](https://discourse.julialang.org/u/Elmo)\
**Post date:** [June 12, 2021, 7:56am UTC](https://discourse.julialang.org/t/break-axis-in-makie/62729/2 "2021-06-12T07:56:47Z")

</div>

So I [asked about this](https://julialang.slack.com/archives/C8RQUU2KH/p1623423101370600) on the Makie Slack channel and apparently this is not implemented yet. However, [Julius Krumbiegel](https://julialang.slack.com/team/UK1BNFHFV) 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.

```julia
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

```

 ![man_y_break](https://global.discourse-cdn.com/julialang/original/3X/0/f/0fc7b6f1658270c30227130f97721af001cc6920.png)

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [June 12, 2021, 8:41am UTC](https://discourse.julialang.org/t/break-axis-in-makie/62729/3 "2021-06-12T08:41:13Z")

</div>

@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)`

---

<div class="post-metadata">

**Author:** ![ptoche](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ptoche/32/23554_2.png) [@ptoche](https://discourse.julialang.org/u/ptoche)\
**Post date:** [June 12, 2021, 8:49am UTC](https://discourse.julialang.org/t/break-axis-in-makie/62729/4 "2021-06-12T08:49:18Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Elmo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elmo/32/17979_2.png) [@Elmo](https://discourse.julialang.org/u/Elmo)\
**Post date:** [June 12, 2021, 9:01am UTC](https://discourse.julialang.org/t/break-axis-in-makie/62729/5 "2021-06-12T09:01:37Z")

</div>

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

 ![Untitled](https://global.discourse-cdn.com/julialang/original/3X/0/4/044a2e2136241755217fd39502d35d23b3849729.png)

---

<div class="post-metadata">

**Author:** ![Elmo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elmo/32/17979_2.png) [@Elmo](https://discourse.julialang.org/u/Elmo)\
**Post date:** [June 12, 2021, 9:03am UTC](https://discourse.julialang.org/t/break-axis-in-makie/62729/6 "2021-06-12T09:03:44Z")

</div>

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](https://discourse.julialang.org/t/break-axis-in-makie/62729/5))

---

<div class="post-metadata">

**Author:** ![ptoche](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ptoche/32/23554_2.png) [@ptoche](https://discourse.julialang.org/u/ptoche)\
**Post date:** [June 12, 2021, 9:06am UTC](https://discourse.julialang.org/t/break-axis-in-makie/62729/7 "2021-06-12T09:06:33Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![Elmo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elmo/32/17979_2.png) [@Elmo](https://discourse.julialang.org/u/Elmo)\
**Post date:** [June 12, 2021, 9:08am UTC](https://discourse.julialang.org/t/break-axis-in-makie/62729/8 "2021-06-12T09:08:49Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [June 12, 2021, 9:49am UTC](https://discourse.julialang.org/t/break-axis-in-makie/62729/9 "2021-06-12T09:49:23Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [June 15, 2021, 2:22pm UTC](https://discourse.julialang.org/t/break-axis-in-makie/62729/10 "2021-06-15T14:22:56Z")

</div>

Here’s a possible implementation, although it uses some rather internal things:

 ![grafik](https://global.discourse-cdn.com/julialang/original/3X/3/d/3dd9fee5d9f01984a78dedf7087ca67a3ce25a83.png)

```julia
f = Figure()

lims = Node(((0.0, 1.3), (7.6, 10.0)))

g = f[1, 1] = GridLayout()

ax_top = Axis(f[1, 1][1, 1], title = "Broken Y-Axis")
ax_bottom = Axis(f[1, 1][2, 1])

on(lims) do (bottom, top)
    ylims!(ax_bottom, bottom)
    ylims!(ax_top, top)
    rowsize!(g, 1, Auto(top[2] - top[1]))
    rowsize!(g, 2, Auto(bottom[2] - bottom[1]))
end

hidexdecorations!(ax_top, grid = false)
ax_top.bottomspinevisible = false
ax_bottom.topspinevisible = false

linkxaxes!(ax_top, ax_bottom)
rowgap!(g, 10)

angle = pi/8
linelength = 30

segments = lift(
        @lift($(ax_top.elements[:yaxis].attributes.endpoints)[1]),
        @lift($(ax_bottom.elements[:yaxis].attributes.endpoints)[2]),
        @lift($(ax_top.elements[:yoppositeline][1])[1]),
        @lift($(ax_bottom.elements[:yoppositeline][1])[2]),
    ) do p1, p2, p3, p4
    ps = Point2f0[p1, p2, p3, p4]

    map(ps) do p
        a = p + Point2f0(cos(angle), sin(angle)) * 0.5 * linelength
        b = p - Point2f0(cos(angle), sin(angle)) * 0.5 * linelength
        (a, b)
    end
end

linesegments!(f.scene, segments)

scatter!(ax_top, randn(100, 2) .* 0.5 .+ 9)
scatter!(ax_bottom, randn(100, 2) .* 0.2 .+ 0.25)

notify(lims)

f

```

---

<div class="post-metadata">

**Author:** ![L\_Adam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/l_adam/32/12086_2.png) [@L\_Adam](https://discourse.julialang.org/u/L_Adam)\
**Post date:** [June 15, 2021, 2:58pm UTC](https://discourse.julialang.org/t/break-axis-in-makie/62729/11 "2021-06-15T14:58:54Z")

</div>

1. rescale data such that they fit into the same coordinate system.
2. plot as you would
3. re-annotate y-ticks

In your example, you have two chunks of data, share same x, but different ys, one from [0, 0.25], and one from [0.75, 1]. To set up common coordinate system, from [0, 0.5], where [0, 0.25] map to [0, 0.25], and [0.75, 1] map to [0.25, 0.5], this should be one simple broadcast. If you need log-scale, just do it.

i dont really know how to do the “//”, but given it serves as attention grabbing marker, you could just plot some shaded region, depends on the determined coordinate system

---

<div class="post-metadata">

**Author:** ![filchristou](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/filchristou/32/26760_2.png) [@filchristou](https://discourse.julialang.org/u/filchristou)\
**Post date:** [March 19, 2022, 3:00pm UTC](https://discourse.julialang.org/t/break-axis-in-makie/62729/12 "2022-03-19T15:00:40Z")

</div>

are there plans to have an API for such use cases ?

---

<div class="post-metadata">

**Author:** ![filchristou](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/filchristou/32/26760_2.png) [@filchristou](https://discourse.julialang.org/u/filchristou)\
**Post date:** [December 8, 2022, 7:33pm UTC](https://discourse.julialang.org/t/break-axis-in-makie/62729/13 "2022-12-08T19:33:19Z")

</div>

This no longer works. Particularly I cannot access `yoppositeline` in the current version. Is there an alternative ?

---

<div class="post-metadata">

**Author:** ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)\
**Post date:** [January 6, 2023, 9:30am UTC](https://discourse.julialang.org/t/break-axis-in-makie/62729/14 "2023-01-06T09:30:32Z")

</div>

This works for me in Makie 0.19.1:

```julia
f = Figure()

lims = Observable(((0.0, 1.3), (7.6, 10.0)))

g = f[1, 1] = GridLayout()

ax_top = Axis(f[1, 1][1, 1], title = "Broken Y-Axis")
ax_bottom = Axis(f[1, 1][2, 1])

on(lims) do (bottom, top)
    ylims!(ax_bottom, bottom)
    ylims!(ax_top, top)
    rowsize!(g, 1, Auto(top[2] - top[1]))
    rowsize!(g, 2, Auto(bottom[2] - bottom[1]))
end

hidexdecorations!(ax_top, grid = false)
ax_top.bottomspinevisible = false
ax_bottom.topspinevisible = false

linkxaxes!(ax_top, ax_bottom)
rowgap!(g, 10)

angle = pi/8
linelength = 30

segments = lift(
        @lift($(ax_top.yaxis.attributes.endpoints)[1]),
        @lift($(ax_bottom.yaxis.attributes.endpoints)[2]),
        @lift($(ax_top.elements[:yoppositeline][1])[1]),
        @lift($(ax_bottom.elements[:yoppositeline][1])[2]),
    ) do p1, p2, p3, p4
    ps = Point2f[p1, p2, p3, p4]
    
    map(ps) do p
        a = p + Point2f(cos(angle), sin(angle)) * 0.5 * linelength
        b = p - Point2f(cos(angle), sin(angle)) * 0.5 * linelength
        (a, b)
    end
end

linesegments!(f.scene, segments)

scatter!(ax_top, randn(100, 2) .* 0.5 .+ 9)
scatter!(ax_bottom, randn(100, 2) .* 0.2 .+ 0.25)

notify(lims)

f

```

---

<div class="post-metadata">

**Author:** ![e3c6](https://avatars.discourse-cdn.com/v4/letter/e/e79b87/32.png) [@e3c6](https://discourse.julialang.org/u/e3c6)\
**Post date:** [March 23, 2026, 5:46pm UTC](https://discourse.julialang.org/t/break-axis-in-makie/62729/15 "2026-03-23T17:46:32Z")

</div>

Sorry to revive an old topic. But I was wondering if there was an updated API for this , or if the accepted solution here is still the best way to achieve this. Thanks
