Zoomed inset using Makie?

Is it possible to achieve zooming in a portion of an (already drawn) axis and display it as another axis, or as an inset?

Something like this in matplotlib:

Yup this is possible, specifically using the BBox function (which specifies the bounding box of the Axis). Here’s a small example:

using CairoMakie
CairoMakie.activate!(type = "svg")

x = 0.0 : 0.1 : 10.0
y = exp.(-x)

begin
    fig = Figure(size=(800,800))
    ax1 = Axis(
        fig[1,1]; 
        xgridvisible=false, ygridvisible=false
    )

    lines!(ax1, x, y)
    bracket!(5, 0.01, 10, 0.01; offset=5, style=:square, orientation=:up)

    ax2 = Axis(
        fig; 
        yscale=log10,
        bbox=BBox(400, 750, 200, 600)
    )
    lines!(ax2, x[50:end], y[50:end])

    fig
end

This produces:

Hope this helps!

1 Like

This here worked on GLMakie v0.8.11 (includes update of rectangle-zoom for interactivity). The idea is to turn this into something like an insetaxis method, but I haven’t found time for that yet.

using GLMakie
import GLMakie.Makie.GeometryBasics: coordinates
GLMakie.activate!()

x = collect(1:100)
y = randn(length(x))

fig = Figure()
ax = Axis(fig[1,1])
inset = Axis(fig[1,1]; width=Relative(0.8), height=Relative(0.2),
             halign=0.9, valign=0.1, backgroundcolor=(:white,1.0))

scatterlines!(ax, x, y)
subx, suby = x[30:40], y[30:40]
scatterlines!(inset, subx, suby)

poly!(ax, inset.finallimits, color=(:black,0), strokewidth=1, strokecolor=:black)

translate!(inset.blockscene, 0, 0, 1000)

shifted_bbox = lift(ax.scene.px_area, inset.layoutobservables.computedbbox,
                    ax.scene.camera.projectionview) do px_area, bbox, _
  Rect2f(bbox.origin .- px_area.origin, bbox.widths)
end

scatter!(ax, shifted_bbox, color=:red, space=:pixel)

vert_edges = [ Observable{Any}() for _ = 1:4 ]
onany(inset.finallimits, shifted_bbox) do bbox1, bbox2
  for (i,(c1, c2)) in enumerate(zip(coordinates(bbox1), coordinates(bbox2)))
    cc1 = Makie.project(ax.scene, Point2f(c1))
    vert_edges[i][] = [ cc1, Point2f(c2) ]
  end
end
notify(inset.finallimits)
for vs in vert_edges
  lines!(ax, vs, color=:grey, space=:pixel)
end

display(fig)

image

I don’t think this is what I need, because this example actually draws the data twice (which is what I am doing right now). It’s easy enough for a simple line plot, but if I have multiple layers, or even dynamically drawn axis, I would prefer to just use the data already in axis one.

This also draws the data twice, so not exactly what I am looking for.