Plot a bounding box around a sf object using ggplot2 - r

I would like to plot a world map (sf object) with a bounding box around the map. The bounding box would is supposed to represent the limits of the globe.
library(ggplot2)
library(sf)
library(rnaturalearth)
countries <- ne_countries(returnclass = "sf")
countries <- st_transform(countries, crs = "+proj=robin")
ggplot(countries) +
geom_sf() +
theme_minimal()
Expected result:
Any tips?

I guess you could make your own sf polygon and plot that in its own layer:
bound <- st_sf(geometry = st_sfc(
st_polygon(x = list(cbind(c(-180, rep(180, 100), rep(-180, 100)),
c(-90, seq(-90, 90, length = 100),
seq(90, -90, length = 100))))),
crs = 'WGS84'))
ggplot(countries) +
geom_sf() +
geom_sf(data = bound, fill = NA, linewidth = 1.5, color = 'black') +
theme_minimal()

Related

Why am I not able to change the legend title for this sf object plotting?

I have a set of point-based data in a vector called "yield_annual_offshore_advantages," which correspond to a value of energy expressed in Watt*hours and can be mapped on to a pair of longitude, latitude coordinates which I obtain from a data frame called "totalityofsites". Using the text below, I am able to get the points to show up quite nicely and everything, but the legend has a title which I would like to change. Let's say I want to change it to "Hello".
What am I doing wrong in the code below? If I'm not mistaken, something similar has worked on other sites.
library(rnaturalearthdata)
library(rnaturalearth)
library(sf)
library(ggplot2)
world_map <- ne_coastline(scale = "medium", returnclass = "sf")
#ggplot2::ggplot(data = world_map)
ggplot2::ggplot(data = world_map) + geom_sf() + geom_point(data = totalityofsites[1:20,],
mapping = aes(x = lon, y = lat, color = (yield_annual_offshore_advantages/1000)), size = 3)
+ coord_sf(xlim = c(min(totalityofsites$lon)-10, max(totalityofsites$lon) + 10), ylim =
c(min(totalityofsites$lat)-10, max(totalityofsites$lat)+10), expand = F)
+ title(main = "Annual energy yield differences", legend(legend = "Hello")) + ggtitle("Annual values, in kWh")
Grateful for any help.
FWIW I will just place the output of the above here.
You can add scale_colour_continuous(name = "hello") to your plot. Here's a full reprex with some made-up data:
library(rnaturalearthdata)
library(rnaturalearth)
library(sf)
#> Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1
library(ggplot2)
world_map <- ne_coastline(scale = "medium", returnclass = "sf")
set.seed(69)
totalityofsites <-
data.frame(lon = runif(20, -100, 100), lat = runif(20, -90, 90),
yield_annual_offshore_advantages = runif(20, -2000, 2000))
ggplot2::ggplot(data = world_map) +
geom_sf() +
geom_point(data = totalityofsites[1:20,],
mapping = aes(x = lon, y = lat,
color = (yield_annual_offshore_advantages/1000)),
size = 3) +
coord_sf(xlim = c(min(totalityofsites$lon)-10,
max(totalityofsites$lon) + 10),
ylim = c(min(totalityofsites$lat)-10,
max(totalityofsites$lat)+10), expand = F) +
scale_colour_continuous(name = "hello") +
ggtitle("Annual values, in kWh")
Created on 2020-08-16 by the reprex package (v0.3.0)

How to make a map of a country (Maldives) in R using ggplot2

I am trying to obtain a map of the Maldives, similar to the one seen in the image. However, I am struggling with the xlim and ylim. Any suggestions?
library(cowplot)
library(googleway)
library(ggplot2)
library(ggrepel)
library(ggspatial)
library(libwgeom)
library(sf)
library(rnaturalearth)
library(rnaturalearthdata)
theme_set(theme_bw())
ggplot(data = world) +
geom_sf() +
coord_sf(xlim = c(-102.15, -74.12), ylim = c(7.65, 33.97), expand = FALSE)
The Maldives don't make for a great map in this format, since they are so individually small and spread out. In fact, if you use the medium resolution data from rnaturalearth that you are currently using, you will only see one or two of the hundreds of islands, and they will just appear as little blobs.
Instead, you can get a higher resolution map like this:
maldives <- ne_countries("large", country = "Maldives", returnclass = "sf")
theme_set(theme_bw())
ggplot(data = maldives) +
geom_sf() +
coord_sf(xlim = c(70, 76))
You can show them in relation to the nearby countries of India and Sri Lanka if you just want to see their overall shape, extent and location:
maldives <- ne_countries("large",
country = c("Maldives", "India", "Sri Lanka"),
returnclass = "sf")
theme_set(theme_bw())
ggplot(data = maldives) +
geom_sf() +
coord_sf(xlim = c(72, 82), ylim = c(-1, 15))
Another option is to colour the map to allow the islands to "pop"
ggplot(data = maldives) +
geom_sf(fill = "#55790A", color = "#90FF20") +
coord_sf(xlim = c(72, 82), ylim = c(-1, 15)) +
theme(panel.background = element_rect(fill = "#342255"),
panel.grid = element_line(color = "#4f4f6f"))
Or stick to your original format but zoom in to near the capital:
ggplot(data = maldives) +
geom_sf() +
coord_sf(xlim = c(72.5, 73.5), ylim = c(6, 7.2))

