Representing different layers in a ggplot map! R - r

M intention is to represent 3 different layers of information in a ggplot map:
1. The map itself using a MULTIPOLYGON file
2. Kriging estimations using geom_tile()
3. datapoints using geom_point()
I used the following script:
library(rnaturalearth)
library(rnaturalearthdata)
world <- ne_countries(scale = "medium", returnclass = "sf")
windows()
ggplot(data = world) +
geom_sf(color="black",fill="grey90") +
theme(panel.background = element_blank()) +
coord_sf(xlim = c(-12.3, 95), ylim = c(70, 22), expand = FALSE) +
geom_tile(data = myKrige, aes(x= x1, y= x2, fill =var1.pred)) +
geom_point(data = roh, aes(x = LON, y = LAT))
In this script I used three datasets: world (a MULTIPOLYGON obtained from rnaturalearthdata), myKrige (data frame obtained from a spatialPointsDataFrame) and roh (data frame with latitude and longitude data points).
This is the figure my script produces:
As you can see the different layers are on top of each other. But I would like to merge nicely the geom_tile with the base plot.
Any idea how can I do it easily. Or should I rethink the complete figure?

Here is starting point, following an example from https://rpubs.com/nabilabd/118172
library(rnaturalearth)
library(rnaturalearthdata)
library(ggplot2)
library(sf)
world <- ne_countries(scale = "medium", returnclass = "sf")
df <- data.frame(x=rnorm(10,sd = 3),
y=rnorm(10,sd = 3))
df <- sf::st_as_sf(df, coords=c("x","y"), crs = 4326, agr = "constant", remove = F)
ggplot(data = world) +
geom_sf() +
geom_sf(data=df) +
# The idea would then to add add a scale_fill_gradient() such
# as in https://rpubs.com/nabilabd/118172 , but I dont know
# how the kring data should look like.
coord_sf(xlim = c(-10,10), ylim=c(-10,10))
# example
lzn.kriged %>% as.data.frame %>%
ggplot(aes(x=x, y=y)) + geom_tile(aes(fill=var1.pred)) + coord_equal() +
scale_fill_gradient(low = "yellow", high="red") +
scale_x_continuous(labels=comma) + scale_y_continuous(labels=comma) +
theme_bw()

Related

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

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)

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

how to plot rivers efficiently?

