library(tidyverse)
library(sf)
Day 19 globe
Code source inspriation
- https://twitter.com/ryanahart/status/1593966022553489410
- https://twitter.com/dhernangomez/status/1591710364571504640
- https://twitter.com/geokaramanis/status/1593999504323317760
- https://github.com/curatedmess/30DayMapChallenge/blob/main/2022/11192022/qatar.R
But see this globe by @geokaramanis for the Day 7 raster entry https://github.com/gkaramanis/30DayMapChallenge/tree/main/2022/07-raster-earth
Code to download the data
The basic libraries
Get the Seattle lat/lon
Code
# Center
<- tibble(address = "Seattle, Washington") |>
city_coords ::geocode(address, method = 'osm', long = long, lat = lat)
tidygeocoder<- city_coords$long[1]
long <- city_coords$lat[1]
lat <- 6384 # https://epsg.io/6384
crs2 <-
coord_center tibble(long, lat) %>%
::st_as_sf(coords = c("long", "lat"), crs = 4326) sf
Set the projection. Had to futz a bit to get something that was close and didn’t throw an error w ggplot.
<- paste0("+proj=ortho +lat_0=", lat, " +lon_0=", long)
crs_string # crs_string <- "+proj=ortho +lat_0=45 +lon_0=-105"
Get US elevations and define hill shading. This will be spatraster and comes with a projection which you can check with terra::crs()
. We don’t need to change that; just need to know that it is specified.
Code
library(tidyterra) # for geom_spatraster
library(geodata)
library(scales)
<- geodata::elevation_global(res=10, path = tempdir())
r names(r) <- "alt"
<- terra::terrain(r, "slope", unit = "radians")
slope <- terra::terrain(r, "aspect", unit = "radians")
aspect <- terra::shade(slope, aspect, 30, 270)
hill
# give the hill shading a name so I can refer to it in aes()
names(hill) <- "shades"
Create a blue globe that will represent the ocean. 637100 is the radius of the earth in meters.
Code
# these are sf functions
<- st_point(x = c(0,0)) %>%
ocean st_buffer(dist = 6371000) %>%
st_sfc(crs = crs_string)
Plot code
Create my globe. The palette “dem_poster” comes from tidyterra package.
Code
library(ggfx) # for with_shadow
<- ggplot() +
p1 with_shadow(geom_sf(data = ocean, fill = "#BBDEFB", color = NA), sigma = 30, x_offset = 25, y_offset = 25, color = "#58595d") +
geom_spatraster(data = hill, aes(fill=shades), maxcell = Inf) +
geom_spatraster(data=r, maxcell = Inf) +
scale_fill_hypso_tint_c(limits = as.vector(minmax(r)),
palette = "dem_poster",
alpha =0.8,
labels = scales::label_comma(),
breaks = c(seq(0,1000, 250), seq(2000, 6000, 1000))) +
guides(fill=guide_legend(title = "elevation", reverse = TRUE)) +
coord_sf(crs = crs_string) +
theme_void()
p1
Then add some annotation. The x and y units are in meters, so the nudge has to be huge (millions).
Code
library("ggrepel")
<- p1 + geom_sf(data=coord_center) +
p2 geom_text_repel(data = coord_center, aes(x=st_coordinates(coord_center)[1], y=st_coordinates(coord_center)[2]), label="Seattle",
nudge_x = -3371000, nudge_y = -1371000) +
labs(
title = "Globe with elevations",
caption = "Graphic: EE Holmes"
+
) theme(
plot.background = element_rect(fill = "grey97", color = NA),
plot.margin = unit(c(.5,.5,.5,.5), "cm"),
plot.title = element_text(hjust = 0.045, size = 26, face = "bold")
) p2
Swap out that square background with one with rounded corners. Well this didn’t really work since I couldn’t figure out how to save.
Code
library(grid)
<- ggplotGrob(p2)
g <- g$grobs[[1]]
bg <- roundrectGrob(x=bg$x, y=bg$y, width=bg$width, height=bg$height,
round_bg r=unit(0.1, "snpc"),
just=bg$just, name=bg$name, gp=bg$gp, vp=bg$vp)
$grobs[[1]] <- round_bg
ggrid.draw(g)
For some reason the shadowing looks wrong in the html. Looks like this in the saved image:
::include_graphics(here::here("content", "globe_elevation.png")) knitr
Save image
ggsave(paste0("globe_elevation", ".png"), dpi = 320, width = 8, height = 8)