Adding points to geom_sf shapes does not work when adding a projection

When I am trying to add points layer to a geom_sf() layer and a projection, the points seem to end up in one location in South Texas. Below is a minimal example of reproducing this issue.
library(sf)
library(ggplot2)
# devtools::install_github("hrbrmstr/albersusa")
library(albersusa)
crs_use = "+proj=laea +lat_0=30 +lon_0=-95"
d_points = data.frame(long = c(-110, -103, -84),
lat = c(45, 40, 41))
A = ggplot(data = usa_sf()) +
geom_sf() +
geom_point(data = d_points,
aes(x = long, y = lat),
color = "red", size = 5) +
theme_minimal() +
ggtitle("(A) right point position, wrong projection")
B = ggplot(data = usa_sf()) +
geom_sf() +
geom_point(data = d_points,
aes(x = long, y = lat),
color = "red", size = 5) +
coord_sf(crs = crs_use) +
theme_minimal() +
ggtitle("(B) right projection, wrong points using geom_point()")
C = ggplot() +
geom_sf(data = usa_sf()) +
geom_sf(data = st_as_sf(d_points,
coords = c("long", "lat"), crs = crs_use),
color = "red", size = 5) +
coord_sf(crs = crs_use) +
theme_minimal() +
ggtitle("(C) right projection, wrong points using geom_sf() points")
cowplot::plot_grid(A, B, C, nrow = 3)
I want to add a points layer to the US map with a custom projection. However, whenever I use a projection, the points that I specify become a weird location in Southeast Texas, which is not in my specified location.
Any suggestion on solving this issue is appreciated. Thank you!
You need to reproject your points as well; sf::st_transform() should do the job.
I don't have access to the {albersusa} package, so I am using {USABoundaries} to get a map of the lower 48, but that is not the point; the point is applying st_transform(crs = crs_use) to both your spatial objects before plotting.
library(sf)
library(ggplot2)
library(USAboundaries)
crs_use <- "+proj=laea +lat_0=30 +lon_0=-95"
usa_sf <- us_boundaries(type="state", resolution = "low") %>%
dplyr::filter(!state_abbr %in% c("PR", "AK", "HI")) %>%
st_transform(crs = crs_use)
d_points <- data.frame(long = c(-110, -103, -84),
lat = c(45, 40, 41)) %>%
st_as_sf(coords = c("long", "lat"), crs = 4326) %>%
st_transform(crs = crs_use)
ggplot(data = usa_sf) +
geom_sf() +
geom_sf(data = d_points,
color = "red", size = 5) +
theme_minimal()

Polar/Stereographic map in R

