diff --git a/src/GeoMakie.jl b/src/GeoMakie.jl index 7d82806f..8a520cdc 100644 --- a/src/GeoMakie.jl +++ b/src/GeoMakie.jl @@ -45,7 +45,6 @@ const Text = Makie.Text Base.convert(::Type{Rect{N, Float64}}, x::Rect{N}) where N = Rect{N, Float64}(x) include("makie_piracy.jl") -include("triangulation3d.jl") include("geojson.jl") # GeoJSON/GeoInterface support include("conversions.jl") include("data.jl") @@ -61,6 +60,8 @@ include("makie-axis.jl") include("mesh_image.jl") include("linesplitting.jl") +include("triangulation3d.jl") + @reexport using Colors, Makie export Proj diff --git a/src/geoaxis.jl b/src/geoaxis.jl index 2d0c5036..c6707317 100644 --- a/src/geoaxis.jl +++ b/src/geoaxis.jl @@ -701,22 +701,42 @@ function Makie.initialize_block!(axis::GeoAxis) fonts = theme(axis.blockscene, :fonts) # Finally calculate protrusions and report all bounding boxes # to the layout system. - approx_x_protrusion = map(axis.blockscene, axis.yticklabelfont, axis.yticklabelsize, lat_text) do font, size, lat_text - max_height = 0.0f0 - for str in lat_text - bb = Makie.text_bb(str, to_font(fonts, font), size) - max_height = max(max_height, widths(bb)[2]) + approx_x_protrusion = map( + axis.blockscene, + axis.yticklabelfont, axis.yticklabelsize, axis.yticklabelpad, lat_text, axis.yticklabelsvisible + ) do ticklabel_font, ticklabel_size, ticklabel_pad, text, ticklabelsvisible + ret = 0.0f0 + + if ticklabelsvisible + max_height = 0.0 + for str in text + bb = Makie.text_bb(str, Makie.to_font(fonts, ticklabel_font), ticklabel_size) + max_height = max(max_height, widths(bb)[2]) + end + ret += max_height + ticklabel_pad end - return max_height + + return ret end - approx_y_protrusion = map(axis.blockscene, axis.yticklabelfont, axis.yticklabelsize, lon_text) do font, size, lon_text - max_width = 0.0f0 - for str in lon_text - bb = Makie.text_bb(str, to_font(fonts, font), size) - max_width = max(max_width, widths(bb)[1]) + approx_y_protrusion = map( + axis.blockscene, + axis.xticklabelfont, axis.xticklabelsize, axis.xticklabelpad, lon_text, axis.xticklabelsvisible, + ) do ticklabel_font, ticklabel_size, ticklabel_pad, text, ticklabelsvisible + + ret = 0.0f0 + + if ticklabelsvisible + max_width = 0.0 + for str in text + bb = Makie.text_bb(str, Makie.to_font(fonts, ticklabel_font), ticklabel_size) + max_width = max(max_width, widths(bb)[1]) + end + ret += max_width + ticklabel_pad end - return max_width + + return ret + end elements = Dict{Symbol,Any}() @@ -773,7 +793,8 @@ function Makie.initialize_block!(axis::GeoAxis) xaxis = (; protrusion=approx_y_protrusion) map!(compute_protrusions, axis.blockscene, axis.layoutobservables.protrusions, axis.title, axis.titlesize, axis.titlegap, axis.titlevisible, - xaxis.protrusion, yaxis.protrusion, + xaxis.protrusion, + yaxis.protrusion, axis.subtitle, axis.subtitlevisible, axis.subtitlesize, axis.subtitlegap, axis.titlelineheight, axis.subtitlelineheight, subtitlet, titlet) @@ -837,12 +858,17 @@ function Makie.plot!(axis::GeoAxis, plot::Makie.AbstractPlot) # actually plot Makie.plot!(axis.scene, plot) - # some area-like plots basically always look better if they cover the whole plot area. - # adjust the limit margins in those cases automatically. - Makie.needs_tight_limits(plot) && reset_limits && Makie.tightlimits!(axis) - if Makie.is_open_or_any_parent(axis.scene) && reset_limits - Makie.reset_limits!(axis) + # reset limits ONLY IF the user has not said otherwise + if reset_limits + # some area-like plots basically always look better if they cover the whole plot area. + # adjust the limit margins in those cases automatically. + Makie.needs_tight_limits(plot) && Makie.tightlimits!(axis) + + if Makie.is_open_or_any_parent(axis.scene) + Makie.reset_limits!(axis) + end end + return plot end @@ -856,7 +882,10 @@ function Makie.MakieCore._create_plot!(F, attributes::Dict, ax::GeoAxis, args... return plot end -# TODO implement -Makie.tightlimits!(axis::GeoAxis) = nothing + +# ## Makie generic axis/block API + +# this is generally false, but I want to deviate from that here. +Makie.needs_tight_limits(axis::GeoAxis, ::Surface) = true Makie.get_scene(ga::GeoAxis) = ga.scene diff --git a/src/makie-axis.jl b/src/makie-axis.jl index a8a9f1ea..49e5f5fb 100644 --- a/src/makie-axis.jl +++ b/src/makie-axis.jl @@ -16,10 +16,14 @@ function axis_setup!(axis::GeoAxis) setfield!(axis, :targetlimits, targetlimits) setfield!(axis, :finallimits, finallimits) topscene = axis.blockscene + scenearea = Makie.sceneareanode!(axis.layoutobservables.computedbbox, finallimits, axis.aspect) + scene = Scene(topscene, viewport=scenearea) - axis.scene = scene setfield!(scene, :float32convert, Makie.Float32Convert()) + + axis.scene = scene + onany(scene, scene.transformation.transform_func, finallimits, axis.xreversed, axis.yreversed) do transform_func, finallimits, xreversed, yreversed Makie.update_axis_camera(scene, transform_func, finallimits, xreversed, yreversed) end @@ -565,3 +569,44 @@ function Makie.Legend(fig_or_scene, axis::GeoAxis, title = nothing; merge = fals isempty(plots) && error("There are no plots with labels in the given axis that can be put in the legend. Supply labels to plotting functions like `plot(args...; label = \"My label\")`") Makie.Legend(fig_or_scene, plots, labels, title; kwargs...) end + + + +# Taken from makielayout/helpers.jl + +""" + tightlimits!(la::Axis) + +Sets the autolimit margins to zero on all sides. +""" +function Makie.tightlimits!(la::GeoAxis) + la.xautolimitmargin = (0, 0) + la.yautolimitmargin = (0, 0) + reset_limits!(la) +end + +function Makie.tightlimits!(la::GeoAxis, sides::Union{Left, Right, Bottom, Top}...) + for s in sides + Makie.tightlimits!(la, s) + end +end + +function Makie.tightlimits!(la::GeoAxis, ::Left) + la.xautolimitmargin = Base.setindex(la.xautolimitmargin[], 0.0, 1) + autolimits!(la) +end + +function Makie.tightlimits!(la::GeoAxis, ::Right) + la.xautolimitmargin = Base.setindex(la.xautolimitmargin[], 0.0, 2) + autolimits!(la) +end + +function Makie.tightlimits!(la::GeoAxis, ::Bottom) + la.yautolimitmargin = Base.setindex(la.yautolimitmargin[], 0.0, 1) + autolimits!(la) +end + +function Makie.tightlimits!(la::GeoAxis, ::Top) + la.yautolimitmargin = Base.setindex(la.yautolimitmargin[], 0.0, 2) + autolimits!(la) +end diff --git a/src/makie_piracy.jl b/src/makie_piracy.jl index 272b9056..9075ba11 100644 --- a/src/makie_piracy.jl +++ b/src/makie_piracy.jl @@ -50,3 +50,10 @@ function Makie.transform_bbox(scenelike, lims::Rect{N, T}) where {N, T} end =# + +# `needs_tight_limits`` should dispatch on axes too +# because what looks bad on one axis (regular Axis) +# will look good on a GeoAxis +# and vice versa + +Makie.needs_tight_limits(axis::Makie.AbstractAxis, plot::Makie.Plot) = Makie.needs_tight_limits(plot) diff --git a/src/mesh_image.jl b/src/mesh_image.jl index fc27d662..d581bd2e 100644 --- a/src/mesh_image.jl +++ b/src/mesh_image.jl @@ -51,6 +51,9 @@ Makie.conversion_trait(::Type{<: MeshImage}) = Makie.ImageLike() # There really is no difference between this and Image, # except the implementation under the hood. +# We also define that `meshimage` needs tight limits when plotted... +Makie.needs_tight_limits(::MeshImage) = true + # This is the recipe implementation. function Makie.plot!(plot::MeshImage) @@ -123,7 +126,7 @@ function Makie.plot!(plot::MeshImage) color = plot.converted[3], # pass on the color directly MakieCore.colormap_attributes(plot)..., # pass on all colormap attributes shading = NoShading, # - transformation = Transformation( + transformation = Makie.Transformation( plot.transformation; # connect up the model matrix to the parent's model matrix transform_func = identity # do NOT connect the transform func, since we've already done that. identity provides a custom transform func, while `nothing` signals that you don't care. ), diff --git a/test/geoaxis.jl b/test/geoaxis.jl index 03ea7335..5b283f36 100644 --- a/test/geoaxis.jl +++ b/test/geoaxis.jl @@ -46,4 +46,44 @@ end @test_nowarn contourf!(ax, lons, lats, field) end +end + +@testset "Protrusions are correctly updated when visible = false" begin + + f, a, p = meshimage(-180..180, -90..90, GeoMakie.earth() |> rotr90; figure = (; figure_padding = 0), axis = (; type = GeoAxis, dest = "+proj=longlat +type=crs")) + + w = widths(a.finallimits[]) + colsize!(f.layout, 1, Aspect(1, w[1] / w[2])) + resize_to_layout!(f) + + Makie.update_state_before_display!(f) + original_prots = a.layoutobservables.protrusions[] + Makie.hidedecorations!(a) + Makie.update_state_before_display!(f) + new_prots = a.layoutobservables.protrusions[] + + @test new_prots.left == 0 + @test new_prots.right == 0 + @test new_prots.top == 0 + @test new_prots.bottom == 0 + +end + +@testset "Aspect ratio is equal to Axis with DataAspect" begin + # Create two figures, one with regular axis and one with geoaxis + # the transformation in both cases is the identity + f1, a1, p1 = meshimage(-180..180, -90..90, GeoMakie.earth() |> rotr90; figure = (; figure_padding = 0), axis = (; aspect = DataAspect())); + f2, a2, p2 = meshimage(-180..180, -90..90, GeoMakie.earth() |> rotr90; figure = (; figure_padding = 0), axis = (; type = GeoAxis, dest = "+proj=longlat +type=crs")); + + Makie.tightlimits!(a1) + hidedecorations!(a1) + hidedecorations!(a2) + + Makie.update_state_before_display!(f1) + Makie.update_state_before_display!(f2) + + Makie.resize_to_layout!(f1) + Makie.resize_to_layout!(f2) + + @test a1.scene.viewport[] == a2.scene.viewport[] end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index 250d7f5d..e32ab082 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -9,9 +9,9 @@ Makie.set_theme!(Theme( @testset "GeoMakie" begin - @testset "MeshImage" begin - include("meshimage.jl") - end + @testset "MeshImage" include("meshimage.jl") + + @testset "GeoAxis" include("geoaxis.jl") @testset "Basics" begin lons = -180:180 @@ -37,26 +37,4 @@ Makie.set_theme!(Theme( @test GeoMakie.coastlines(ga)[] isa AbstractVector end - @testset "Legend" begin - fig = Figure() - ga = GeoAxis(fig[1, 1]) - lines!(ga, 1:10, 1:10; label = "series 1") - scatter!(ga, 1:19, 2:20; label= "series 2") - @test_nowarn Legend(fig[1, 2], ga) - fig - end - - @testset "Plotlists get transformed" begin - fig = Figure() - ax = GeoAxis(fig[1,1]) - plotspecs = [S.Lines(Point2f.(1:10, 1:10)), S.Scatter(Point2f.(1:10, 1:10))] - - p1 = plotlist!(ax, plotspecs) - - @test p1.transformation.transform_func[] isa GeoMakie.Proj.Transformation - - for plot in p1.plots - @test plot.transformation.transform_func[] isa GeoMakie.Proj.Transformation - end - end end