I came up with a way to plot rivers using geom_path. I do not know if there is a better way. I had to split the dataframe into hundreds of "rivers". So it is very slow. Any ideas?
world_map <- map_data('world')
system("wget https://sites.google.com/site/joabelb/Home/PrincRiosBrazil.zip")
system("unzip -o PrincRiosBrazil.zip")
library(rgdal)
shapeHid <- readOGR(dsn = ".", layer = "PrincipaisRiosDoBrasil")
shapeHid#data$id = rownames(shapeHid#data)
library(ggplot2)
shapeHid.points = fortify(shapeHid, region="id")#
shapeHid.df = merge(shapeHid.points, shapeHid#data, by="id", all=F)
listofrivers<-split(shapeHid.df, shapeHid.df$id)
myMap3 <- ggplot() +
lapply(listofrivers, function(x) geom_path(data=x, aes(x=long, y=lat), color="gray70", linetype=1)) +
geom_map(data = world_map, map = world_map, aes(map_id = region),
color = 'black', fill = NA, linetype=2) +
theme(panel.border = element_rect(fill = NA, colour = "black"))+
theme(axis.title=element_blank())+
scale_y_continuous(limits=c(-15,6),expand=c(0,0))+
scale_x_continuous(limits=c(-76,-55),expand=c(0,0))
myMap3
If you routinely work with shapefiles, geom_path and geom_polygon gives everything you need. In recent versions, ggplot deals directly with spatial objects, so there's no need to use fortify and merge (probably the step taking more time in your code). Here's an example using the shapefile of federative units of Brazil from IBGE as base map:
shapeUFs <- readOGR('.', 'BRUFE250GC_SIR')
shapeHid <- readOGR('.', 'PrincipaisRiosDoBrasil')
ggplot(shapeUFs, aes(long, lat, group = group)) +
geom_polygon(fill = 'gray90', color = 'black') +
geom_path(data = shapeHid, color = 'steelblue2') +
coord_map() + theme_void()
Performance will be affected by the size of your shapes (determined by number of features and level of details) more than the geometry you're using in ggplot. You can use rgeos::gSimplify to reduce the number of vertices in a spatial polygon/lines object. You can also plot points directly over the map:
# Simplifying the geometry of the federative units
shapeUFs.s <- rgeos::gSimplify(shapeUFs, .05, TRUE)
# Storing map in an object
riversMap <- ggplot(shapeUFs.s, aes(long, lat)) +
geom_polygon(aes(group = group), fill = 'gray90', color = 'black') +
geom_path(data = shapeHid, aes(group = group), color = 'steelblue2') +
coord_map() + theme_void()
# Sampling 20 cities in Brazil
brMunics <- read.csv('https://raw.githubusercontent.com/kelvins/Municipios-Brasileiros/master/Municipios_Brasileiros.csv')
Munics <- brMunics[sample(nrow(brMunics), 20), ]
# Plotting points over the map
riversMap + geom_point(data = Munics, aes(Longitude, Latitude), color = 'red')
# If your data already have the coordinates named 'lat' and 'long',
# you can skip aes(Longitude, Latitude):
names(Munics)[6:7] <- c('lat','long')
riversMap + geom_point(data = Munics, color = 'red')
I would do the following:
library(sf)
library(ggplot2)
world_map <- map_data('world')
sdf <- read_sf("PrincipaisRiosDoBrasil.shp")
myMap3 <- ggplot() +
geom_map(data = world_map, map = world_map, aes(map_id = region), color = 'black', fill = NA, linetype=2) +
geom_sf(data = sdf)+
theme(panel.border = element_rect(fill = NA, colour = "black"))+
theme(axis.title=element_blank())+
scale_y_continuous(limits=c(-15,6),expand=c(0,0))+
scale_x_continuous(limits=c(-76,-55),expand=c(0,0))
myMap3
You'll need to update ggplot2 to 3.0.0 for geom_sf.

How to draw ggmap with two different administrative boundaries?

I am wondering how to draw a map using get_map and ggmap of any federal country (i.e. a country with provinces and counties). Any country, other than the US would be great. To make it look nice, fill the geom_polygon of counties (any fill), and provinces are empty polygons, only with its contours. So, basically, it is two overlapping ggmaps.
You can get the shapefiles here:
https://www.dropbox.com/s/4nl685t860x1e8r/municipios_br.zip
rm(list = ls())
library(ggplot2)
library(rgdal)
library(ggmap)
# READ SHAPEFILE OF BOUNDARIES
Map <- readShapePoly("municipios_br.shp")
head(as.data.frame(Map))
Map = gBuffer(Map, width=0, byid=TRUE)
MapC <- fortify(Map, region="CODIGO_MUN") # municipalities
MapP <- fortify(Map, region="CODIGO_UF") # state boundaries
MapC$test <- 1
MapP$test <- 1
MapC <- Map[order(MapC$order),]
MapP <- MapP[order(MapP$order),]
The following code produces counties boundaries:
google.map <- get_map(location = 'Brazil', zoom=4,maptype="terrain")
m0 <- ggmap(google.map)
m1 <- m0 + geom_polygon(color = 'grey90', size = .01, aes(x=long, y=lat, group=group, fill=as.factor(test)), data=MapC, alpha=.6)
m1 + guides(fill=FALSE) + scale_fill_manual(values=c("red"))
Now, provinces:
m2 <- m0 + geom_polygon(color = 'grey50', size = .1, aes(x=long, y=lat, group=group, fill=as.factor(test)), data=MapP, alpha=.9)
m2 + guides(fill=FALSE) + scale_fill_manual(values=c(NA))
How to make the two work together?
You could also get your maps from e.g. GADM:
library(raster)
adm1 <- getData('GADM', country='HUN', level=0)
adm2 <- getData('GADM', country='HUN', level=1)
And let us fortify those for ggplot usage:
library(ggplot2)
fadm1 = fortify(adm1)
fadm2 = fortify(adm2)
And add as many layers and geoms as you wish:
ggplot(fadm1, aes(x = long, y = lat, group = group)) + geom_path() +
geom_polygon(data = fadm2, aes(x = long, y = lat),
fill = "green", alpha = 0.5) +
geom_path(data = fadm2, aes(x = long, y = lat), color = "blue") +
theme_bw()
Resulting in:
Update: combining your two layers mentioned in the updated questions
m0 + geom_polygon(size = .01,
aes(x = long, y = lat, group = group, fill = as.factor('red')),
data = MapC,
alpha = .6) +
geom_path(color = 'grey50', size = .1, aes(x = long, y = lat, group = group),
data=MapP, alpha=.9) +
guides(fill=FALSE)

Resources