I am trying to produce a sterographic map similarly to this:
What I am trying to do is to add:
Coordinates
Graticule lines
This can be in both base R or with ggplot2. Any help is appreciated.
My attempts so far
library(rgdal)
library(raster)
proj <- "+proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +k=1 +x_0=0 +y_0=0 +a=6378273 +b=6356889.449 +units=m +no_defs"
data("wrld_simpl", package = "maptools")
wm <- crop(wrld_simpl, extent(-180, 180, 45, 90))
plot(wm)
wm <- spTransform(wm, CRSobj = CRS(proj))
plot(wm)
This is quite a complex map to reproduce, and all the details required to make it work seem beyond the scope of a single question. However, this is most of the stuff you require.
Doing this in ggplot is easier to do that using the base graphics. However, it is quite a complex graph to make.
I have had to use a few hacks to get it to work. In particular, the axes produced from coord_map did not end at the edge of the plot, so I had to manually delete the axes and then recreate them using the geom_text and geom_segment lines below.
library(rgdal)
library(raster)
library(ggplot2)
# Defines the x axes required
x_lines <- seq(-120,180, by = 60)
ggplot() +
geom_polygon(data = wm_ggplot, aes(x = long, y = lat, group = group), fill = "grey", colour = "black", alpha = 0.8) +
# Convert to polar coordinates
coord_map("ortho", orientation = c(90, 0, 0)) +
scale_y_continuous(breaks = seq(45, 90, by = 5), labels = NULL) +
# Removes Axes and labels
scale_x_continuous(breaks = NULL) +
xlab("") +
ylab("") +
# Adds labels
geom_text(aes(x = 180, y = seq(55, 85, by = 10), hjust = -0.2, label = paste0(seq(55, 85, by = 10), "°N"))) +
geom_text(aes(x = x_lines, y = 39, label = c("120°W", "60°W", "0°", "60°E", "120°E", "180°W"))) +
# Adds axes
geom_hline(aes(yintercept = 45), size = 1) +
geom_segment(aes(y = 45, yend = 90, x = x_lines, xend = x_lines), linetype = "dashed") +
# Change theme to remove axes and ticks
theme(panel.background = element_blank(),
panel.grid.major = element_line(size = 0.25, linetype = 'dashed',
colour = "black"),
axis.ticks=element_blank()) +
labs(caption = "Designed by Mikey Harper")
An alternative solution using the PlotSvalbard package:
# devtools::install_github("MikkoVihtakari/PlotSvalbard") ## Run once
library(PlotSvalbard)
basemap("panarctic", limits = 60)
The function also plots bathymetry:
basemap("panarctic", limits = 60, bathymetry = TRUE)
Check the user manual for further features. Plotting data is possible using ggplot2 syntax. Use the add_land function to add land shapes on top of the raster you need to plot (needs to be in the same projection than the Pan-Arctic basemaps, see map_projection("panarctic")). The transform_coord function might be helpful for transforming projections.

geom_rect + coord_map = very slow

I am plotting a map of Norway with an area of interest highlighted with a red rectangle using ggplot2. If I omit the geom_rect or coord_map, the map plots very quickly (< 1 seconds). If I use both - which I need to - it is extremely slow to print and render (about five minutes).
I presume this is something to do with the munching - projecting the rectangle onto the new coordinate system. Is there a way to control this?
library(ggplot2)
library(maps)
library(mapdata)
xlim <- c(5, 10)
ylim <- c(60, 62)
norwaymap <- map_data("worldHires", "Norway")
a <- ggplot(norwaymap, aes(x = long, y = lat, group = group)) +
geom_polygon(colour = NA, fill = "grey60") +
geom_rect(xmin = xlim[1], xmax = xlim[2], ymin = ylim[1], ymax = ylim[2],
colour = "red", fill = NA) +
coord_map(xlim = c(3, 33), ylim = c(57, 72))
print(a) # super slow
Using the low resolution map makes the map plotting much faster (about 10 seconds).
No need to resort to mercator approximations:
library(ggplot2)
library(maps)
library(mapdata)
norwaymap <- map_data("worldHires", "Norway")
xlim <- c(5, 10)
ylim <- c(60, 62)
ggplot() +
geom_map(data=norwaymap, map=norwaymap,
aes(long, lat, map_id=region),
color=NA, fill="grey60") +
geom_rect(data=data.frame(),
aes(xmin=xlim[1], xmax=xlim[2], ymin=ylim[1], ymax=ylim[2]),
color="red", fill=NA) +
coord_map(xlim=c(3, 33), ylim=c(57, 72)) +
ggthemes::theme_map()
Another option would be to use an Albers equal-area conic projection (a typical one for that region):
ggplot() +
geom_map(data=norwaymap, map=norwaymap,
aes(long, lat, map_id=region),
color=NA, fill="grey60") +
geom_rect(data=data.frame(),
aes(xmin=xlim[1], xmax=xlim[2], ymin=ylim[1], ymax=ylim[2]),
color="red", fill=NA) +
ggalt::coord_proj("+proj=aea +lat_1=60 +lat_2=70 +lon_0=18.37",
xlim=c(3, 33), ylim=c(57, 72)) +
ggthemes::theme_map()
That has a "disadvantage" of the rectangle being projected (it is with Mercator, too, there's just no distortion).
Either way, the magic for the rectangle is ensuring you're plotting only one, like Luke said.
Use coord_quickmap and especially annotate instead of geom_rect to speed things up:
ggplot(norwaymap, aes(x = long, y = lat, group = group)) +
geom_polygon(colour = NA, fill = "grey60") +
annotate(geom="rect", xmin = xlim[1], xmax = xlim[2], ymin = ylim[1],
ymax = ylim[2], colour = "red", fill = NA) +
coord_quickmap(xlim = c(3, 33), ylim = c(57, 72))
geom_rect overplots several rectangles on the same spot, annotate just plots one rectangle. You can read about the difference between coord_map and coord_quickmap in the help files: ?coord_quickmap.

Resources