Skip to content
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