Title: | Add Inset Panels to Maps |
---|---|
Description: | Helper to add insets based on geom_sf() from 'ggplot2'. This package gives you a drop-in replacement for geom_sf() that supports adding a zoomed inset map without having to create and embed a separate plot. |
Authors: | Carl Suster [aut, cre] , Western Sydney Local Health District, NSW Health [cph] |
Maintainer: | Carl Suster <[email protected]> |
License: | MIT + file LICENSE |
Version: | 0.3.0.9000 |
Built: | 2024-11-09 05:08:59 UTC |
Source: | https://github.com/cidm-ph/ggmapinset |
This package helps with making zoomed map insets. See geom_sf_inset()
.
Maintainer: Carl Suster [email protected] (ORCID)
Other contributors:
Western Sydney Local Health District, NSW Health [copyright holder]
Useful links:
Report bugs at https://github.com/cidm-ph/ggmapinset/issues
For plotting, use geom_sf_inset()
instead. This helper is intended to be used when
implementing custom geometries based on geom_sf_inset()
so that they can provide
parameters to control the inset.
build_sf_inset_layers( data, mapping, stat, position, show.legend, inherit.aes, params, inset, map_base = "normal", map_inset = "auto" )
build_sf_inset_layers( data, mapping, stat, position, show.legend, inherit.aes, params, inset, map_base = "normal", map_inset = "auto" )
data |
The data to be displayed in this layer. There are three options: If A A |
mapping |
Set of aesthetic mappings created by |
stat |
The statistical transformation to use on the data for this layer.
When using a
|
position |
A position adjustment to use on the data for this layer. This
can be used in various ways, including to prevent overplotting and
improving the display. The
|
show.legend |
logical. Should this layer be included in the legends?
|
inherit.aes |
If |
params |
Additional parameters to the |
inset |
Inset configuration; see |
map_base |
Controls the layer with the base map. Possible values are
|
map_inset |
Controls the layer with the inset map. Possible values are
|
A ggplot
layer, or a pair of layers.
my_custom_geom <- function(mapping = ggplot2::aes(), data = NULL, stat = "my_custom_stat", position = "identity", ..., inset = NA, map_base = "normal", map_inset = "auto", na.rm = TRUE, inherit.aes = TRUE) { params <- rlang::list2(na.rm = na.rm, ...) build_sf_inset_layers(data = data, mapping = mapping, stat = stat, position = position, show.legend = show.legend, inherit.aes = inherit.aes, params = params, inset = inset, map_base = map_base, map_inset = map_inset) }
my_custom_geom <- function(mapping = ggplot2::aes(), data = NULL, stat = "my_custom_stat", position = "identity", ..., inset = NA, map_base = "normal", map_inset = "auto", na.rm = TRUE, inherit.aes = TRUE) { params <- rlang::list2(na.rm = na.rm, ...) build_sf_inset_layers(data = data, mapping = mapping, stat = stat, position = position, show.legend = show.legend, inherit.aes = inherit.aes, params = params, inset = inset, map_base = map_base, map_inset = map_inset) }
The configuration returned by this function will normally be passed to the
coordinate system via coord_sf_inset()
. Insets can either be circular
(if radius
is specified) or rectangular (if hwidth
and
optionally hheight
are specified).
configure_inset( centre, scale = NULL, translation = NULL, radius = NULL, hwidth = NULL, hheight = NULL, units = "km", crs_working = NULL )
configure_inset( centre, scale = NULL, translation = NULL, radius = NULL, hwidth = NULL, hheight = NULL, units = "km", crs_working = NULL )
centre |
Coordinates of the inset centre. Ideally this should be an
|
scale |
Zoom scale: values larger than one will make the inset bigger. |
translation |
Translation (shift) of the inset relative to the centre.
This can be an |
radius |
Radius of the inset circle in the units of |
hwidth |
Half width of the inset in the units of |
hheight |
Half height of the inset in the units of |
units |
Base length unit (e.g. |
crs_working |
The coordinate reference system to use internally when applying the transformations. See Details. |
The default crs_working
uses the equidistant cylindrical coordinate
reference system with the latitude of true scale set to match the latitude of
centre
. This ensures that circular insets will appear circular in most
cases since the projection is not distorted near the centre. The geometries
are converted to this CRS for the inset transformation and constructing the
inset frame, and are converted back to the CRS of centre
at the end.
The default units are kilometres but can be changed with units
instead of specifying the whole projection. The possible values for
units
are
those understood by proj
:
"mm"
: millimetre
"cm"
: centimetre
"m"
: metre
"ft"
: foot
"us-ft"
: US survey foot
"fath"
: fathom
"kmi"
: nautical mile
"us-ch"
: US survey chain
"us-mi"
: US survey mile
"km"
: kilometre
"ind-ft"
: Indian foot (1937)
"ind-yd"
: Indian yard (1937)
"mi"
: Statute mile
"yd"
: yard
"ch"
: chain
"link"
: link
"dm"
: decimeter
"in"
: inch
"ind-ch"
: Indian chain
"us-in"
: US survey inch
"us-yd"
: US survey yard
An inset configuration object of class inset_config
.
library(sf) # circular inset with a 2x enlargement cfg <- configure_inset( centre = st_sfc(st_point(c(-82, 35)), crs = 4326), scale = 2, translation = c(70, -180), radius = 50, units = "mi")
library(sf) # circular inset with a 2x enlargement cfg <- configure_inset( centre = st_sfc(st_point(c(-82, 35)), crs = 4326), scale = 2, translation = c(70, -180), radius = 50, units = "mi")
This allows a default inset configuration to be provided to avoid having to repeat it for each layer. Any layer that is inset-aware can use this as the default configuration if none is specifically provided to that layer. This coord also expands the axis limits to include the inset area.
coord_sf_inset(inset, ...)
coord_sf_inset(inset, ...)
inset |
Inset configuration; see |
... |
Arguments passed to |
A ggplot coordinate object to be added to a plot.
library(ggplot2) nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE) ggplot(nc) + geom_sf_inset(aes(fill = AREA)) + geom_inset_frame() + coord_sf_inset(inset = configure_inset( centre = sf::st_sfc(sf::st_point(c(-80, 35.5)), crs = 4326), scale = 1.5, translation = c(-50, -140), radius = 50, units = "mi"))
library(ggplot2) nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE) ggplot(nc) + geom_sf_inset(aes(fill = AREA)) + geom_inset_frame() + coord_sf_inset(inset = configure_inset( centre = sf::st_sfc(sf::st_point(c(-80, 35.5)), crs = 4326), scale = 1.5, translation = c(-50, -140), radius = 50, units = "mi"))
The frame is computed from the inset configuration, so any data
passed
to this layer is ignored. The frame is an sf object consisting of three features:
the source area, the target area (a scaled and translated version of the source
area), and the connecting/burst lines.
geom_inset_frame( mapping = ggplot2::aes(), data = NULL, stat = "sf_inset", position = "identity", ..., inset = NA, na.rm = FALSE, source.aes = list(), target.aes = list(), lines.aes = list(), show.legend = NA, inherit.aes = FALSE )
geom_inset_frame( mapping = ggplot2::aes(), data = NULL, stat = "sf_inset", position = "identity", ..., inset = NA, na.rm = FALSE, source.aes = list(), target.aes = list(), lines.aes = list(), show.legend = NA, inherit.aes = FALSE )
mapping , data , stat , position , na.rm , show.legend , inherit.aes , ...
|
See |
inset |
Inset configuration; see |
source.aes , target.aes , lines.aes
|
Override the aesthetics of the inset source, target, and lines respectively. The value should be a list named by the aesthetics, and the values should be scalars of length one. |
Burst lines for circular insets are bitangenets (tangent to both the source and target circles) or absent if the circles are nested. Burst lines for rectangular insets are the shortest line from each corner of the source rectangle to any corner of the target rectangle, after excluding any such lines that intersect either rectangle or each other. When the burst lines are absent due to geometrical constraints, there will still be a corresponding (empty) feature in the frame layer's data.
A ggplot layer holding the inset frame.
The frame cannot be drawn without another sf layer that contains data due to
a limitation of the ggplot layout evaluation. Attempting to plot a frame by
itself will result in the error:
"Scale limits cannot be mapped onto spatial coordinates in coord_sf()
".
library(ggplot2) nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE) ggplot(nc) + geom_sf_inset() + geom_inset_frame( source.aes = list(fill = "red", alpha = 0.2, linewidth = 0), target.aes = list(colour = "blue"), lines.aes = list(linetype = 2, linewidth = 2) ) + coord_sf_inset(inset = configure_inset( centre = sf::st_sfc(sf::st_point(c(-82, 35)), crs = 4326), scale = 4, translation = c(0, -260), radius = 50, units = "mi")) make_demo <- function(...) { centroid <- sf::st_centroid(nc$geometry[[21]]) |> sf::st_sfc(crs = sf::st_crs(nc)) ggplot(nc) + geom_sf(fill = "grey95", colour = "grey85") + # For a filled frame, we want to interleave it between the base layer # (above this line) and the target layer (below the following line). geom_inset_frame(target.aes = list(fill = "white")) + geom_sf_inset(map_base = "none") + coord_sf_inset(inset = configure_inset(centre = centroid, ...)) + theme_void() } # the lines connecting the frames vary depending on relative size and position: make_demo(scale = 3, radius = 50, translation = c(-200, -200)) make_demo(scale = 3, radius = 50, translation = c(-100, -100)) make_demo(scale = 3, radius = 50, translation = c(0, 0)) make_demo(scale = 0.5, radius = 50, translation = c(0, 0)) make_demo(scale = 3, hwidth = 50, hheight = 40, translation = c(-300, 0)) make_demo(scale = 3, hwidth = 50, hheight = 40, translation = c(-250, -200)) make_demo(scale = 3, hwidth = 50, hheight = 40, translation = c(-150, -100)) make_demo(scale = 3, hwidth = 50, hheight = 40, translation = c(0, 0)) make_demo(scale = 0.5, hwidth = 50, hheight = 40, translation = c(0, 0))
library(ggplot2) nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE) ggplot(nc) + geom_sf_inset() + geom_inset_frame( source.aes = list(fill = "red", alpha = 0.2, linewidth = 0), target.aes = list(colour = "blue"), lines.aes = list(linetype = 2, linewidth = 2) ) + coord_sf_inset(inset = configure_inset( centre = sf::st_sfc(sf::st_point(c(-82, 35)), crs = 4326), scale = 4, translation = c(0, -260), radius = 50, units = "mi")) make_demo <- function(...) { centroid <- sf::st_centroid(nc$geometry[[21]]) |> sf::st_sfc(crs = sf::st_crs(nc)) ggplot(nc) + geom_sf(fill = "grey95", colour = "grey85") + # For a filled frame, we want to interleave it between the base layer # (above this line) and the target layer (below the following line). geom_inset_frame(target.aes = list(fill = "white")) + geom_sf_inset(map_base = "none") + coord_sf_inset(inset = configure_inset(centre = centroid, ...)) + theme_void() } # the lines connecting the frames vary depending on relative size and position: make_demo(scale = 3, radius = 50, translation = c(-200, -200)) make_demo(scale = 3, radius = 50, translation = c(-100, -100)) make_demo(scale = 3, radius = 50, translation = c(0, 0)) make_demo(scale = 0.5, radius = 50, translation = c(0, 0)) make_demo(scale = 3, hwidth = 50, hheight = 40, translation = c(-300, 0)) make_demo(scale = 3, hwidth = 50, hheight = 40, translation = c(-250, -200)) make_demo(scale = 3, hwidth = 50, hheight = 40, translation = c(-150, -100)) make_demo(scale = 3, hwidth = 50, hheight = 40, translation = c(0, 0)) make_demo(scale = 0.5, hwidth = 50, hheight = 40, translation = c(0, 0))
These geoms are wrappers around ggplot2::geom_sf()
and its relatives that
assist with creating map insets.
In many cases all that is needed is to use coord_sf_inset()
with configure_inset()
to configure the location and transformation of the inset, and then replace the
sf-related geoms with their _inset
counterparts.
Use geom_inset_frame()
to add a frame around the inset that connects it to the main map.
geom_sf_inset( mapping = ggplot2::aes(), data = NULL, stat = "sf_inset", position = "identity", ..., inset = NA, map_base = "normal", map_inset = "auto", na.rm = TRUE, show.legend = NA, inherit.aes = TRUE ) geom_sf_text_inset( mapping = aes(), data = NULL, stat = "sf_coordinates_inset", position = "identity", ..., where = "inset", parse = FALSE, check_overlap = FALSE, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, fun.geometry = NULL ) geom_sf_label_inset( mapping = aes(), data = NULL, stat = "sf_coordinates_inset", position = "identity", ..., where = "inset", parse = FALSE, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, fun.geometry = NULL ) stat_sf_inset( mapping = ggplot2::aes(), data = NULL, geom = "sf_inset", position = "identity", ..., inset = NA, na.rm = TRUE, show.legend = NA, inherit.aes = TRUE )
geom_sf_inset( mapping = ggplot2::aes(), data = NULL, stat = "sf_inset", position = "identity", ..., inset = NA, map_base = "normal", map_inset = "auto", na.rm = TRUE, show.legend = NA, inherit.aes = TRUE ) geom_sf_text_inset( mapping = aes(), data = NULL, stat = "sf_coordinates_inset", position = "identity", ..., where = "inset", parse = FALSE, check_overlap = FALSE, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, fun.geometry = NULL ) geom_sf_label_inset( mapping = aes(), data = NULL, stat = "sf_coordinates_inset", position = "identity", ..., where = "inset", parse = FALSE, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, fun.geometry = NULL ) stat_sf_inset( mapping = ggplot2::aes(), data = NULL, geom = "sf_inset", position = "identity", ..., inset = NA, na.rm = TRUE, show.legend = NA, inherit.aes = TRUE )
mapping , data , stat , geom , position , na.rm , show.legend , inherit.aes , ...
|
See |
inset |
Inset configuration; see |
map_base |
Controls the layer with the base map. Possible values are
|
map_inset |
Controls the layer with the inset map. Possible values are
|
where |
Specifies how the text position interacts with the inset.
|
parse |
If |
check_overlap |
If |
fun.geometry |
A function that takes a |
Internally this works by creating two layers: one for the base map, and one
for the inset. These can be separately controlled by the map_base
and
map_inset
parameters. If inset
is not specified, this geom will instead
behave like ggplot2::geom_sf()
.
When an inset is configured, the default creates both base and inset layers using the same aesthetic mapping and params:
geom_sf_inset(...)
You can alternatively specify the two layers separately:
# draw the base map only (both versions are equivalent): geom_sf(...) geom_sf_inset(..., map_inset = "none") # separately, draw the inset map only: geom_sf_inset(..., map_base = "none")
stat_sf_inset()
works the same ggplot2::stat_sf()
except that it also
expands the axis limits to account for the inset area.
A ggplot layer similar to ggplot2::geom_sf()
but transformed according to the
inset configuration.
library(ggplot2) nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE) ggplot(nc) + geom_sf_inset(aes(fill = AREA)) + geom_inset_frame() + coord_sf_inset(inset = configure_inset( centre = sf::st_sfc(sf::st_point(c(-80, 35.5)), crs = sf::st_crs(nc)), scale = 1.5, translation = c(-50, -140), radius = 50, units = "mi"))
library(ggplot2) nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE) ggplot(nc) + geom_sf_inset(aes(fill = AREA)) + geom_inset_frame() + coord_sf_inset(inset = configure_inset( centre = sf::st_sfc(sf::st_point(c(-80, 35.5)), crs = sf::st_crs(nc)), scale = 1.5, translation = c(-50, -140), radius = 50, units = "mi"))
This is a helper for implementing inset-aware ggplot layers. If the inset
is
missing (NA
) then the default inset configuration is retrieved from the coord.
get_inset_config(inset, coord)
get_inset_config(inset, coord)
inset |
Inset passed in as a param to the layer |
coord |
Coord object for the plot |
Inset configuration or NULL
# defining a new geom deriving from geom_sf() GeomCustom <- ggplot2::ggproto("GeomCustom", ggplot2::GeomSf, draw_panel = function(self, data, panel_params, coord, inset = NA) { inset <- get_inset_config(inset, coord) # do something with the inset ... # note that this example doesn't pass on the remaining geom_sf params but # in real usage you would probably want to do that ggplot2::ggproto_parent(ggplot2::GeomSf, self)$draw_panel(data, panel_params, coord) }, )
# defining a new geom deriving from geom_sf() GeomCustom <- ggplot2::ggproto("GeomCustom", ggplot2::GeomSf, draw_panel = function(self, data, panel_params, coord, inset = NA) { inset <- get_inset_config(inset, coord) # do something with the inset ... # note that this example doesn't pass on the remaining geom_sf params but # in real usage you would probably want to do that ggplot2::ggproto_parent(ggplot2::GeomSf, self)$draw_panel(data, panel_params, coord) }, )
This dataset is derived from the NSW Arbovirus Surveillance and Mosquito Monitoring program. The program monitors mosquito-borne diseases in the state of New South Wales, Australia. A number of mosquito traps are managed by the program during the spring to autumn months when mosquitoes are active.
mozzies_nsw2301
mozzies_nsw2301
Data frame with the following fields:
Location of the mosquito trap
Date of the end of the week of observation
Mosquito species counted, or "total" for the total count
Binned mosquito abundance
Category of the site
Latitude of trap in WGS 84 coordinates
Longitude of trap in WGS 84 coordinates
Each week traps are collected and the mosquito species are identified and counted. This is analysed alongside climate conditions, and arbovirus detections in the traps to inform public health management of human disease risk from arboviruses in NSW. This dataset includes the mosquito abundance tables for January 2023. Additional context and analysis can be found in the original report published by NSW Health.
The trap locations are classified as inland or coastal (since the species found will depend on the environmental conditions). A separate group of sites are labelled as being in the Sydney region (i.e. with the highest human population density).
The counts are binned with the following definition:
NA
No observation
< 50
50 - 100
101 - 1,000
1,001 - 10,000
> 10,000
Surveillance and Risk Unit, Environmental Health Branch, Health Protection NSW, NSW Health. "NSW Arbovirus Surveillance and Mosquito Monitoring 2022-2023; Weekly Update: Week ending 25 February 2023 (Report Number 19)" https://www.health.nsw.gov.au/environment/pests/vector/Publications/nswasp-weekly-report-2023-02-25.pdf, accessed 15 January 2024.
The original dataset is published under the Creative Commons Attribution 4.0 licence © State of New South Wales NSW Ministry of Health 2023.
Reduce spatial data to coordinates in the same way as stat_sf_coordinates()
.
The result can then be used by geom_sf()
or
geom_sf_inset()
or any geom that needs x
and
y
aesthetics.
stat_sf_coordinates_inset( mapping = ggplot2::aes(), data = NULL, geom = "point", position = "identity", ..., inset = NA, fun.geometry = NULL, where = "inset", na.rm = TRUE, show.legend = NA, inherit.aes = TRUE )
stat_sf_coordinates_inset( mapping = ggplot2::aes(), data = NULL, geom = "point", position = "identity", ..., inset = NA, fun.geometry = NULL, where = "inset", na.rm = TRUE, show.legend = NA, inherit.aes = TRUE )
mapping , data , geom , position , na.rm , show.legend , inherit.aes , ...
|
|
inset |
Inset configuration; see |
fun.geometry |
A function that takes a |
where |
Specifies how the text position interacts with the inset.
|
A plot layer
The sf geometry column containing spatial features
X dimension of the simple feature
Y dimension of the simple feature
X dimension of the simple feature after inset transformation
Y dimension of the simple feature after inset transformation
logical indicating points inside the inset viewport
1 for points outside the inset, otherwise the configured inset scale parameter
library(ggplot2) nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE) ggplot(nc) + geom_sf_inset() + geom_inset_frame() + geom_sf_text(aes(x = after_stat(x_inset), y = after_stat(y_inset), label = NAME), stat = "sf_coordinates_inset") + coord_sf_inset(inset = configure_inset( centre = sf::st_sfc(sf::st_point(c(-80, 35.5)), crs = 4326), scale = 1.5, translation = c(-50, -140), radius = 50, units = "mi"))
library(ggplot2) nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE) ggplot(nc) + geom_sf_inset() + geom_inset_frame() + geom_sf_text(aes(x = after_stat(x_inset), y = after_stat(y_inset), label = NAME), stat = "sf_coordinates_inset") + coord_sf_inset(inset = configure_inset( centre = sf::st_sfc(sf::st_point(c(-80, 35.5)), crs = 4326), scale = 1.5, translation = c(-50, -140), radius = 50, units = "mi"))
This helper operates on an sf object to scale and translate its geometry according to the inset specification.
transform_to_inset(x, inset)
transform_to_inset(x, inset)
x |
Spatial data frame or other sf object; see |
inset |
Inset configuration; see |
A copy of x
with the geometry replaced by the transformed version.
library(sf) nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE) cfg <- configure_inset( centre = st_sfc(st_point(c(-82, 35)), crs = 4326), scale = 2, translation = c(10, -60), radius = 50, units = "mi") transform_to_inset(nc, cfg)
library(sf) nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE) cfg <- configure_inset( centre = st_sfc(st_point(c(-82, 35)), crs = 4326), scale = 2, translation = c(10, -60), radius = 50, units = "mi") transform_to_inset(nc, cfg)