Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce max_auto_ticklabel_spacing! for less jitter #4607

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- Fix `colorbuffer(axis)` for `px_per_unit != 1` [#4574](https://github.com/MakieOrg/Makie.jl/pull/4574).
- Fix render order of Axis3 frame lines in CairoMakie [#4591](https://github.com/MakieOrg/Makie.jl/pull/4591)
- Fixed an incorrect comparison in CairoMakie's line clipping code causing a line segment to disappear [#4631](https://github.com/MakieOrg/Makie.jl/pull/4631)
- Introduce `max_auto_ticklabel_spacing!` for a jitter free tickspace which only grows larger and `use_zoom_reset_timer`/`use_pan_reset_timer` to disable timed reset [#4607](https://github.com/MakieOrg/Makie.jl/pull/4607).

## [0.21.16] - 2024-11-06

Expand Down
5 changes: 2 additions & 3 deletions src/layouting/text_boundingbox.jl
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,8 @@ end
# Utility
function text_bb(str, font, size)
rot = Quaternionf(0,0,0,1)
fonts = nothing # TODO: remove the arg if possible
layout = layout_text(
str, size, font, fonts, Vec2f(0), rot, 0.5, 1.0,
str, size, font, nothing, Vec2f(0), rot, 0.5, 1.0,
RGBAf(0, 0, 0, 0), RGBAf(0, 0, 0, 0), 0f0, 0f0)
return string_boundingbox(layout, Point3d(0), rot)
end
Expand Down Expand Up @@ -149,4 +148,4 @@ end
function rotate_bbox(bb::Rect3{T}, rot) where {T <: Real}
points = decompose(Point3{T}, bb)
return Rect3{T}(Ref(rot) .* points)
end
end
29 changes: 23 additions & 6 deletions src/makielayout/blocks/axis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1086,11 +1086,9 @@ function timed_ticklabelspace_reset(ax::Axis, reset_timer::Ref,

reset_timer[] = Timer(threshold_sec) do t
reset_timer[] = nothing

ax.xticklabelspace = prev_xticklabelspace[]
ax.yticklabelspace = prev_yticklabelspace[]
end

end


Expand Down Expand Up @@ -1198,8 +1196,10 @@ end
Sets the space allocated for the yticklabels of the `Axis` to the minimum that is needed and returns that value.
"""
function tight_yticklabel_spacing!(ax::Axis)
space = tight_ticklabel_spacing!(ax.yaxis)
return space
spacing = tight_ticklabel_spacing!(ax.yaxis)
# Needed to not reset to automatic... But still doesn't keep the value somehow?
# ax.yticklabelspace = spacing
return spacing
end

"""
Expand All @@ -1208,8 +1208,10 @@ end
Sets the space allocated for the xticklabels of the `Axis` to the minimum that is needed and returns that value.
"""
function tight_xticklabel_spacing!(ax::Axis)
space = tight_ticklabel_spacing!(ax.xaxis)
return space
spacing = tight_ticklabel_spacing!(ax.xaxis)
# Needed to not reset to automatic... But still doesn't keep the value somehow?
# ax.xticklabelspace = spacing
return spacing
end

"""
Expand All @@ -1223,6 +1225,21 @@ function tight_ticklabel_spacing!(ax::Axis)
return
end

"""
max_auto_ticklabel_spacing!(ax::Axis)

Sets the space allocated for the xticklabels and yticklabels of the `Axis` to the maximum of what is currently displayed,
and when zooming or panning, tick space will only ever get larger but never shrink.
This is useful for avoiding jittering when interacting with the plot.
"""
function max_auto_ticklabel_spacing!(ax::Axis)
ax.use_zoom_reset_timer = false
ax.use_pan_reset_timer = false
max_auto_ticklabel_spacing!(ax.xaxis)
max_auto_ticklabel_spacing!(ax.yaxis)
return
end

function Base.show(io::IO, ::MIME"text/plain", ax::Axis)
nplots = length(ax.scene.plots)
println(io, "Axis with $nplots plots:")
Expand Down
6 changes: 4 additions & 2 deletions src/makielayout/interactions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ function process_interaction(s::ScrollZoom, event::ScrollEvent, ax::Axis)
yzoomlock = ax.yzoomlock
xzoomkey = ax.xzoomkey
yzoomkey = ax.yzoomkey
use_zoom_reset_timer = ax.use_zoom_reset_timer[]


scene = ax.scene
Expand Down Expand Up @@ -276,7 +277,7 @@ function process_interaction(s::ScrollZoom, event::ScrollEvent, ax::Axis)
newxorigin = xzoomlock[] ? xorigin : xorigin + mp_axfraction[1] * (xwidth - newxwidth)
newyorigin = yzoomlock[] ? yorigin : yorigin + mp_axfraction[2] * (ywidth - newywidth)

timed_ticklabelspace_reset(ax, s.reset_timer, s.prev_xticklabelspace, s.prev_yticklabelspace, s.reset_delay)
use_zoom_reset_timer && timed_ticklabelspace_reset(ax, s.reset_timer, s.prev_xticklabelspace, s.prev_yticklabelspace, s.reset_delay)

newrect_trans = if ispressed(scene, xzoomkey[])
Rectd(newxorigin, yorigin, newxwidth, ywidth)
Expand Down Expand Up @@ -304,6 +305,7 @@ function process_interaction(dp::DragPan, event::MouseEvent, ax)
ypanlock = ax.ypanlock
xpankey = ax.xpankey
ypankey = ax.ypankey
use_pan_reset_timer = ax.use_pan_reset_timer[]

scene = ax.scene
cam = camera(scene)
Expand Down Expand Up @@ -345,7 +347,7 @@ function process_interaction(dp::DragPan, event::MouseEvent, ax)
yori = tlimits_trans.origin[2]
end

timed_ticklabelspace_reset(ax, dp.reset_timer, dp.prev_xticklabelspace, dp.prev_yticklabelspace, dp.reset_delay)
use_pan_reset_timer && timed_ticklabelspace_reset(ax, dp.reset_timer, dp.prev_xticklabelspace, dp.prev_yticklabelspace, dp.reset_delay)

inv_transf = Makie.inverse_transform(transf)
newrect_trans = Rectd(Vec2(xori, yori), widths(tlimits_trans))
Expand Down
35 changes: 22 additions & 13 deletions src/makielayout/lineaxis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,8 @@ function LineAxis(parent::Scene, attrs::Attributes)
onany(parent, ticklabel_ideal_space, ticklabelspace) do idealspace, space
s = if space == automatic
idealspace
elseif space == :max_auto
max(idealspace, actual_ticklabelspace[])
else
space
end
Expand Down Expand Up @@ -506,29 +508,36 @@ function LineAxis(parent::Scene, attrs::Attributes)
return LineAxis(parent, protrusion, attrs, decorations, tickpositions, tickvalues, tickstrings, minortickpositions, minortickvalues)
end

function tight_ticklabel_spacing!(la::LineAxis)

horizontal = if la.attributes.endpoints[][1][2] == la.attributes.endpoints[][2][2]
function tight_ticklabel_spacing(la::LineAxis)
endpoints = la.attributes.endpoints[]
horizontal = if endpoints[1][2] == endpoints[2][2]
true
elseif la.attributes.endpoints[][1][1] == la.attributes.endpoints[][2][1]
elseif endpoints[1][1] == endpoints[2][1]
false
else
error("endpoints not on a horizontal or vertical line")
end

tls = la.elements[:ticklabels]
maxwidth = if horizontal
# height
tls.visible[] ? height(Rect2f(boundingbox(tls, :data))) : 0f0
else
# width
tls.visible[] ? width(Rect2f(boundingbox(tls, :data))) : 0f0
end
bb = Rect2f(boundingbox(tls, :data))
maxwidth = horizontal ? height(bb) : width(bb)
return Float64(tls.visible[] ? maxwidth : 0.0)
end

function tight_ticklabel_spacing!(la::LineAxis)
maxwidth = tight_ticklabel_spacing(la)
la.attributes.ticklabelspace = maxwidth
return Float64(maxwidth)
return maxwidth
end


function max_auto_ticklabel_spacing!(la::LineAxis)
# Grow tickspace to fit the current ticklabels to prevent jittering
maxwidth = tight_ticklabel_spacing(la)
la.attributes.actual_ticklabelspace = maxwidth
la.attributes.ticklabelspace = :max_auto
return maxwidth
end

iswhitespace(str) = match(r"^\s*$", str) !== nothing

function Base.delete!(la::LineAxis)
Expand Down
13 changes: 9 additions & 4 deletions src/makielayout/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -327,10 +327,10 @@ Axis(fig_or_scene; palette = nothing, kwargs...)
xticklabelsvisible::Bool = true
"Controls if the yticklabels are visible."
yticklabelsvisible::Bool = true
"The space reserved for the xticklabels."
xticklabelspace::Union{Makie.Automatic, Float64} = Makie.automatic
"The space reserved for the yticklabels."
yticklabelspace::Union{Makie.Automatic, Float64} = Makie.automatic
"The space reserved for the xticklabels. Can be set to `Makie.automatic` to automatically determine the space needed, `:max_auto` to only ever grow to fit the current ticklabels, or a specific value."
xticklabelspace::Union{Makie.Automatic, Float64, Symbol} = Makie.automatic
"The space reserved for the yticklabels. Can be set to `Makie.automatic` to automatically determine the space needed, `:max_auto` to only ever grow to fit the current ticklabels, or a specific value."
yticklabelspace::Union{Makie.Automatic, Float64, Symbol} = Makie.automatic
"The space between xticks and xticklabels."
xticklabelpad::Float64 = 2f0
"The space between yticks and yticklabels."
Expand Down Expand Up @@ -676,6 +676,11 @@ Axis(fig_or_scene; palette = nothing, kwargs...)
on the values of `yticks` and `ytickformat`.
"""
yscale = identity

"Controls if the zoom reset timer is used, which is used to reset the ticklabel space after zooming."
use_zoom_reset_timer = true
"Controls if the pan reset timer is used, which is used to reset the ticklabel space after panning."
use_pan_reset_timer = true
end
end

Expand Down
Loading