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

Fix GeoAxis size and protrusions #298

Merged
merged 10 commits into from
Dec 12, 2024
3 changes: 2 additions & 1 deletion src/GeoMakie.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -61,6 +60,8 @@ include("makie-axis.jl")
include("mesh_image.jl")
include("linesplitting.jl")

include("triangulation3d.jl")

@reexport using Colors, Makie
export Proj

Expand Down
69 changes: 49 additions & 20 deletions src/geoaxis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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}()
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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

Expand All @@ -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
47 changes: 46 additions & 1 deletion src/makie-axis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
7 changes: 7 additions & 0 deletions src/makie_piracy.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
5 changes: 4 additions & 1 deletion src/mesh_image.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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.
),
Expand Down
40 changes: 40 additions & 0 deletions test/geoaxis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
28 changes: 3 additions & 25 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Loading