Polar/Stereographic map in R - 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.

Related

Plot a bounding box around a sf object using ggplot2

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()

Why are the degrees not showing up in my plot?

I'm making a ggplot of a basemap with some points overlaid. I believe the default for plotting a basemap is to have the axes plot in latlong with degrees N/W (even though its projected in web mercator) but the degree symbol isn't showing up and instead is displayed as a little box?
library(sf)
library(basemaps)
library(ggplot2)
library(ggstar)
pt_df = data.frame(X = c(-10069438, -10827213),
Y = c(4014585, 4013104),
Type = c("MS", "OK"))
pt_df = st_as_sf(pt_df, coords = c("X", "Y"), crs = 3857)
bbox = st_box(pt_df)
bbox["xmin"]<- -11500000
bbox["xmax"]<- -9900000
bbox["ymin"] <- 3000000
bbox["ymax"] <- 4500000
basemap_ggplot(bbox, map_service="osm_stamen", map_type="terrain")+
geom_star(data = pt_df, aes(x=X, y=Y, fill="red"), size=5)+
xlab("")+
ylab("")
I wrote out the expression to recode the x- and y- axes yet they're still showing boxes.
basemap_ggplot(bbox, map_service="osm_stamen",
map_type="terrain")+
geom_star(data = pt_df, aes(x=X, y=Y, fill="red"), size=5)+
xlab("")+
ylab("")+
scale_y_continuous(breaks = c(28, 30, 32, 34, 36),
labels = c(expression(28~degree~N),
expression(30~degree~N),
expression(32~degree~N),
expression(34~degree~N),
expression(36~degree~N)))+
scale_x_continuous(breaks = c(-100, -95, -90, -85),
labels = c(expression(-100~degree~W),
expression(-95~degree~W),
expression(-90~degree~W),
expression(-85~degree~W)))
Any ideas?
Here's an example of my code but I almost think it might be some sort of setting issue and therefore isn't reproducible on someone else's computer? Any help/ideas appreciated.
We could insert unicode character:
scale_y_continuous(labels = function(x) paste0(x, '\u00B0', "N"))
ggplot() +
geom_sf(
data = border$osm_lines,
inherit.aes = FALSE,
color = "black",
size = .4,
alpha = .8
)+
scale_y_continuous(labels = ~ paste0(., '\u00B0', "N"))+
scale_x_continuous(labels = ~ paste0(., '\u00B0', "N"))

Creating bathymetric lines from getNOAA.bathy and add them to ggplot: how do I homogenize the bathymetric lines?

