Zetison
November 27, 2023, 7:14am
1
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
jules
November 27, 2023, 7:33am
2
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
Zetison
November 27, 2023, 3:21pm
3
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