How to update Makie plot upon zooming?

I’m trying to update the plot with higher resolution when zooming in a Makie plot. But it seems events(ax).scroll is not triggered. Is this a bug? The following MWE illustrates this issue:

using GLMakie
 
function update_zoom!(ax,xlim)
    noPoints = 1000
    x = range(xlim[1]/noPoints,xlim[2],noPoints)
    y = sin.(1 ./ x)
 
    lines!(ax, x, y)
end
 
fig = Figure()
ax = Makie.Axis(fig[1, 1])
 
on(events(ax).scroll) do event
    println("Scroll event detected")
    xlims = ax.limits.x
    update_zoom!(event, ax)
end
 
update_zoom!(ax,[0.01,1])
fig

Try setting priority = some_positive_integer in the on call so your function gets called before the axis scroll interaction which consumes the event.

But you shouldn’t create new lines! on scroll, that will fill your axis up real quick. Look in the docs how animations using observables are done

Thanks a lot for your quick reply. It worked nicely! I expanded upon the code and fixed some bugs for future users:

include("startup.jl")

using GLMakie
noPoints = 1000
function update_zoom!(l,xlims)
    x = range(xlims[1],xlims[2],noPoints)
    y = sin.(1 ./ x)
    l[1] = x
    l[2] = y
end
 
fig = Figure()
ax = Makie.Axis(fig[1, 1])

x = range(0.01,1,noPoints)
y = sin.(1 ./ x)

l = lines!(ax, x, y)

# Function to extract pixel to data coordinates
function extractMouseCoordinates(ax)
    mouse_pos = events(ax).mouseposition[]
    plot_origin = pixelarea(ax.scene)[].origin
    plot_widths = pixelarea(ax.scene)[].widths
    rectangle = ax.finallimits[]
    xlims = (rectangle.origin[1], rectangle.origin[1] + rectangle.widths[1])
    ylims = (rectangle.origin[2], rectangle.origin[2] + rectangle.widths[2])
    xrange = xlims[2] - xlims[1]
    yrange = ylims[2] - ylims[1]
    x = xlims[1] + (mouse_pos[1] - plot_origin[1]) * xrange / plot_widths[1]
    y = ylims[1] + (mouse_pos[2] - plot_origin[2]) * yrange / plot_widths[2]
    return (x, y, xlims, ylims, xrange, yrange)
end
 
on(events(ax).scroll, priority = 1) do event
    mouse_pos_x, mouse_pos_y, xlims, ylims, xrange, yrange = extractMouseCoordinates(ax)

    # Determine zoom factor (adjust the value for different zoom speed)
    zoom_factor = event[2]
    zoom_factor = zoom_factor > 0 ? 1/(zoom_factor+1) : -zoom_factor+1

    # Calculate the ratios of mouse position within current limits
    x_ratio = (mouse_pos_x - xlims[1]) / xrange
    y_ratio = (mouse_pos_y - ylims[1]) / yrange

    # Adjusted xrange and yrange
    adjusted_xrange = xrange * zoom_factor
    adjusted_yrange = yrange * zoom_factor

    # Calculate new limits based on mouse position ratio
    new_xlims = (
        mouse_pos_x - adjusted_xrange * x_ratio, 
        mouse_pos_x + adjusted_xrange * (1 - x_ratio)
    )
    new_ylims = (
        mouse_pos_y - adjusted_yrange * y_ratio, 
        mouse_pos_y + adjusted_yrange * (1 - y_ratio)
    )

    # Update limits
    ax.limits = (new_xlims..., new_ylims...)

    update_zoom!(l,new_xlims)
end

is_dragging = Ref(false)
start_pos = Ref((0.0,0.0))

# Event handlers
on(events(ax.scene).mousebutton, priority = 2) do event
    if event.button == Mouse.left
        if event.action == Mouse.press
            mouseInfo = extractMouseCoordinates(ax)
            start_pos[] = mouseInfo[1:2]
            is_dragging[] = true
        elseif event.action == Mouse.release && is_dragging[]
            mouseInfo = extractMouseCoordinates(ax)
            end_pos = mouseInfo[1:2]
            is_dragging[] = false

            # Set new limits based on the rectangle
            new_xlims = (min(start_pos[][1], end_pos[1]), max(start_pos[][1], end_pos[1]))
            new_ylims = (min(start_pos[][2], end_pos[2]), max(start_pos[][2], end_pos[2]))
            ax.limits = (new_xlims..., new_ylims...)

            update_zoom!(l,new_xlims)
        end
    end
end

fig