From e2eba12059e606498d6b89cd747e2b8bfe178ecd Mon Sep 17 00:00:00 2001 From: ffreyer Date: Fri, 17 Nov 2023 14:43:23 +0100 Subject: [PATCH 01/14] replace radial distortion with radius_at_origin --- src/makielayout/blocks/polaraxis.jl | 73 ++++++++++++++--------------- src/makielayout/types.jl | 6 +-- 2 files changed, 38 insertions(+), 41 deletions(-) diff --git a/src/makielayout/blocks/polaraxis.jl b/src/makielayout/blocks/polaraxis.jl index dc2d7aa240d..ffa23b3edbc 100644 --- a/src/makielayout/blocks/polaraxis.jl +++ b/src/makielayout/blocks/polaraxis.jl @@ -26,11 +26,11 @@ function initialize_block!(po::PolarAxis; palette=nothing) end # Setup camera/limits and Polar transform - usable_fraction, radius_at_origin = setup_camera_matrices!(po) + usable_fraction = setup_camera_matrices!(po) Observables.connect!( po.scene.transformation.transform_func, - @lift(Polar($(po.theta_as_x), $(po.target_theta_0), $(po.direction), $(radius_at_origin))) + @lift(Polar($(po.theta_as_x), $(po.target_theta_0), $(po.direction), $(po.radius_at_origin))) ) Observables.connect!( po.overlay.transformation.transform_func, @@ -38,7 +38,7 @@ function initialize_block!(po::PolarAxis; palette=nothing) ) # Draw clip, grid lines, spine, ticks - rticklabelplot, thetaticklabelplot = draw_axis!(po, radius_at_origin) + rticklabelplot, thetaticklabelplot = draw_axis!(po) # Calculate fraction of screen usable after reserving space for theta ticks # TODO: Should we include rticks here? @@ -216,18 +216,13 @@ function setup_camera_matrices!(po::PolarAxis) reset_limits!(po) onany((_, _) -> reset_limits!(po), po.blockscene, po.rlimits, po.thetalimits) - # To keep the inner clip radius below a certain fraction of the outer clip - # radius we map all r > r0 to 0. This computes that r0. - radius_at_origin = map(po.blockscene, po.target_rlims, po.radial_distortion_threshold) do (rmin, rmax), max_fraction - # max_fraction = (rmin - r0) / (rmax - r0) solved for r0 - return max(0.0, (rmin - max_fraction * rmax) / (1 - max_fraction)) - end - # get cartesian bbox defined by axis limits - # OPT: target_radius update triggers radius_at_origin update - data_bbox = map(po.blockscene, po.target_thetalims, radius_at_origin, po.direction, po.target_theta_0) do tlims, ro, dir, t0 - return polaraxis_bbox(po.target_rlims[], tlims, ro, dir, t0) - end + data_bbox = map( + polaraxis_bbox, + po.blockscene, + po.target_rlims, po.target_thetalims, + po.radius_at_origin, po.direction, po.target_theta_0 + ) # fit data_bbox into the usable area of PolarAxis (i.e. with tick space subtracted) onany(po.blockscene, usable_fraction, data_bbox) do usable_fraction, bb @@ -239,9 +234,10 @@ function setup_camera_matrices!(po::PolarAxis) end # same as above, but with rmax scaled to 1 + # OPT: data_bbox triggers on radius_at_origin, target_rlims updates onany(po.blockscene, usable_fraction, data_bbox) do usable_fraction, bb mini = minimum(bb); ws = widths(bb) - rmax = po.target_rlims[][2] - radius_at_origin[] # both update data_bbox + rmax = po.target_rlims[][2] - po.radius_at_origin[] scale = minimum(2usable_fraction ./ ws) trans = to_ndim(Vec3f, -scale .* (mini .+ 0.5ws), 0) scale *= rmax @@ -460,12 +456,15 @@ function setup_camera_matrices!(po::PolarAxis) return Consume(false) end - return usable_fraction, radius_at_origin + return usable_fraction end function reset_limits!(po::PolarAxis) + # Resolve automatic as origin + rlimits = (po.rlimits[][1] === :origin ? po.radius_at_origin[] : po.rlimits[][1], po.rlimits[][2]) + # at least one derived limit - if any(isnothing, po.rlimits[]) || any(isnothing, po.thetalimits[]) + if any(isnothing, rlimits) || any(isnothing, po.thetalimits[]) if !isempty(po.scene.plots) # TODO: Why does this include child scenes by default? @@ -482,11 +481,11 @@ function reset_limits!(po::PolarAxis) # cleanup autolimits (0 width, negative rmin) if rmin == rmax - rmin = max(0.0, rmin - 5.0) + rmin = max(po.radius_at_origin[], rmin - 5.0) rmax = rmin + 10.0 else dr = rmax - rmin - rmin = max(0.0, rmin - po.rautolimitmargin[][1] * dr) + rmin = max(po.radius_at_origin[], rmin - po.rautolimitmargin[][1] * dr) rmax += po.rautolimitmargin[][2] * dr end @@ -506,11 +505,11 @@ function reset_limits!(po::PolarAxis) end # apply - po.target_rlims[] = ifelse.(isnothing.(po.rlimits[]), (rmin, rmax), po.rlimits[]) + po.target_rlims[] = ifelse.(isnothing.(rlimits), (rmin, rmax), rlimits) po.target_thetalims[] = ifelse.(isnothing.(po.thetalimits[]), (thetamin, thetamax), po.thetalimits[]) else # all limits set - if po.target_rlims[] != po.rlimits[] - po.target_rlims[] = po.rlimits[] + if po.target_rlims[] != rlimits + po.target_rlims[] = rlimits end if po.target_thetalims[] != po.thetalimits[] po.target_thetalims[] = po.thetalimits[] @@ -537,7 +536,7 @@ function _polar_clip_polygon( return [Polygon(exterior, [interior])] end -function draw_axis!(po::PolarAxis, radius_at_origin) +function draw_axis!(po::PolarAxis) rtick_pos_lbl = Observable{Vector{<:Tuple{AbstractString, Point2f}}}() rtick_align = Observable{Point2f}() rtick_offset = Observable{Point2f}() @@ -557,16 +556,14 @@ function draw_axis!(po::PolarAxis, radius_at_origin) end end - # OPT: target_radius update triggers radius_at_origin update onany( po.blockscene, po.rticks, po.rminorticks, po.rtickformat, po.rtickangle, - po.direction, po.target_thetalims, po.sample_density, radius_at_origin + po.direction, po.target_rlims, po.target_thetalims, po.sample_density, po.radius_at_origin ) do rticks, rminorticks, rtickformat, rtickangle, - dir, thetalims, sample_density, radius_at_origin + dir, rlims, thetalims, sample_density, radius_at_origin # For text: - rlims = po.target_rlims[] rmaxinv = 1.0 / (rlims[2] - radius_at_origin) _rtickvalues, _rticklabels = get_ticks(rticks, identity, rtickformat, rlims...) _rtickradius = (_rtickvalues .- radius_at_origin) .* rmaxinv @@ -625,8 +622,8 @@ function draw_axis!(po::PolarAxis, radius_at_origin) onany( po.blockscene, po.thetaticks, po.thetaminorticks, po.thetatickformat, po.thetaticklabelpad, - po.direction, po.target_theta_0, po.target_rlims, po.target_thetalims, po.radial_distortion_threshold - ) do thetaticks, thetaminorticks, thetatickformat, px_pad, dir, theta_0, rlims, thetalims, max_clip + po.direction, po.target_theta_0, po.target_rlims, po.target_thetalims, po.radius_at_origin + ) do thetaticks, thetaminorticks, thetatickformat, px_pad, dir, theta_0, rlims, thetalims, r0 _thetatickvalues, _thetaticklabels = get_ticks(thetaticks, identity, thetatickformat, thetalims...) @@ -652,7 +649,7 @@ function draw_axis!(po::PolarAxis, radius_at_origin) thetatick_pos_lbl[] = tuple.(_thetaticklabels, Point2f.(1, _thetatickvalues)) # Grid lines - rmin = min(rlims[1] / rlims[2], max_clip) + rmin = (rlims[1] - r0) / (rlims[2] - r0) thetagridpoints[] = [Point2f(r, theta) for theta in _thetatickvalues for r in (rmin, 1)] _thetaminortickvalues = get_minor_tickvalues(thetaminorticks, identity, _thetatickvalues, thetalims...) @@ -795,19 +792,19 @@ function draw_axis!(po::PolarAxis, radius_at_origin) rotate!.((outer_clip_plot, inner_clip_plot), (Vec3f(0,0,1),), angle) end - onany(po.blockscene, po.target_rlims, po.radial_distortion_threshold) do lims, maxclip - s = min(lims[1] / lims[2], maxclip) + onany(po.blockscene, po.target_rlims, po.radius_at_origin) do lims, r0 + s = (lims[1] - r0) / (lims[2] - r0) scale!(inner_clip_plot, Vec3f(s, s, 1)) end - notify(po.radial_distortion_threshold) + notify(po.radius_at_origin) # spine traces circle sector - inner circle spine_points = map(po.blockscene, - po.target_rlims, po.target_thetalims, po.radial_distortion_threshold, po.sample_density - ) do (rmin, rmax), thetalims, max_clip, N + po.target_rlims, po.target_thetalims, po.radius_at_origin, po.sample_density + ) do (rmin, rmax), thetalims, r0, N thetamin, thetamax = thetalims - rmin = min(rmin/rmax, max_clip) + rmin = (rmin - r0) / (rmax - r0) rmax = 1.0 # make sure we have 2+ points per arc @@ -906,9 +903,9 @@ end Sets the radial limits of a given `PolarAxis`. """ -rlims!(po::PolarAxis, r::Union{Nothing, Real}) = rlims!(po, po.rlimits[][1], r) +rlims!(po::PolarAxis, r::Union{Symbol, Nothing, Real}) = rlims!(po, po.rlimits[][1], r) -function rlims!(po::PolarAxis, rmin::Union{Nothing, Real}, rmax::Union{Nothing, Real}) +function rlims!(po::PolarAxis, rmin::Union{Symbol, Nothing, Real}, rmax::Union{Nothing, Real}) po.rlimits[] = (rmin, rmax) return end diff --git a/src/makielayout/types.jl b/src/makielayout/types.jl index f9a71ebd212..80df3d60d3f 100644 --- a/src/makielayout/types.jl +++ b/src/makielayout/types.jl @@ -1664,19 +1664,19 @@ end clip::Bool = true "Sets the color of the clip polygon. Mainly for debug purposes." clipcolor = automatic - "Sets a threshold relative to `rmin/rmax` after which radii are distorted to fit more on the screen. No distortion is applied if `radial_distortion_threshold ≥ 1`" - radial_distortion_threshold::Float64 = 1.0 # Limits & transformation settings "The radial limits of the PolarAxis." - rlimits = (0.0, nothing) + rlimits = (:origin, nothing) "The angle limits of the PolarAxis. (0.0, 2pi) results a full circle. (nothing, nothing) results in limits picked based on plot limits." thetalimits = (0.0, 2pi) "The direction of rotation. Can be -1 (clockwise) or 1 (counterclockwise)." direction::Int = 1 "The angular offset for (1, 0) in the PolarAxis. This rotates the axis." theta_0::Float32 = 0f0 + "Sets the radius at the origin of the PolarAxis, such that `r_out = r_in - radius_at_origin`." + radius_at_origin::Float32 = 0f0 "Controls the argument order of the Polar transform. If `theta_as_x = true` it is (θ, r), otherwise (r, θ)." theta_as_x::Bool = true "The relative margins added to the autolimits in r direction." From 919637de51feedcd4894c26b2f28a0f2ba796352 Mon Sep 17 00:00:00 2001 From: ffreyer Date: Fri, 17 Nov 2023 15:21:30 +0100 Subject: [PATCH 02/14] update docs --- docs/reference/blocks/polaraxis.md | 43 +++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/docs/reference/blocks/polaraxis.md b/docs/reference/blocks/polaraxis.md index eede5ff6422..f0ddc4ba477 100644 --- a/docs/reference/blocks/polaraxis.md +++ b/docs/reference/blocks/polaraxis.md @@ -204,9 +204,9 @@ clipping via the `clip` attribute. For reference, the z values used by `PolarAxis` are `po.griddepth[] = 8999` for grid lines, 9000 for the clip polygons, 9001 for spines and 9002 for tick labels. -### Radial Distortion +### Radial Offset -If you have a plot with a large rmin and rmax over a wide range of angles you will end up with a narrow PolarAxis. +If you have a plot with rlimits far away from 0 you will end up with a lot of empty space in the PolarAxis. Consider for example: \begin{examplefigure}{svg = true} @@ -218,22 +218,47 @@ fig ``` \end{examplefigure} -In this case you may want to distort the r-direction to make more of your data visible. -This can be done by setting `ax.radial_distortion_threshold` to a value between 0 and 1. +In this case you may want to offset the r-direction to make more of your data visible. +This can be done by setting `ax.radius_at_origin` which translates radii as `r_out = r_in - radius_at_origin`. \begin{examplefigure}{svg = true} ```julia fig = Figure() -ax = PolarAxis(fig[1, 1], thetalimits = (0, pi), radial_distortion_threshold = 0.2, rlimits = (nothing, nothing)) +ax = PolarAxis(fig[1, 1], thetalimits = (0, pi), radius_at_origin = 8) lines!(ax, range(0, pi, length=100), 10 .+ sin.(0.3 .* (1:100))) fig ``` \end{examplefigure} -Internally PolarAxis will check `rmin/rmax` against the set threshold. -If that ratio exceed the threshold, the polar transform is adjusted to shift all radii by some `r0` such that `(rmin - r0) / rmax - r0) == ax.radial_distortion_threshold`. -In effect this will hold the inner cutout/clip radius at a fraction of the outer radius. -Note that at `ax.radial_distortion_threshold >= 1.0` (default) this will never distort your data. +This can also be used to show a plot with negative radii: + +\begin{examplefigure}{svg = true} +```julia +fig = Figure() +ax = PolarAxis(fig[1, 1], thetalimits = (0, pi), radius_at_origin = -12) +lines!(ax, range(0, pi, length=100), sin.(0.3 .* (1:100)) .- 10) +fig +``` +\end{examplefigure} + +Note however that translating radii results in some level of distortion: + +\begin{examplefigure}{svg = true} +```julia +phis = range(pi/4, 9pi/4, length=201) +rs = 1.0 ./ sin.(range(pi/4, 3pi/4, length=51)[1:end-1]) +rs = vcat(rs, rs, rs, rs, rs[1]) + +fig = Figure(size = (1200, 400)) +ax = PolarAxis(fig[1, 1], radius_at_origin = -2, title = "radius_at_origin = -2") +lines!(ax, phis, rs) +ax = PolarAxis(fig[1, 2], title = "radius_at_origin = 0") +lines!(ax, phis, rs) +ax = PolarAxis(fig[1, 3], radius_at_origin = 0.5, title = "radius_at_origin = 0.5") +lines!(ax, phis, rs) +fig +``` +\end{examplefigure} ## Attributes From a53ab7ef151e5667dcff86f82493288ca798a869 Mon Sep 17 00:00:00 2001 From: ffreyer Date: Fri, 17 Nov 2023 15:25:43 +0100 Subject: [PATCH 03/14] update tests --- test/PolarAxis.jl | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/test/PolarAxis.jl b/test/PolarAxis.jl index 1866f439743..b881033c404 100644 --- a/test/PolarAxis.jl +++ b/test/PolarAxis.jl @@ -144,17 +144,9 @@ @test all(isapprox.(ax.target_thetalims[], (0.5pi, 1.0pi), rtol=1e-6)) end - @testset "Radial Distortion" begin + @testset "Radial Offset" begin fig = Figure() - ax = PolarAxis(fig[1, 1], radial_distortion_threshold = 0.2, rlimits = (0, 10)) - tf = ax.scene.transformation.transform_func - @test /(ax.target_rlims[]...) == 0.0 - @test /((ax.target_rlims[] .- tf[].r0)...) == 0.0 - rlims!(ax, 1, 10) - @test /(ax.target_rlims[]...) == 0.1 - @test /((ax.target_rlims[] .- tf[].r0)...) == 0.1 - rlims!(ax, 5, 10) - @test /(ax.target_rlims[]...) == 0.5 - @test /((ax.target_rlims[] .- tf[].r0)...) ≈ 0.2 + ax = PolarAxis(fig[1, 1], radius_at_origin = -1.0, rlimits = (0, 10)) + @test ax.scene.transformation.transform_func[].r0 == -1.0 end end \ No newline at end of file From 63b26d8f78e0699cbf9130484662648ed9f1dbad Mon Sep 17 00:00:00 2001 From: ffreyer Date: Fri, 17 Nov 2023 15:29:10 +0100 Subject: [PATCH 04/14] update NEWS [skip ci] --- NEWS.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 6879ced31ef..e3b71c1b6a3 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # News +- (Breaking) Replaced `PolarAxis.radial_distortion_threshold` with `PolarAxis.radius_at_origin`. [#3381](https://github.com/MakieOrg/Makie.jl/pull/3381) + ## beta - GLMakie has gained support for HiDPI (aka Retina) screens. @@ -11,7 +13,7 @@ - Added `shading = :verbose` in GLMakie to allow for multiple light sources. Also added more light types, fixed light directions for the previous lighting model (now `shading = :fast`) and adjusted `backlight` to affect normals. [#3246](https://github.com/MakieOrg/Makie.jl/pull/3246) - Deprecated the `resolution` keyword in favor of `size` to reflect that this value is not a pixel resolution anymore [#3343](https://github.com/MakieOrg/Makie.jl/pull/3343). - Changed the glyph used for negative numbers in tick labels from hyphen to minus [#3379](https://github.com/MakieOrg/Makie.jl/pull/3379). - + ## master - Added `cornerradius` attribute to `Box` for rounded corners [#3346](https://github.com/MakieOrg/Makie.jl/pull/3346). From d4a677214974cb0f1d2b7de4b941ef43848c0bfb Mon Sep 17 00:00:00 2001 From: ffreyer Date: Fri, 17 Nov 2023 15:38:14 +0100 Subject: [PATCH 05/14] add refimg --- .../src/tests/figures_and_makielayout.jl | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/ReferenceTests/src/tests/figures_and_makielayout.jl b/ReferenceTests/src/tests/figures_and_makielayout.jl index 787ede722cb..377a9e47f58 100644 --- a/ReferenceTests/src/tests/figures_and_makielayout.jl +++ b/ReferenceTests/src/tests/figures_and_makielayout.jl @@ -211,6 +211,23 @@ end f end +@reference_test "PolarAxis radial shift" begin + phis = range(pi/4, 9pi/4, length=201) + rs = 1.0 ./ sin.(range(pi/4, 3pi/4, length=51)[1:end-1]) + rs = vcat(rs, rs, rs, rs, rs[1]) + + fig = Figure(size = (900, 300)) + ax1 = PolarAxis(fig[1, 1], radius_at_origin = -2) # should reveal red square, rest distorted + ax2 = PolarAxis(fig[1, 2], radius_at_origin = -2) # black square, blue distorted + ax3 = PolarAxis(fig[1, 3], radius_at_origin = 0.5) # black distorted, blue square + for ax in (ax1, ax2, ax3) + lines!(ax, phis, rs .- 2, color = :red, linewidth = 4) + lines!(ax, phis, rs, color = :black, linewidth = 4) + lines!(ax, phis, rs .+ 0.5, color = :blue, linewidth = 4) + end + fig +end + @reference_test "Axis3 axis reversal" begin f = Figure(size = (1000, 1000)) revstr(dir, rev) = rev ? "$dir rev" : "" From 4cdfe82f3abed95d2a23c3c55f3fb2c69faacab9 Mon Sep 17 00:00:00 2001 From: ffreyer Date: Fri, 17 Nov 2023 15:57:13 +0100 Subject: [PATCH 06/14] fix tests --- test/PolarAxis.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/PolarAxis.jl b/test/PolarAxis.jl index b881033c404..8029e1835f1 100644 --- a/test/PolarAxis.jl +++ b/test/PolarAxis.jl @@ -68,7 +68,7 @@ @test ax.thetaautolimitmargin[] == (0.05, 0.05) # default should have mostly set default limits - @test ax.rlimits[] == (0.0, nothing) + @test ax.rlimits[] == (:origin, nothing) @test ax.thetalimits[] == (0.0, 2pi) @test ax.target_rlims[] == (0.0, 10.0) @test ax.target_thetalims[] == (0.0, 2pi) @@ -130,7 +130,7 @@ # with default limits reset_limits!(ax) - @test ax.rlimits[] == (0.0, nothing) + @test ax.rlimits[] == (:origin, nothing) @test ax.thetalimits[] == (0.0, 2pi) @test ax.target_rlims[] == (0.0, 5.0) @test ax.target_thetalims[] == (0.0, 2pi) From 2446607207a0d655db73e41ef67202a5e9d1aff4 Mon Sep 17 00:00:00 2001 From: ffreyer Date: Sun, 19 Nov 2023 14:36:23 +0100 Subject: [PATCH 07/14] allow radius_at_origin = automatic --- src/makielayout/blocks/polaraxis.jl | 51 +++++++++++++++++++---------- src/makielayout/types.jl | 5 +-- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/src/makielayout/blocks/polaraxis.jl b/src/makielayout/blocks/polaraxis.jl index ffa23b3edbc..7d6cb6a2b9e 100644 --- a/src/makielayout/blocks/polaraxis.jl +++ b/src/makielayout/blocks/polaraxis.jl @@ -30,7 +30,7 @@ function initialize_block!(po::PolarAxis; palette=nothing) Observables.connect!( po.scene.transformation.transform_func, - @lift(Polar($(po.theta_as_x), $(po.target_theta_0), $(po.direction), $(po.radius_at_origin))) + @lift(Polar($(po.theta_as_x), $(po.target_theta_0), $(po.direction), $(po.target_r0))) ) Observables.connect!( po.overlay.transformation.transform_func, @@ -213,6 +213,7 @@ function setup_camera_matrices!(po::PolarAxis) setfield!(po, :target_rlims, Observable{Tuple{Float64, Float64}}((0.0, 10.0))) setfield!(po, :target_thetalims, Observable{Tuple{Float64, Float64}}((0.0, 2pi))) setfield!(po, :target_theta_0, map(identity, po.theta_0)) + setfield!(po, :target_r0, Observable{Float32}(0f0)) reset_limits!(po) onany((_, _) -> reset_limits!(po), po.blockscene, po.rlimits, po.thetalimits) @@ -221,7 +222,7 @@ function setup_camera_matrices!(po::PolarAxis) polaraxis_bbox, po.blockscene, po.target_rlims, po.target_thetalims, - po.radius_at_origin, po.direction, po.target_theta_0 + po.target_r0, po.direction, po.target_theta_0 ) # fit data_bbox into the usable area of PolarAxis (i.e. with tick space subtracted) @@ -234,10 +235,10 @@ function setup_camera_matrices!(po::PolarAxis) end # same as above, but with rmax scaled to 1 - # OPT: data_bbox triggers on radius_at_origin, target_rlims updates + # OPT: data_bbox triggers on target_r0, target_rlims updates onany(po.blockscene, usable_fraction, data_bbox) do usable_fraction, bb mini = minimum(bb); ws = widths(bb) - rmax = po.target_rlims[][2] - po.radius_at_origin[] + rmax = po.target_rlims[][2] - po.target_r0[] scale = minimum(2usable_fraction ./ ws) trans = to_ndim(Vec3f, -scale .* (mini .+ 0.5ws), 0) scale *= rmax @@ -461,7 +462,8 @@ end function reset_limits!(po::PolarAxis) # Resolve automatic as origin - rlimits = (po.rlimits[][1] === :origin ? po.radius_at_origin[] : po.rlimits[][1], po.rlimits[][2]) + rmin_to_origin = po.rlimits[][1] === :origin + rlimits = ifelse.(rmin_to_origin, nothing, po.rlimits[]) # at least one derived limit if any(isnothing, rlimits) || any(isnothing, po.thetalimits[]) @@ -479,13 +481,28 @@ function reset_limits!(po::PolarAxis) rmax, thetamax = maximum(lims2d) end - # cleanup autolimits (0 width, negative rmin) + # Determine automatic target_r0 + if po.radius_at_origin[] isa Real + po.target_r0[] = po.radius_at_origin[] + else + po.target_r0[] = rmin + end + + # cleanup autolimits (0 width, rmin ≥ target_r0) if rmin == rmax - rmin = max(po.radius_at_origin[], rmin - 5.0) + if rmin_to_origin + rmin = po.target_r0[] + else + rmin = max(po.target_r0[], rmin - 5.0) + end rmax = rmin + 10.0 else dr = rmax - rmin - rmin = max(po.radius_at_origin[], rmin - po.rautolimitmargin[][1] * dr) + if rmin_to_origin + rmin = po.target_r0[] + else + rmin = max(po.target_r0[], rmin - po.rautolimitmargin[][1] * dr) + end rmax += po.rautolimitmargin[][2] * dr end @@ -559,14 +576,14 @@ function draw_axis!(po::PolarAxis) onany( po.blockscene, po.rticks, po.rminorticks, po.rtickformat, po.rtickangle, - po.direction, po.target_rlims, po.target_thetalims, po.sample_density, po.radius_at_origin + po.direction, po.target_rlims, po.target_thetalims, po.sample_density, po.target_r0 ) do rticks, rminorticks, rtickformat, rtickangle, - dir, rlims, thetalims, sample_density, radius_at_origin + dir, rlims, thetalims, sample_density, target_r0 # For text: - rmaxinv = 1.0 / (rlims[2] - radius_at_origin) + rmaxinv = 1.0 / (rlims[2] - target_r0) _rtickvalues, _rticklabels = get_ticks(rticks, identity, rtickformat, rlims...) - _rtickradius = (_rtickvalues .- radius_at_origin) .* rmaxinv + _rtickradius = (_rtickvalues .- target_r0) .* rmaxinv _rtickangle = default_rtickangle(rtickangle, dir, thetalims) rtick_pos_lbl[] = tuple.(_rticklabels, Point2f.(_rtickradius, _rtickangle)) @@ -575,7 +592,7 @@ function draw_axis!(po::PolarAxis) rgridpoints[] = GeometryBasics.LineString.([Point2f.(r, thetas) for r in _rtickradius]) _rminortickvalues = get_minor_tickvalues(rminorticks, identity, _rtickvalues, rlims...) - _rminortickvalues .= (_rminortickvalues .- radius_at_origin) .* rmaxinv + _rminortickvalues .= (_rminortickvalues .- target_r0) .* rmaxinv rminorgridpoints[] = GeometryBasics.LineString.([Point2f.(r, thetas) for r in _rminortickvalues]) return @@ -622,7 +639,7 @@ function draw_axis!(po::PolarAxis) onany( po.blockscene, po.thetaticks, po.thetaminorticks, po.thetatickformat, po.thetaticklabelpad, - po.direction, po.target_theta_0, po.target_rlims, po.target_thetalims, po.radius_at_origin + po.direction, po.target_theta_0, po.target_rlims, po.target_thetalims, po.target_r0 ) do thetaticks, thetaminorticks, thetatickformat, px_pad, dir, theta_0, rlims, thetalims, r0 _thetatickvalues, _thetaticklabels = get_ticks(thetaticks, identity, thetatickformat, thetalims...) @@ -792,16 +809,16 @@ function draw_axis!(po::PolarAxis) rotate!.((outer_clip_plot, inner_clip_plot), (Vec3f(0,0,1),), angle) end - onany(po.blockscene, po.target_rlims, po.radius_at_origin) do lims, r0 + onany(po.blockscene, po.target_rlims, po.target_r0) do lims, r0 s = (lims[1] - r0) / (lims[2] - r0) scale!(inner_clip_plot, Vec3f(s, s, 1)) end - notify(po.radius_at_origin) + notify(po.target_r0) # spine traces circle sector - inner circle spine_points = map(po.blockscene, - po.target_rlims, po.target_thetalims, po.radius_at_origin, po.sample_density + po.target_rlims, po.target_thetalims, po.target_r0, po.sample_density ) do (rmin, rmax), thetalims, r0, N thetamin, thetamax = thetalims rmin = (rmin - r0) / (rmax - r0) diff --git a/src/makielayout/types.jl b/src/makielayout/types.jl index 80df3d60d3f..bd0d55e016d 100644 --- a/src/makielayout/types.jl +++ b/src/makielayout/types.jl @@ -1636,6 +1636,7 @@ end target_rlims::Observable{Tuple{Float64, Float64}} target_thetalims::Observable{Tuple{Float64, Float64}} target_theta_0::Observable{Float32} + target_r0::Observable{Float32} @attributes begin # Generic @@ -1675,8 +1676,8 @@ end direction::Int = 1 "The angular offset for (1, 0) in the PolarAxis. This rotates the axis." theta_0::Float32 = 0f0 - "Sets the radius at the origin of the PolarAxis, such that `r_out = r_in - radius_at_origin`." - radius_at_origin::Float32 = 0f0 + "Sets the radius at the origin of the PolarAxis such that `r_out = r_in - radius_at_origin`. Can be set to `automatic` to match rmin." + radius_at_origin = 0f0 "Controls the argument order of the Polar transform. If `theta_as_x = true` it is (θ, r), otherwise (r, θ)." theta_as_x::Bool = true "The relative margins added to the autolimits in r direction." From e8a24f40ca641bd484ca9d1e73a35046df9f0b86 Mon Sep 17 00:00:00 2001 From: ffreyer Date: Sun, 19 Nov 2023 15:26:44 +0100 Subject: [PATCH 08/14] add `clip_r` to control clipping of r < 0 --- src/layouting/transformation.jl | 39 +++++++++++++++++++---------- src/makielayout/blocks/polaraxis.jl | 4 +-- src/makielayout/types.jl | 2 ++ 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/layouting/transformation.jl b/src/layouting/transformation.jl index 840740f8a80..bde0e8b3340 100644 --- a/src/layouting/transformation.jl +++ b/src/layouting/transformation.jl @@ -378,26 +378,36 @@ end ################################################################################ """ - Polar(theta_0::Float64 = 0.0, direction::Int = +1, r0::Float64 = 0) + Polar(theta_as_x = true, clip_r = true, theta_0::Float64 = 0.0, direction::Int = +1, r0::Float64 = 0) + +This struct defines a general polar-to-cartesian transformation, i.e. -This struct defines a general polar-to-cartesian transformation, i.e., ```math (r, θ) -> ((r - r₀) ⋅ \\cos(direction ⋅ (θ + θ₀)), (r - r₀) ⋅ \\sin(direction \\cdot (θ + θ₀))) ``` -where theta is assumed to be in radians. - -`direction` should be either -1 or +1, `r0` should be positive and `theta_0` may be any value. - -Note that for `r0 != 0` the inversion may return wrong results. +where θ is assumed to be in radians. + +Controls: +- `theta_as_x = true` controls the order of incoming arguments. If true, a `Point2f` +is interpreted as `(θ, r)`, otherwise `(r, θ)`. +- `clip_r = true` controls whether negative radii are clipped. If true, `r < 0` +produces `NaN`, otherwise they simply enter in the formula above as is. Note that +the inversion only returns `r ≥ 0` +- `theta_0 = 0` offsets angles by the specified amount. +- `direction = +1` inverts the direction of θ. +- `r0 = 0` offsets radii by the specified amount. Not that this will affect the +shape of transformed objects. """ struct Polar theta_as_x::Bool + clip_r::Bool theta_0::Float64 direction::Int r0::Float64 - function Polar(theta_as_x = true, theta_0 = 0.0, direction = +1, r0 = 0) - return new(theta_as_x, theta_0, direction, r0) + + function Polar(theta_0::Real = 0.0, direction::Int = +1, r0::Real = 0, theta_as_x::Bool = true, clip_r::Bool = true) + return new(theta_as_x, clip_r, theta_0, direction, r0) end end @@ -405,12 +415,15 @@ Base.broadcastable(x::Polar) = (x,) function apply_transform(trans::Polar, point::VecTypes{2, T}) where T <: Real if trans.theta_as_x - r = max(0.0, point[2] - trans.r0) - θ = trans.direction * (point[1] + trans.theta_0) + θ, r = point else - r = max(0.0, point[1] - trans.r0) - θ = trans.direction * (point[2] + trans.theta_0) + r, θ = point + end + r = r - trans.r0 + if trans.clip_r && (r < 0.0) + return Point2{T}(NaN) end + θ = trans.direction * (θ + trans.theta_0) y, x = r .* sincos(θ) return Point2{T}(x, y) end diff --git a/src/makielayout/blocks/polaraxis.jl b/src/makielayout/blocks/polaraxis.jl index 7d6cb6a2b9e..4b122b44bec 100644 --- a/src/makielayout/blocks/polaraxis.jl +++ b/src/makielayout/blocks/polaraxis.jl @@ -30,11 +30,11 @@ function initialize_block!(po::PolarAxis; palette=nothing) Observables.connect!( po.scene.transformation.transform_func, - @lift(Polar($(po.theta_as_x), $(po.target_theta_0), $(po.direction), $(po.target_r0))) + @lift(Polar($(po.target_theta_0), $(po.direction), $(po.target_r0), $(po.theta_as_x), $(po.clip_r))) ) Observables.connect!( po.overlay.transformation.transform_func, - @lift(Polar(false, $(po.target_theta_0), $(po.direction))) + @lift(Polar($(po.target_theta_0), $(po.direction), 0.0, false)) ) # Draw clip, grid lines, spine, ticks diff --git a/src/makielayout/types.jl b/src/makielayout/types.jl index bd0d55e016d..df21bc65c37 100644 --- a/src/makielayout/types.jl +++ b/src/makielayout/types.jl @@ -1680,6 +1680,8 @@ end radius_at_origin = 0f0 "Controls the argument order of the Polar transform. If `theta_as_x = true` it is (θ, r), otherwise (r, θ)." theta_as_x::Bool = true + "Controls whether `r < 0` (after applying `radius_at_origin`) gets clipped (true) or not (false)." + clip_r::Bool = true "The relative margins added to the autolimits in r direction." rautolimitmargin::Tuple{Float64, Float64} = (0.05, 0.05) "The relative margins added to the autolimits in theta direction." From 09ab30e827b0ca9a66e45cd69ddd0ffdea3b68e5 Mon Sep 17 00:00:00 2001 From: ffreyer Date: Sun, 19 Nov 2023 15:42:31 +0100 Subject: [PATCH 09/14] update docs --- docs/reference/blocks/polaraxis.md | 35 ++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/docs/reference/blocks/polaraxis.md b/docs/reference/blocks/polaraxis.md index f0ddc4ba477..96036e82532 100644 --- a/docs/reference/blocks/polaraxis.md +++ b/docs/reference/blocks/polaraxis.md @@ -249,13 +249,34 @@ phis = range(pi/4, 9pi/4, length=201) rs = 1.0 ./ sin.(range(pi/4, 3pi/4, length=51)[1:end-1]) rs = vcat(rs, rs, rs, rs, rs[1]) -fig = Figure(size = (1200, 400)) -ax = PolarAxis(fig[1, 1], radius_at_origin = -2, title = "radius_at_origin = -2") -lines!(ax, phis, rs) -ax = PolarAxis(fig[1, 2], title = "radius_at_origin = 0") -lines!(ax, phis, rs) -ax = PolarAxis(fig[1, 3], radius_at_origin = 0.5, title = "radius_at_origin = 0.5") -lines!(ax, phis, rs) +fig = Figure(size = (900, 300)) +ax1 = PolarAxis(fig[1, 1], radius_at_origin = -2, title = "radius_at_origin = -2") +ax2 = PolarAxis(fig[1, 2], title = "radius_at_origin = 0") +ax3 = PolarAxis(fig[1, 3], radius_at_origin = 0.5, title = "radius_at_origin = 0.5") +for ax in (ax1, ax2, ax3) + lines!(ax, phis, rs .- 2, color = :red, linewidth = 4) + lines!(ax, phis, rs, color = :black, linewidth = 4) + lines!(ax, phis, rs .+ 0.5, color = :blue, linewidth = 4) +end +fig +``` +\end{examplefigure} + +### Radial clipping + +By default radii `r_out = r_in - radius_at_origin < 0` are clipped by the Polar transform. +This can be disabled by setting `ax.clip_r = false`. +With that setting `r_out < 0` will pass through the polar transform as is, resulting in a coordinate at $(|r_{out}|, \theta - pi)$. + +\begin{examplefigure}{svg = true} +```julia +fig = Figure(size = (600, 300)) +ax1 = PolarAxis(fig[1, 1], clip_r = true, title = "clip_r = true") +ax2 = PolarAxis(fig[1, 2], clip_r = false, title = "clip_r = false") +for ax in (ax1, ax2) + lines!(ax, 0..2pi, phi -> cos(2phi) - 0.5, color = :red, linewidth = 4) + lines!(ax, 0..2pi, phi -> sin(2phi), color = :black, linewidth = 4) +end fig ``` \end{examplefigure} From 8635b2c0364d6f99937abe605ebc4afcc4a5cf15 Mon Sep 17 00:00:00 2001 From: ffreyer Date: Sun, 19 Nov 2023 15:56:11 +0100 Subject: [PATCH 10/14] tweak refimg --- ReferenceTests/src/tests/figures_and_makielayout.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ReferenceTests/src/tests/figures_and_makielayout.jl b/ReferenceTests/src/tests/figures_and_makielayout.jl index 377a9e47f58..6c6f46a2013 100644 --- a/ReferenceTests/src/tests/figures_and_makielayout.jl +++ b/ReferenceTests/src/tests/figures_and_makielayout.jl @@ -211,15 +211,15 @@ end f end -@reference_test "PolarAxis radial shift" begin +@reference_test "PolarAxis radial shift and clip" begin phis = range(pi/4, 9pi/4, length=201) rs = 1.0 ./ sin.(range(pi/4, 3pi/4, length=51)[1:end-1]) rs = vcat(rs, rs, rs, rs, rs[1]) fig = Figure(size = (900, 300)) - ax1 = PolarAxis(fig[1, 1], radius_at_origin = -2) # should reveal red square, rest distorted - ax2 = PolarAxis(fig[1, 2], radius_at_origin = -2) # black square, blue distorted - ax3 = PolarAxis(fig[1, 3], radius_at_origin = 0.5) # black distorted, blue square + ax1 = PolarAxis(fig[1, 1], clip_r = false, radius_at_origin = -2) # red square, black, blue bulging + ax2 = PolarAxis(fig[1, 2], clip_r = false, radius_at_origin = 0) # red flower, black square, blue bulging + ax3 = PolarAxis(fig[1, 3], clip_r = false, radius_at_origin = 0.5) # red large flower, black star, blue square for ax in (ax1, ax2, ax3) lines!(ax, phis, rs .- 2, color = :red, linewidth = 4) lines!(ax, phis, rs, color = :black, linewidth = 4) From 2e852045f139f992195e2d03f48586e9796f4ff2 Mon Sep 17 00:00:00 2001 From: ffreyer Date: Sun, 19 Nov 2023 16:00:59 +0100 Subject: [PATCH 11/14] switch back to automatic negative r shift --- docs/reference/blocks/polaraxis.md | 8 ++++---- src/makielayout/blocks/polaraxis.jl | 2 +- src/makielayout/types.jl | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/reference/blocks/polaraxis.md b/docs/reference/blocks/polaraxis.md index 96036e82532..426db39665c 100644 --- a/docs/reference/blocks/polaraxis.md +++ b/docs/reference/blocks/polaraxis.md @@ -250,8 +250,8 @@ rs = 1.0 ./ sin.(range(pi/4, 3pi/4, length=51)[1:end-1]) rs = vcat(rs, rs, rs, rs, rs[1]) fig = Figure(size = (900, 300)) -ax1 = PolarAxis(fig[1, 1], radius_at_origin = -2, title = "radius_at_origin = -2") -ax2 = PolarAxis(fig[1, 2], title = "radius_at_origin = 0") +ax1 = PolarAxis(fig[1, 1], radius_at_origin = -2, title = "radius_at_origin = -2") +ax2 = PolarAxis(fig[1, 2], radius_at_origin = 0, title = "radius_at_origin = 0") ax3 = PolarAxis(fig[1, 3], radius_at_origin = 0.5, title = "radius_at_origin = 0.5") for ax in (ax1, ax2, ax3) lines!(ax, phis, rs .- 2, color = :red, linewidth = 4) @@ -271,8 +271,8 @@ With that setting `r_out < 0` will pass through the polar transform as is, resul \begin{examplefigure}{svg = true} ```julia fig = Figure(size = (600, 300)) -ax1 = PolarAxis(fig[1, 1], clip_r = true, title = "clip_r = true") -ax2 = PolarAxis(fig[1, 2], clip_r = false, title = "clip_r = false") +ax1 = PolarAxis(fig[1, 1], radius_at_origin = 0.0, clip_r = true, title = "clip_r = true") +ax2 = PolarAxis(fig[1, 2], radius_at_origin = 0.0, clip_r = false, title = "clip_r = false") for ax in (ax1, ax2) lines!(ax, 0..2pi, phi -> cos(2phi) - 0.5, color = :red, linewidth = 4) lines!(ax, 0..2pi, phi -> sin(2phi), color = :black, linewidth = 4) diff --git a/src/makielayout/blocks/polaraxis.jl b/src/makielayout/blocks/polaraxis.jl index 4b122b44bec..07ea43424cf 100644 --- a/src/makielayout/blocks/polaraxis.jl +++ b/src/makielayout/blocks/polaraxis.jl @@ -485,7 +485,7 @@ function reset_limits!(po::PolarAxis) if po.radius_at_origin[] isa Real po.target_r0[] = po.radius_at_origin[] else - po.target_r0[] = rmin + po.target_r0[] = min(0.0, rmin) end # cleanup autolimits (0 width, rmin ≥ target_r0) diff --git a/src/makielayout/types.jl b/src/makielayout/types.jl index df21bc65c37..827026ec5f4 100644 --- a/src/makielayout/types.jl +++ b/src/makielayout/types.jl @@ -1668,7 +1668,7 @@ end # Limits & transformation settings - "The radial limits of the PolarAxis." + "The radial limits of the PolarAxis. " rlimits = (:origin, nothing) "The angle limits of the PolarAxis. (0.0, 2pi) results a full circle. (nothing, nothing) results in limits picked based on plot limits." thetalimits = (0.0, 2pi) @@ -1676,8 +1676,8 @@ end direction::Int = 1 "The angular offset for (1, 0) in the PolarAxis. This rotates the axis." theta_0::Float32 = 0f0 - "Sets the radius at the origin of the PolarAxis such that `r_out = r_in - radius_at_origin`. Can be set to `automatic` to match rmin." - radius_at_origin = 0f0 + "Sets the radius at the origin of the PolarAxis such that `r_out = r_in - radius_at_origin`. Can be set to `automatic` to match rmin. Note that this will affect the shape of plotted objects." + radius_at_origin = automatic "Controls the argument order of the Polar transform. If `theta_as_x = true` it is (θ, r), otherwise (r, θ)." theta_as_x::Bool = true "Controls whether `r < 0` (after applying `radius_at_origin`) gets clipped (true) or not (false)." From 60c8e24235703fdde4e730883d886df084e256b8 Mon Sep 17 00:00:00 2001 From: ffreyer Date: Sun, 19 Nov 2023 16:29:06 +0100 Subject: [PATCH 12/14] fix Makie tests --- src/makielayout/blocks/polaraxis.jl | 2 +- test/transformations.jl | 28 +++++++++++++++++++--------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/makielayout/blocks/polaraxis.jl b/src/makielayout/blocks/polaraxis.jl index 07ea43424cf..40dbcb9db5f 100644 --- a/src/makielayout/blocks/polaraxis.jl +++ b/src/makielayout/blocks/polaraxis.jl @@ -213,7 +213,7 @@ function setup_camera_matrices!(po::PolarAxis) setfield!(po, :target_rlims, Observable{Tuple{Float64, Float64}}((0.0, 10.0))) setfield!(po, :target_thetalims, Observable{Tuple{Float64, Float64}}((0.0, 2pi))) setfield!(po, :target_theta_0, map(identity, po.theta_0)) - setfield!(po, :target_r0, Observable{Float32}(0f0)) + setfield!(po, :target_r0, Observable{Float32}(po.radius_at_origin[] isa Real ? po.radius_at_origin[] : 0f0)) reset_limits!(po) onany((_, _) -> reset_limits!(po), po.blockscene, po.rlimits, po.thetalimits) diff --git a/test/transformations.jl b/test/transformations.jl index 6033d5f3381..ff3366a9737 100644 --- a/test/transformations.jl +++ b/test/transformations.jl @@ -88,39 +88,49 @@ end end @testset "Polar Transform" begin - tf = Makie.Polar(false) - @test tf.theta_as_x == false + tf = Makie.Polar() + @test tf.theta_as_x == true + @test tf.clip_r == true @test tf.theta_0 == 0.0 @test tf.direction == 1 @test tf.r0 == 0.0 - input = Point2f.(1:6, [0, pi/3, pi/2, pi, 2pi, 3pi]) - output = [r * Point2f(cos(phi), sin(phi)) for (r, phi) in input] - inv = Point2f.(1:6, mod.([0, pi/3, pi/2, pi, 2pi, 3pi], (0..2pi,))) + input = Point2f.([0, pi/3, pi/2, pi, 2pi, 3pi], 1:6) + output = [r * Point2f(cos(phi), sin(phi)) for (phi, r) in input] + inv = Point2f.(mod.([0, pi/3, pi/2, pi, 2pi, 3pi], (0..2pi,)), 1:6) @test apply_transform(tf, input) ≈ output @test apply_transform(Makie.inverse_transform(tf), output) ≈ inv - tf = Makie.Polar(false, pi/2) + tf = Makie.Polar(pi/2, 1, 0, false) + input = Point2f.(1:6, [0, pi/3, pi/2, pi, 2pi, 3pi]) output = [r * Point2f(cos(phi+pi/2), sin(phi+pi/2)) for (r, phi) in input] + inv = Point2f.(1:6, mod.([0, pi/3, pi/2, pi, 2pi, 3pi], (0..2pi,))) @test apply_transform(tf, input) ≈ output @test apply_transform(Makie.inverse_transform(tf), output) ≈ inv - tf = Makie.Polar(false, pi/2, -1) + tf = Makie.Polar(pi/2, -1, 0, false) output = [r * Point2f(cos(-phi-pi/2), sin(-phi-pi/2)) for (r, phi) in input] @test apply_transform(tf, input) ≈ output @test apply_transform(Makie.inverse_transform(tf), output) ≈ inv - tf = Makie.Polar(false, pi/2, -1, 0.5) + tf = Makie.Polar(pi/2, -1, 0.5, false) output = [(r - 0.5) * Point2f(cos(-phi-pi/2), sin(-phi-pi/2)) for (r, phi) in input] @test apply_transform(tf, input) ≈ output @test apply_transform(Makie.inverse_transform(tf), output) ≈ inv - tf = Makie.Polar(true) + tf = Makie.Polar(0, 1, 0, true) input = Point2f.([0, pi/3, pi/2, pi, 2pi, 3pi], 1:6) output = [r * Point2f(cos(phi), sin(phi)) for (phi, r) in input] inv = Point2f.(mod.([0, pi/3, pi/2, pi, 2pi, 3pi], (0..2pi,)), 1:6) @test apply_transform(tf, input) ≈ output @test apply_transform(Makie.inverse_transform(tf), output) ≈ inv + + tf = Makie.Polar(0, 1, 0, true, false) + input = Point2f.([0, pi/3, pi/2, pi, 2pi, 3pi], -6:-1) + output = [r * Point2f(cos(phi), sin(phi)) for (phi, r) in input] + inv = Point2f.(mod.([0, pi/3, pi/2, pi, 2pi, 3pi] .+ pi, (0..2pi,)), 6:-1:1) + @test apply_transform(tf, input) ≈ output + @test apply_transform(Makie.inverse_transform(tf), output) ≈ inv end @testset "Coordinate Systems" begin From 99d8c0c566be47e53052aee71ce004b80d06ec20 Mon Sep 17 00:00:00 2001 From: ffreyer Date: Sun, 19 Nov 2023 16:32:47 +0100 Subject: [PATCH 13/14] fix refimg test --- ReferenceTests/src/tests/examples2d.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReferenceTests/src/tests/examples2d.jl b/ReferenceTests/src/tests/examples2d.jl index 8cc85e7e075..fca5d6aff09 100644 --- a/ReferenceTests/src/tests/examples2d.jl +++ b/ReferenceTests/src/tests/examples2d.jl @@ -1218,7 +1218,7 @@ end @reference_test "Triplot with nonlinear transformation" begin f = Figure() - ax = PolarAxis(f[1, 1]) + ax = PolarAxis(f[1, 1], radius_at_origin = 0.0) points = Point2f[(phi, r) for r in 1:10 for phi in range(0, 2pi, length=36)[1:35]] tr = triplot!(ax, points) f From 3df665ea290834ad473911ae5c8e78c5a189d10e Mon Sep 17 00:00:00 2001 From: ffreyer Date: Sun, 19 Nov 2023 16:37:21 +0100 Subject: [PATCH 14/14] fix with custom data_limits instead --- ReferenceTests/src/tests/examples2d.jl | 2 +- src/basic_recipes/triplot.jl | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/ReferenceTests/src/tests/examples2d.jl b/ReferenceTests/src/tests/examples2d.jl index fca5d6aff09..8cc85e7e075 100644 --- a/ReferenceTests/src/tests/examples2d.jl +++ b/ReferenceTests/src/tests/examples2d.jl @@ -1218,7 +1218,7 @@ end @reference_test "Triplot with nonlinear transformation" begin f = Figure() - ax = PolarAxis(f[1, 1], radius_at_origin = 0.0) + ax = PolarAxis(f[1, 1]) points = Point2f[(phi, r) for r in 1:10 for phi in range(0, 2pi, length=36)[1:35]] tr = triplot!(ax, points) f diff --git a/src/basic_recipes/triplot.jl b/src/basic_recipes/triplot.jl index d2ccc94ffc6..917e3ff4265 100644 --- a/src/basic_recipes/triplot.jl +++ b/src/basic_recipes/triplot.jl @@ -239,3 +239,17 @@ function Makie.plot!(p::Triplot{<:Tuple{<:DelTri.Triangulation}}) strokecolor=p.strokecolor, marker=p.marker, visible=p.show_points, depth_shift=-3.0f-5) return p end + + +function data_limits(p::Triplot{<:Tuple{<:Vector{<:Point}}}) + if transform_func(p) isa Polar + # Because the Polar transform is handled explicitly we cannot rely + # on the default data_limits. (data limits are pre transform) + iter = (to_ndim(Point3f, p, 0f0) for p in p.converted[1][]) + limits_from_transformed_points(iter) + else + # First component is either another Voronoiplot or a poly plot. Both + # cases span the full limits of the plot + data_limits(p.plots[1]) + end +end \ No newline at end of file