I have created maps using the ggplot function on R. I then wanted to add bathymetric lines. I so downloaded them from the NOAA portal using the code lines:
library(marmap)
bat <- getNOAA.bathy(-11.99792 ,-5.002083 ,35.00208,43.99792,res=4, keep=TRUE)
plot(bat, land=TRUE, n=100, lwd=0.03)
plot(bat, deep=-200, shallow=-200, step=0, lwd=0.5, drawlabel=TRUE, add=TRUE)
plot(bat, deep=-1000, shallow=-1000, step=0, lwd=0.3, drawlabel=TRUE, add=TRUE)
Until this moment the lines look homogeneous and not discontinued.
I then run these two lines:
bathy_df <- inlmisc::Grid2Polygons(as.SpatialGridDataFrame(bat),
level=TRUE, pretty=TRUE)
bathy_map <- fortify(bathy_df)
But then, when I add bathy_map to my ggplot, the lines of the bathymetry appear as you can see in the attached picture: not homogeneous at all and discontinue.
This is the script of my ggplot:
D <- ggplot() +
geom_raster(data = Fig_D, aes(x = x, y = y, fill = value)) +
facet_wrap(~ variable) +
coord_equal() +
scale_fill_viridis_c(option = "turbo", direction = 1, limits=c(0, 160)) +
geom_polygon(data=bathy_map,
aes(x=long,y=lat,group=group), inherit.aes=F,
colour='black', fill=NA, lwd=0.5)+
geom_polygon(data = coast_map,
aes(x=long,y=lat,group=group), inherit.aes=F,
colour='black', fill='gray', lwd=0.5) +
theme_void(base_size = 12) +
theme(strip.text.x = element_text(size = 10, vjust = 1)) +
theme(legend.position = "right", legend.justification = "left") +
labs(fill='SPL')
(the first geom_polygon is the one referring to the bathymetric lines)
Do you know how I can make these lines look more homogeneous? And also, do you know how I can show the depth of some of the most important bathymetric lines?
Thank you.
Maps created with ggplot showing bathymetric lines
When you want to draw maps with ggplot2, always think library(sf)! ;-)
Here is an example:
# Load useful packages
library(sf)
library(marmap)
library(tidyverse)
library(rnaturalearth)
# Get bathymetric data
bat <- getNOAA.bathy(-12, -5, 35, 44, res = 4, keep = TRUE)
bat_xyz <- as.xyz(bat)
# Import country data
country <- ne_countries(scale = "medium", returnclass = "sf")
# Plot using ggplot and sf
ggplot() +
geom_sf(data = country) +
geom_tile(data = bat_xyz, aes(x = V1, y = V2, fill = V3)) +
geom_contour(data = bat_xyz,
aes(x = V1, y = V2, z = V3),
binwidth = 100, color = "grey85", size = 0.1) +
geom_contour(data = bat_xyz,
aes(x = V1, y = V2, z = V3),
breaks = -200, color = "grey85", size = 0.5) +
geom_sf(data = country) +
coord_sf(xlim = c(-12, -5),
ylim = c(35, 44)) +
labs(x = "Longitude", y = "Latitude", fill = "Depth (m)") +
theme_minimal()
And here is the result.
You don't need to use inlmisc::Grid2Polygons() nor ggplot2::fortify(). Simply use marmap::as.xyz() to transform your bathymetric data into a long data.frame, and use either (or both), of geom_tile() and geom_contour().
Of course, you can add several layers of geom_contour(). Here, I've added one with one isobath every 100 meters, and a darker one at -200m.
As for labelling some (or all) of the isobaths, have a look at metR::geom_label_contour()

How to plot a sector of the south pole in R

I need to plot some data over a map of Antarctica and I managed to do so following this thread
Polar/Stereographic map in R
library(rgdal)
library(raster)
library(ggplot2)
Long <- c(-75, -76, -77, -78, -79)
Lat <- c(123, 124, 125, 126, 127)
Sodio<- c(110, 209, 65.7, 47.6, 135)
data<-data.frame(Long, Lat, Sodio)
# Defines the x axes required
x_lines <- seq(-120,180, by = 60)
wm <- map_data("world")
ggplot() +
geom_polygon(data = wm, 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(limits=c(-90,-60),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 = -160, y = seq(-55, -85, by = -10), hjust = -0.2, label = paste0(seq(55, 85, by = 10), "°S"))) +
geom_text(aes(x = x_lines, y = -63, label = c("120°W", "60°W", "0°", "60°E", "120°E", "180°W"))) +
# Adds axes
geom_hline(aes(yintercept = -60), size = 1) +
geom_segment(aes(y = -60, 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()) +
geom_point(data=data, aes(x=Long, y=Lat, color=Sodio))+
scale_color_gradient(low="blue", high="red")
And the code works. Like a charm and kudos to the original user to posting it because it helped me a ton.
The problem is that since all the data are in a small sector (mostly between 85° and 65 °N and between 180° W and 130° W, the one I posted are just a super short dummy set) I was tryig to plot just that "wedge" of the Antarctic continent in order to help me visualize the data more clearly. I could just expland the plot and cut it with photoshop but I need to plot a number of these.
I tried changing the projection to a conic one but it starts doing... extremely weird stuff like trying to peoject the entirety of the world even when I try to put limits in the scale_y_continuous.
Any idea on how to solve this? Also, any idea on how I can add "elevation" lines on the map? I'm working in ggplot because I need to plot some data on top of it afterwards and I'm more familiar with that package of R, but I'm ok with other packages as long as they allow me to plot data on top of it and they can save the plot at 300 dpi...

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