# Rotating Plots in Makie

**URL:** <https://discourse.julialang.org/t/rotating-plots-in-makie/72017>\
**Category:** Visualization\
**Tags:** plotting, makie\
**Created:** [November 24, 2021, 5:08pm UTC](https://discourse.julialang.org/t/rotating-plots-in-makie/72017 "2021-11-24T17:08:29Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![davibarreira](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/davibarreira/32/20270_2.png) [@davibarreira](https://discourse.julialang.org/u/davibarreira)\
**Post date:** [November 24, 2021, 5:08pm UTC](https://discourse.julialang.org/t/rotating-plots-in-makie/72017/1 "2021-11-24T17:08:29Z")

</div>

I’m interested in understanding how one can rotate a whole axis/plot in Makie, in order to produce visualizations like the one below.

 ![image](https://global.discourse-cdn.com/julialang/original/3X/c/2/c2b563207b492012fbdbac26e76c74ef958fafe6.png)

This solution was posted by Simon Danisch on Slack:

```julia
using GLMakie

f, ax, pl = barplot(rand(5), bar_labels=:y, figure=(resolution=(500, 500),))
hideydecorations!(ax)
hidespines!(ax, :t, :r, :l)
hidexdecorations!(ax, ticks=false)
tightlimits!(ax)
f
img = Makie.colorbuffer(ax.scene)

f, ax, pl = scatter(rand(Point2f, 100), axis=(aspect = DataAspect(),))
impl = image!(ax, 0..1, 0..1, rotr90(img))
display(f)

rotate!(impl, -0.25pi)
translate!(impl, 0.5, 1.2, 0)
xlims!(ax, 0, 2)
ylims!(ax, 0, 2)

```

Although it’s a great solution, I’v got some problems with it. First of all, it does not seem to work with `CairoMakie`. Secondly, I’d like for the visualization to be fully `svg`, which I’m guessing would not be the case here, since `img = Makie.colorbuffer(ax.scene)` would rasterize the original scene.

Following the Julia Data Science book by @lazarusA , I tried the following:

```julia
function add_box_inset(fig; left=100, right=250, bottom=200, top=300,
bgcolor=:grey90)
 inset_box = Axis(fig, bbox=BBox(left, right, bottom, top),
 xticklabelsize=12, yticklabelsize=12, backgroundcolor=bgcolor)

 # bring content upfront

 translate!(inset_box.scene, 0, 0, 10)
 qx = qrotation(Vec(1, 0, 0), pi / 4)
 rotate!(inset_box.scene,qr)

 elements = keys(inset_box.elements)
 filtered = filter(ele -> ele != :xaxis && ele != :yaxis, elements)
 foreach(ele -> translate!(inset_box.elements[ele], 0, 0, 9), filtered)
 return inset_box
end

```

But with no success. Any ideas?

---

<div class="post-metadata">

**Author:** ![ffreyer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffreyer/32/21569_2.png) [@ffreyer](https://discourse.julialang.org/u/ffreyer)\
**Post date:** [November 24, 2021, 5:58pm UTC](https://discourse.julialang.org/t/rotating-plots-in-makie/72017/2 "2021-11-24T17:58:39Z")

</div>

The reason why just rotating `ax.scene` doesn’t work is because Axis has a lot of screen space components that are in `fig.scene`. If you look at `ax.scene.plots` you’ll see that the only plot you didn’t add yourself is a mesh plot. This is the (by default white) background. Everything else is in `fig.scene.plots` - the box outline, ticks, text, labels, etc. The problem is that “everything else” includes every other Axis as well.  
I played around with Axis a bit and it turns out you can call it with a scene as well. So what you can do is add a pixel-space proxy scene and base your rotated Axis off of that. Then you can rotate and translate the proxy scene and `ax.scene` to get your rotated inset axis:

```julia
fig = Figure()
b = Axis(fig[1, 1])
scene = Scene(fig.scene)
campixel!(scene)
ax = Axis(scene, bbox = MakieLayout.BBox(-100, 100, -100, 100))

for s in (scene, ax.scene)
    Makie.rotate!(s, Vec3f(0,0,1), -pi/4)
    translate!(s, Vec3f(300, 300, 100))
end
fig

```

This works for me in GLMakie but CairoMakie still has two problems - text gets transformed differently and disappears, and the background pane of the rotated axis doesn’t draw over the normal axis. I think these are things that need to fixed in CairoMakie though.

---

<div class="post-metadata">

**Author:** ![davibarreira](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/davibarreira/32/20270_2.png) [@davibarreira](https://discourse.julialang.org/u/davibarreira)\
**Post date:** [November 25, 2021, 12:41am UTC](https://discourse.julialang.org/t/rotating-plots-in-makie/72017/3 "2021-11-25T00:41:30Z")

</div>

Thanks a lot. Very nice solution. I just wish CairoMakie worked 😢

---

<div class="post-metadata">

**Author:** ![davibarreira](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/davibarreira/32/20270_2.png) [@davibarreira](https://discourse.julialang.org/u/davibarreira)\
**Post date:** [November 25, 2021, 1:26am UTC](https://discourse.julialang.org/t/rotating-plots-in-makie/72017/4 "2021-11-25T01:26:31Z")

</div>

@ffreyer , I’ve tried adding a scatter plot to the rotated axis, but it did not work with your example. The plot is not translated and not rotated. Any idea on what might be going on?

```julia
fig = Figure()
b = Axis(fig[1, 1])
scene = Scene(fig.scene)
campixel!(scene)
ax = Axis(scene, bbox = MakieLayout.BBox(-100, 100, -100, 100))
scatter!(ax, rand(10,2))

for s in (scene, ax.scene)
    Makie.rotate!(s, Vec3f(0,0,1), -pi/4)
    translate!(s, Vec3f(300, 300, 100))
end
fig

```

---

<div class="post-metadata">

**Author:** ![ffreyer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffreyer/32/21569_2.png) [@ffreyer](https://discourse.julialang.org/u/ffreyer)\
**Post date:** [November 25, 2021, 1:13pm UTC](https://discourse.julialang.org/t/rotating-plots-in-makie/72017/5 "2021-11-25T13:13:27Z")

</div>

Alright, I’ve tried a bit more. Some issues that the previous solution had were:

1. Applying transformation to a scene doesn’t actually transform the scene - it transforms the plots inside the scene. With the `Axis` call we create one in the bottom left corner and it’s still there after the transformations are applied.
2. Transformations are passed down to child scenes and plots and apply to whatever space that scene or plot is in. So translating `scene` by 200 pixels also means translating `ax.scene` by 200 _data units_.

The first one can be solved by explicitly replacing `ax.scene.px_area` (if we only adjust it we mess with some other Axis internals) and the second by transforming plots individually. My (fragile) solution is now:

```julia

fig = Figure()
b = Axis(fig[1, 1])
scene = Scene(fig.scene)
campixel!(scene)
bbox = MakieLayout.BBox(-100, 100, -100, 100)
ax = Axis(scene, bbox = bbox)
p = scatter!(ax, 1:5, [0, 1, 2, 1, 0])

# Make axis scene visible:
#scene.plots[1].visible[] = false # axis background off
#ax.scene.clear = true # clear to background color
#ax.scene.backgroundcolor[] = RGBAf(0.9, 0.9, 0.5, 1);

# Transform decorations
ϕ = -pi/4
v = Vec3f(300, 300, 0)
for p in scene.plots
    Makie.rotate!(p, Vec3f(0,0,1), ϕ)
    translate!(p, v)
end
translate!(scene, 0, 0, 100)

# Adjust ax.scene position
scale = sqrt(2) # for a 45° rotation
center = 0.5f0* (minimum(bbox) + maximum(bbox))
ws = widths(bbox)
ax.scene.px_area = Observable(Rect2i(
    floor.(Int, center + v[Vec(1, 2)]) - ceil.(Int, 0.5 * scale .* ws), 
    2 * ceil.(Int, 0.5 * scale .* ws)
))
iscale = width(ax.scene.px_area[]) ./ ws

# rotate plots in ax.scene
model = map(ax.finallimits, ax.scene.px_area) do rect, px_area 
    bb_width = widths(ax.layoutobservables.computedbbox[])
    iscale = width(px_area) ./ bb_width
    ws = widths(rect)
    center = minimum(rect) .+ 0.5ws
    Makie.translationmatrix(Vec3f(center..., 100)) *
    Makie.scalematrix(Vec3f((ws ./ iscale)..., 1)) *
    Makie.rotationmatrix_z(Float32(ϕ)) *
    Makie.scalematrix(Vec3f((1.0 ./ ws)..., 1)) *
    Makie.translationmatrix(Vec3f(-center..., 0))
end
# p.model = model
ax.scene.transformation.model[] = model[]
p.markersize[] = 9 / iscale[1]

fig

```

This breaks when the limits of the rotated axis change, when that axis is not square or when it’s rotated by some other angle (both require different transformations).

---

<div class="post-metadata">

**Author:** ![grero](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/grero/32/109_2.png) [@grero](https://discourse.julialang.org/u/grero)\
**Post date:** [July 18, 2026, 2:27pm UTC](https://discourse.julialang.org/t/rotating-plots-in-makie/72017/6 "2026-07-18T14:27:10Z")

</div>

I apologize for resurrecting this old thread, is there way to achieve this now in CairoMakie? I’m trying to reproduce this exact type of plot.

---

<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:** [July 19, 2026, 11:33am UTC](https://discourse.julialang.org/t/rotating-plots-in-makie/72017/7 "2026-07-19T11:33:01Z")

</div>

Probably easiest to build the visualization from rotated primitives instead of fighting Axis which is not meant to be rotated.
