Skip to content

Commit

Permalink
Activate GeoAxis Maps using a GeoMakie extension (#114)
Browse files Browse the repository at this point in the history
* add an extension to GeoMakie so that Tyler works

* Make this an actual extension

* Fix Map docstring to render correctly

* Remove unused import from Makie for compat with v0.22

* Set up axis with correct limits
  • Loading branch information
asinghvi17 authored Dec 23, 2024
1 parent e67cf5b commit 27dc936
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 14 deletions.
7 changes: 7 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
ThreadSafeDicts = "4239201d-c60e-5e0a-9702-85d713665ba7"
TileProviders = "263fe934-28e1-4ae9-998a-c2629c5fede6"

[weakdeps]
GeoMakie = "db073c08-6b98-4ee5-b6a4-5efafb3259c6"

[extensions]
TylerGeoMakieExt = ["GeoMakie"]

[compat]
ArchGDAL = "0.10"
Colors = "0.12, 0.13"
Expand All @@ -35,6 +41,7 @@ Extents = "0.1.2"
FileIO = "1"
GeoFormatTypes = "0.4"
GeoInterface = "1"
GeoMakie = "0.7.9"
GeometryBasics = "0.4, 0.5"
GeometryOps = "0.1"
HTTP = "1"
Expand Down
50 changes: 50 additions & 0 deletions ext/TylerGeoMakieExt/TylerGeoMakieExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
module TylerGeoMakieExt

using Tyler, GeoMakie

using LinearAlgebra, OrderedCollections

import Tyler: tile_reloader, create_tileplot!, update_tile_plot!,
Map, AbstractMap, ImageData, PlotConfig, DebugPlotConfig,
SimpleTiling, Halo2DTiling

using Tyler: to_rect


using Makie, Makie.GeometryBasics

using Makie: AbstractAxis, Mat

using Extents
using TileProviders, MapTiles

function Tyler.setup_axis!(axis::GeoAxis, ext_target, crs)
X = ext_target.X
Y = ext_target.Y

# Set the axis's limits
rect = Rect2f((X[1], Y[1]), (X[2] - X[1], Y[2] - Y[1]))
transf = GeoMakie.create_transform(axis.source[], crs)
transformed_limits = Makie.apply_transform(transf, rect)

tXmin, tYmin = transformed_limits.origin
tXmax, tYmax = transformed_limits.origin .+ transformed_limits.widths

axis.limits[] = (tXmin, tXmax, tYmin, tYmax)
Makie.reset_limits!(axis)

# axis.elements[:background].depth_shift[] = 0.1f0
# translate!(axis.elements[:background], 0, 0, -1000)
# axis.elements[:background].color = :transparent
# axis.xgridvisible = false
# axis.ygridvisible = false
return
end

# functions directly related to plotting
include("tile-plotting.jl")

# functions related to fetching tiles
include("tile-fetching.jl")

end
66 changes: 66 additions & 0 deletions ext/TylerGeoMakieExt/tile-fetching.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
function Tyler.tile_reloader(m::Map{GeoAxis})
axis = m.axis
throttled = Makie.Observables.throttle(0.2, axis.finallimits)
map_inverse_transform = lift(axis.scene, axis.dest) do dest
GeoMakie.create_transform(#= destination =# m.crs, #= source =# dest)
end

onany(axis.scene, map_inverse_transform, throttled; update=true) do ax2map, axis_finallimits
new_extent = Makie.apply_transform(ax2map, axis_finallimits)
Tyler.update_tiles!(m, new_extent)
return
end
end


# Here, the `area` has already been transformed to the tile CRS
function Tyler.get_tiles_for_area(m::Map{GeoAxis}, scheme::Halo2DTiling, area::Union{Rect,Extent})
area = typeof(area) <: Rect ? Extents.extent(area) : area
# `depth` determines the number of layers below the current
# layer to load. Tiles are downloaded in order from lowest to highest zoom.
depth = scheme.depth

# Calculate the zoom level
# TODO, also early return if too many tiles to plot?
ideal_zoom, zoom, approx_ntiles = Tyler.optimal_zoom(m, norm(widths(to_rect(area))))
m.zoom[] = zoom

# And the z layers we will plot
layer_range = max(Tyler.min_zoom(m), zoom - depth):zoom
# Get the tiles around the mouse first
xpos, ypos = Makie.mouseposition(m.axis.scene)
# transform the mouse position to tile CRS
# TODO: we should instead transform areas after they are calculated in the axis's CRS
xpos, ypos = Makie.apply_transform(GeoMakie.create_transform(m.crs, m.axis.dest[]), Point2f(xpos, ypos))
xspan = (area.X[2] - area.X[1]) * 0.01
yspan = (area.Y[2] - area.Y[1]) * 0.01
mouse_area = Extents.Extent(; X=(xpos - xspan, xpos + xspan), Y=(ypos - yspan, ypos + yspan))
# Make a halo around the mouse tile to load next, intersecting area so we don't download outside the plot
mouse_halo_area = Tyler.grow_extent(mouse_area, 10)
# Define a halo around the area to download last, so pan/zoom are filled already
halo_area = Tyler.grow_extent(area, scheme.halo) # We don't mind that the middle tiles are the same, the OrderedSet will remove them

# transform the areas to tile crs

# Define all the tiles in the order they will load in
background_areas = if Extents.intersects(mouse_halo_area, area)
mha = Extents.intersection(mouse_halo_area, area)
if Extents.intersects(mouse_area, area)
[Extents.intersection(mouse_area, area), mha, halo_area]
else
[mha, halo_area]
end
else
[halo_area]
end

foreground = OrderedSet{Tile}(MapTiles.TileGrid(area, zoom, m.crs))
background = OrderedSet{Tile}()
for z in layer_range
z == zoom && continue
for ext in background_areas
union!(background, MapTiles.TileGrid(ext, z, m.crs))
end
end
return foreground, background
end
53 changes: 53 additions & 0 deletions ext/TylerGeoMakieExt/tile-plotting.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
########################################
# PlotConfig #
########################################


function Tyler.create_tileplot!(config::PlotConfig, axis::GeoAxis, data::ImageData, bounds::Rect, tile_crs)
mini, maxi = extrema(bounds)
plot = GeoMakie.meshimage!(
axis,
(mini[1], maxi[1]), (mini[2], maxi[2]), data;
uv_transform=:rotl90,
inspectable=false,
reset_limits=false, # substitute for plotting directly to scene, since GeoMakie handles the CRS stuff
source = tile_crs[2], # tile_crs is a tuple of (tile, crs), we can pass the CRS directly to GeoMakie though
config.attributes...
)
return plot
end

function Tyler.update_tile_plot!(plot::GeoMakie.MeshImage, ::PlotConfig, axis::AbstractAxis, data::ImageData, bounds::Rect, tile_crs)
mini, maxi = extrema(bounds)
plot[1] = (mini[1], maxi[1])
plot[2] = (mini[2], maxi[2])
plot[3] = data
return
end


########################################
# DebugPlotConfig #
########################################

function create_tileplot!(config::DebugPlotConfig, axis::GeoAxis, data::ImageData, bounds::Rect, tile_crs)
plot = Makie.poly!(
axis,
bounds;
color=reverse(data; dims=1),
strokewidth=2,
strokecolor=:black,
inspectable=false,
stroke_depth_shift=-0.01f0,
reset_limits=false, # substitute for plotting directly to scene, since GeoMakie handles the CRS stuff
source = tile_crs[2], # tile_crs is a tuple of (tile, crs), we can pass the CRS directly to GeoMakie though
config.attributes...
)
return plot
end

function update_tile_plot!(plot::Makie.Poly, ::DebugPlotConfig, axis::GeoAxis, data::ImageData, bounds::Rect, tile_crs)
plot[1] = bounds
plot.color = reverse(data; dims=1)
return
end
2 changes: 1 addition & 1 deletion src/Tyler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ using GeometryBasics: GeometryBasics, GLTriangleFace, Point2f, Vec2f, Rect2f, Re
using HTTP: HTTP
using LRUCache: LRUCache, LRU
using MapTiles: MapTiles, Tile, TileGrid, web_mercator, wgs84, CoordinateReferenceSystemFormat
using Makie: Makie, Observable, Figure, Axis, LScene, RGBAf, on, isopen, meta, mesh!, translate!, scale!, Plot
using Makie: Makie, Observable, Figure, Axis, LScene, RGBAf, on, isopen, mesh!, translate!, scale!, Plot
using OrderedCollections: OrderedCollections, OrderedSet
using ThreadSafeDicts: ThreadSafeDicts, ThreadSafeDict
using TileProviders: TileProviders, AbstractProvider, geturl, min_zoom, max_zoom
Expand Down
26 changes: 13 additions & 13 deletions src/map.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,24 @@ When layering providers over each other with `Map(map::Map; ...)`, you can use `
# Arguments
-`extent`: the initial extent of the map, as a `GeometryBasics.Rect`
- `extent`: the initial extent of the map, as a `GeometryBasics.Rect`
or an `Extents.Extent` in the projection of `extent_crs`.
-`extent_crs`: Any `GeoFormatTypes` compatible crs, the default is wsg84.
- `extent_crs`: Any `GeoFormatTypes` compatible crs, the default is wsg84.
# Keywords
-`size`: The figure size.
-`figure`: an existing `Makie.Figure` object.
-`crs`: The providers coordinate reference system.
-`provider`: a TileProviders.jl `Provider`.
-`max_parallel_downloads`: limits the attempted simultaneous downloads, with a default of `16`.
-`cache_size_gb`: limits the cache for storing tiles, with a default of `5`.
-`fetching_scheme=Halo2DTiling()`: The tile fetching scheme. Can be SimpleTiling(), Halo2DTiling(), or Tiling3D().
-`scale`: a tile scaling factor. Low number decrease the downloads but reduce the resolution.
- `size`: The figure size.
- `figure`: an existing `Makie.Figure` object.
- `crs`: The providers coordinate reference system.
- `provider`: a TileProviders.jl `Provider`.
- `max_parallel_downloads`: limits the attempted simultaneous downloads, with a default of `16`.
- `cache_size_gb`: limits the cache for storing tiles, with a default of `5`.
- `fetching_scheme=Halo2DTiling()`: The tile fetching scheme. Can be SimpleTiling(), Halo2DTiling(), or Tiling3D().
- `scale`: a tile scaling factor. Low number decrease the downloads but reduce the resolution.
The default is `0.5`.
-`plot_config`: A `PlotConfig` object to change the way tiles are plotted.
-`max_zoom`: The maximum zoom level to display, with a default of `TileProviders.max_zoom(provider)`.
-`max_plots=400:` The maximum number of plots to keep displayed at the same time.
- `plot_config`: A `PlotConfig` object to change the way tiles are plotted.
- `max_zoom`: The maximum zoom level to display, with a default of `TileProviders.max_zoom(provider)`.
- `max_plots=400:` The maximum number of plots to keep displayed at the same time.
"""
struct Map{Ax<:Makie.AbstractAxis} <: AbstractMap
provider::AbstractProvider
Expand Down

0 comments on commit 27dc936

Please sign in to comment.