R map - poor representation of land borders - r

I map the southern part of the South hemisphere. My issue is Australia which has poorly drawn borders.
My data :
library("maptools")
library("ggplot2")
library("tidyverse")
ylim_map <- c(-90, -30)
xlim_map <- c(-180, 180)
world <- maps::map("world", fill=TRUE, plot=FALSE, ylim = ylim_map)
Convert data in correct format for ggplot :
IDs <- sapply(strsplit(world$names, ":"), function(x) x[1])
world <- map2SpatialPolygons(world, IDs = IDs,
proj4string = CRS("+proj=longlat +datum=WGS84"))
world_map <- fortify(world)
world_map <- world_map[which(between(world_map$lat, ylim_map[1], ylim_map[2]) &
between(world_map$lon, xlim_map[1], xlim_map[2])),]
And my plot :
ggplot() +
coord_map("orthographic", orientation = c(-90, 0, 0),
xlim = xlim_map, ylim = c(ylim_map[1], ylim_map[2] + 10)) +
geom_map(data = world_map, map = world_map,
aes(x = long, y = lat, map_id = id), fill = "black") +
geom_text(aes(x = 180, y = ylim_map[2]+5, label = "180°E"), color = "black") +
geom_text(aes(x = 90, y = ylim_map[2]+5, label = "90°E"), angle = -90, color = "black") +
geom_text(aes(x = 0, y = ylim_map[2]+5, label = "0°"), color = "black") +
geom_text(aes(x = -90, y = ylim_map[2]+5, label = "90°W"), angle = 90, color = "black") +
labs(y = "", x = "") +
# Theme
theme(text = element_text(size = 20),
panel.background = element_blank(),
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
axis.line = element_blank(),
aspect.ratio = 1)

TLDR:
You need to close your polygons.
Explanation:
Let's trim away extraneous code & zoom in onto Australia. (Though actually the problem exists for Africa & South America as well; it's just not as obvious there...)
We can see that the top line is misbehaving. It's intersecting with the coastline further down south, rather than sticking to its correct latitude level:
ggplot() +
coord_map("orthographic", orientation = c(-40, 130, 0)) +
geom_map(data = world_map, map = world_map,
aes(x = long, y = lat, map_id=id),
fill = "darkgrey") +
theme_bw()
Now a geom_map layer is essentially plotting polygons, and ?geom_polygon states:
Polygons are very similar to paths (as drawn by geom_path()) except
that the start and end points are connected and the inside is coloured
by fill. The group aesthetic determines which cases are connected
together into a polygon.
If we replace the geom_map layer with its geom_polygon / geom_path equivalents, the situation becomes much more obvious: the polygon corresponding to Australia has no top line. Instead, the path starts at the one corner and ends at the opposite corner. geom_polygon connects them with a straight line, which may intersect other lines when the coordinate system isn't linear (and coord_map isn't):
ggplot() +
coord_map("orthographic",
orientation = c(-40, 130, 0)) +
geom_polygon(data = world_map,
aes(x = long, y = lat, group = group),
fill = "lightgrey") +
geom_path(data = world_map,
aes(x = long, y = lat, group = group)) +
theme_bw()
Solution:
We can manually close each polygon by repeating its first point at the end. (For polygons that are already closed, this has no additional effect.)
library(dplyr)
world_map2 <- world_map %>%
group_by(group) %>% # each group corresponds to a unique polygon
arrange(order) %>% # sort points in the appropriate sequence
slice(c(1:n(), 1)) %>% # repeat first row after last row
mutate(order = seq(1, n())) %>% # define new order for n+1 rows
ungroup()
Check that the polygons are now closed, & the top line for Australia now traces its latitude level nicely:
ggplot() +
coord_map("orthographic",
orientation = c(-40, 130, 0)) +
geom_polygon(data = world_map2,
aes(x = long, y = lat, group = group),
fill = "lightgrey") +
geom_path(data = world_map2,
aes(x = long, y = lat, group = group)) +
theme_bw()
Applying this to the original use case:
ggplot() +
coord_map("orthographic", orientation = c(-90, 0, 0),
xlim = xlim_map, ylim = c(ylim_map[1], ylim_map[2] + 10)) +
geom_map(data = world_map2, map = world_map2,
aes(x = long, y = lat, map_id = id), fill = "black") +
geom_text(aes(x = 180, y = ylim_map[2]+5, label = "180°E"), color = "black") +
geom_text(aes(x = 90, y = ylim_map[2]+5, label = "90°E"), angle = -90, color = "black") +
geom_text(aes(x = 0, y = ylim_map[2]+5, label = "0°"), color = "black") +
geom_text(aes(x = -90, y = ylim_map[2]+5, label = "90°W"), angle = 90, color = "black") +
labs(y = "", x = "") +
# Theme
theme(text = element_text(size = 20),
panel.background = element_blank(),
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
axis.line = element_blank(),
aspect.ratio = 1)

Related

Create animation or GIF with point plots in R

I am trying to create an animation or GIF that shows the evolution of an environmental condition over time. Basically, I have a dataset (example below) with year, value of the environmental condition, unit, and coordinates.
year
condition
unit
Lat
Long
1945
-0.120148
TSS
41.36531
41.67889
1948
0.274646
TSS
30.45368
-87.99042
1948
0.074794
TSS
30.45368
-87.99042
1975
-0.102050
TSS
38.10541
-122.06782
1979
-0.169886
NTU
29.77048
-84.91630
Complete dataset: https://drive.google.com/file/d/1XQ95KP_x-kbq_wdmpfpCiOonF-RoFsU1/view?usp=sharing
I am using ggplot2 to create the plots comprising year gaps. Here is the code I am using to plot the variation from 1945 to 1980:
`ggplot() +
geom_map(data = world, map = world,aes(long, lat, map_id = region),color = "seashell2", fill = "seashell", size = 0.3, alpha=0.9)+
geom_point(data = mapa_variacao_anual_45_80,aes(Long, Lat, color = med_turb),size=2, shape=16, position = position_jitter(width = 8)) +
labs(title = "1945 to 1980")+
theme(plot.title = element_text(hjust = 0.5))+
scale_colour_gradient( low = "darkgreen", high = "red")+
xlab("Longitude") + ylab("Latitude")+
theme(legend.title= element_blank())+
theme(panel.background = element_rect(fill = 'aliceblue', colour = 'gray'))`
My plan is to have several plots with determined year ranges and in the end combine all of them in sequence to show temporal variation.
Is there an easy way to combine the plots? I have been looking for solutions online but they seem not to suit my goal or are just too complicated.
Thanks in advance for any help.
You could get gganimate to handle the animation for you:
library(ggplot2)
library(gganimate)
world <- map_data("world")
mapa_variacao_anual_45_80$frames <- as.numeric(
factor(mapa_variacao_anual_45_80$year))
p <- ggplot() +
geom_map(data = world, map = world,
aes(long, lat, map_id = region),
color = "seashell2", fill = "seashell", size = 0.3, alpha = 0.9)+
geom_point(data = mapa_variacao_anual_45_80,
aes(Long, Lat, color = med_turb),
size = 2, shape = 16, position = position_jitter(width = 8)) +
labs(title = "1945 to 1980")+
theme(plot.title = element_text(hjust = 0.5))+
scale_colour_gradient( low = "darkgreen", high = "red") +
geom_text(data = mapa_variacao_anual_45_80,
aes(x = -180, y = 65, label = year), hjust = 0, size = 8,
check_overlap = TRUE) +
xlab("Longitude") +
ylab("Latitude")+
theme(legend.title= element_blank())+
theme(panel.background = element_rect(fill = 'aliceblue', colour = 'gray')) +
transition_events(mapa_variacao_anual_45_80$frames,
enter_length = 1, exit_length = 1)
anim_save("map.gif", p, device = "ragg_png", duration = 20, fps = 30,
width = 900, height = 450)
You can create a series of png files and assemble them into an animation with the gifski package:
library(ggplot2)
library(gifski)
for(i in 1:30){
gg <- ggplot(......)
ggsave(sprintf("myplot%03d.png", i), gg)
}
png_files <- Sys.glob("myplot*.png")
gifski(
png_files,
"myanimation.gif",
width = 400, height = 400,
delay = 1/5 # 5 images per second
)
file.remove(png_files)

Change fill colour of polygon with ggplot2

I have a simple question which I've asked myself many times already. When I am plotting one or more polygons in R using ggplot2, how can I actually change the filling colour? I do not only want to change the outline of the polygon, but the whole thing.
In my first simple plots (ea_map and hb_map) it works fine to assign the colours "yellow" and "purple", however in my final plot "ea_hb_map" (which I've pictured below), the colours are set back to default.
ea <- readOGR("C:/Users/BASELINE/Eastern Arctic/Summer/2010_EA_S/cis_SGRDREA_20100628_pl_a.shp")
hb <- readOGR("C:/Users/BASELINE/Hudson Bay/Summer/2010_HB_S/cis_SGRDRHB_20100628_pl_a.shp")
ea_map <- ggplot() +
geom_polygon(data=ea, aes(x = long, y = lat, group = group), fill = "red")
plot(ea_map)
hb_map <- ggplot() +
geom_polygon(data=hb, aes(x = long, y = lat, group = group), fill = "purple")
plot(hb_map)
ea_df <- tidy(ea)
hb_df <- tidy(hb)
eastern_arctic_map <- ea_map +
geom_sf(data=world, fill = "antiquewhite1") +
coord_sf(xlim = c(-115, -50), ylim = c(50,83), expand = FALSE)+
scale_y_continuous(breaks = c(50, 60, 70, 80)) +
scale_x_continuous(breaks = c(-50, -70, -90, -110)) +
geom_polygon(data = ea_df, aes(x=long, y=lat, group=group, fill="Eastern Arctic"), alpha=0.4) +
labs(fill = "",
x = "lon",
y = "lat") +
theme_grey(base_size = 9) +
theme(legend.key.size = unit(0.8,"line"))
print(eastern_arctic_map)
ea_hb_map <- eastern_arctic_map +
geom_polygon(data=hb_df, aes(x = long, y = lat, group = group, fill = "Hudson Bay"), alpha=0.4)
print(ea_hb_map)

How to fix axis and add polygon to inset map in ggplot2

I'm trying to add a couple details to my map in ggplot2 but I'm new to the package and I'm not sure how to proceed. Code and map are below (ignore the weird spacing on the map, I took a screen shot in Rstudio). Thanks for taking a look!
I'm trying to do the following:
Add latitude and longitude tick marks on the x and y axis. I coded it in the script below but nothing is happening, not sure why - no errors pop up.
If possible, I'd like to add a box in the inset map showing the extent/coverage of the larger map, since the points in the smaller map (the red ones) are barely visible. I'm not sure how to add and place a polygon in the inset map.
Here is what the map currently looks like for reference:
library(raster)
library(ggplot2)
library(ggthemes)
library(ggsn)
library(ggmap)
library(maps)
library(mapdata)
mapdata <- getData("GADM", country = "panama", level = 1)
mymap <- fortify(mapdata)
mypoint <- data.frame(long=c(-79.743, -79.696, -79.645, -79.595),
lat=c(9.160, 9.117, 9.058, 9.015),
group=c("L", "GW", "OGR", "LC"))
mypoint2 <- data.frame(long=c(-79.846, -79.707, -79.665, -79.610),
lat=c(9.181, 9.112, 9.057, 9.014),
group=c("BCI", "G", "EH", "MF"))
g1 <- ggplot() +
geom_blank(data = mymap, aes(x=long, y=lat)) +
geom_map(data = mymap, map = mymap,
aes(group = group, map_id = id),
fill = "#b2b2b2", color = "black", size = 0.3) +
coord_sf(xlim=c(-80,-79.5), ylim=c(8.9, 9.25), expand = FALSE) +
geom_point(data = mypoint, aes(x = long, y = lat),
color = "black", size = 3) +
geom_label(data = mypoint, aes(label = group, x = long, y = lat),
size = 3, fontface = "bold", nudge_x = c(0.015, 0.02, 0.022, 0.018)) +
geom_point(data = mypoint2, aes(x = long, y = lat),
color = "blue", size = 3) +
geom_label(data = mypoint2, aes(label = group, x = long, y = lat),
size = 3, fontface = "bold", nudge_x = c(-0.02, -0.018, -0.02, -0.02)) +
scale_x_continuous(limits = c(-80,-79.5), expand = c(0, 0)) +
scale_y_continuous(limits = c(8.9, 9.25), expand = c(0, 0)) +
theme_map() +
ggsn::scalebar(location = "bottomleft", dist = 5,
transform = TRUE, dist_unit = "km", model = 'WGS84',
x.min = -79.97, x.max = -79.8,
y.min = 8.93, y.max = 9.25) +
north(x.min = -79.6, x.max = -79.5,
y.min = 9.2, y.max = 9.24,
location = "toprgiht", scale = 0.1)
g2 <- ggplotGrob(
ggplot() +
geom_polygon(data = mymap,
aes(x = long, y = lat, group = group),
fill = "#b2b2b2", color = "black", size = 0.3) +
geom_point(data = mypoint, aes(x = long, y = lat),
color = "red", size = 0.5) +
coord_map("polyconic") +
theme_map() +
theme(panel.background = element_rect(fill = NULL))
)
g3 <- g1 +
annotation_custom(grob = g2, xmin = -79.75, xmax = -79.51,
ymin = 8.9, ymax = 9.0)
g3
Latitude and longitude tick marks are disappearing because of theme_map() - it sets axis_ticks and axis_text (among other things) to element_blank(). One way to get them back is to override theme_map() with
g1_with_lbls <- g1 +
theme(
axis.text = element_text(),
axis.ticks = element_line(),
axis.title = element_text()
) +
xlab("Longitude") +
ylab("Lattitude")
You would place the polygon on the smaller map as a part of the ggplotGrob object you are creating
g2 <- ggplotGrob(
ggplot() +
geom_polygon(data = mymap,
aes(x = long, y = lat, group = group),
fill = "#b2b2b2", color = "black", size = 0.3) +
geom_point(data = mypoint, aes(x = long, y = lat),
color = "red", size = 0.5) +
coord_map("polyconic") +
theme_map() +
theme(
panel.background = element_rect(fill = NULL)
) +
geom_rect(
aes(xmin = -80, xmax = -79, ymin = 8.5, ymax = 9.5), fill = NA,
col = "red", size = 1
)
)
Then
g3 <- g1_with_lbls +
annotation_custom(grob = g2, xmin = -79.75, xmax = -79.51,
ymin = 8.9, ymax = 9.0)
g3
Has both the ticks and the rectangle.

Secondary legend on chloropleth for points and polygons, ggplot

I have a map with polygons and points on it - showing countries of interest in the world.
I want legends for both items (points and polygons), but can't add them. The polygon is plotted first (and so has a legend), while the points do not appear on the legend. To try and address this i add
show.legend = T
However the legend then adds the dots on top of the polygon colors as below:
What i want is another legend item with a yellow dot, where i can set the label as i want.
At the moment i am generating the points layer using a separate file. Perhaps i need to do this all from one df with points and polygons included - to generate the points and polygons from a single aes. But i can't think how to do this given my points have no group number.
Here is my code as it stands:
world <- map_data("world")
countries <- read_excel("country_table.xlsx", sheet = 3) #table of coutries with interest
world3 <- merge(world, countries, all.x = TRUE) %>%
arrange(order)
world4 <- world3 %>%
filter(!is.na(interest))
city <- read_excel("country_table.xlsx", sheet = 4) #point data
city$long <- as.numeric(city$long)
city$lat <- as.numeric(city$lat)
ggplot() +
geom_polygon(data = world3, aes(x = long, y = lat, group = group),
fill = "light grey") +
geom_polygon(data = world4, aes(x = long, y = lat, group = group, fill = interest),
col = "white") +
scale_fill_manual(name = "Interest/Support:",
breaks = c("interest", "past", "current"),
values = c(interest = "#a7ef88", past = "#3a7f1d", current = "#1b5104"),
labels = c("interest", "past", "current")) +
theme_map() +
theme(legend.position = "bottom") +
coord_fixed(xlim = c(-130, 160),
ylim = c(-50, 75),
ratio = 1.4) +
geom_point(data = city, aes(x= long, y = lat),
shape = 21, inherit.aes = F, size = 2, col = "black", fill = "yellow", show.legend = T)
Any thoughts?
Final code for the ggplot section posted below. Thanks to aosmith.
ggplot() +
#create base plot all polygons in grey
geom_polygon(data = world3, aes(x = long, y = lat, group = group),
fill = "light grey") +
#create chloropleth layer for countries with data
geom_polygon(data = world4, aes(x = long, y = lat, group = group, fill = interest),
col = "white") +
#add map theme from ggthemes
theme_map() +
#Set the zoom
coord_fixed(xlim = c(-130, 160),
ylim = c(-50, 75), ratio = 1.4) +
#Add city layer - include col in aes() to get city as a separate legend item
geom_point(data = city, aes(x= long, y = lat, col = interest),
shape = 21, inherit.aes = F, size = 3, fill = "yellow") +
#set fill for countries by interest (include city (special) to have the correct number of aesthetics)
scale_fill_manual(name = NULL,
breaks = c("interest", "past", "current", "special"),
values = c(interest = "#a7ef88", past = "#3a7f1d", current = "#1b5104", special = "yellow"),
labels = c("interest", "past", "current", "city")) +
#set color for cities and labels for cities legend
scale_color_manual(name = NULL,
breaks = c("special"),
values = c(special = "black"),
labels = c("cities")) +
#set order of legend items (fill first)
guides(fill = guide_legend(order = 1), color = guide_legend(order = 2)) +
#set legend position and vertical arrangement
theme(legend.text = element_text(size = 9), legend.position = "bottom", legend.box = "vertical")
Gives the following:

Mapping issue with fill when plotting multiple countries

I am trying to plot a map with Peru and Ecuador, that presents two simple lat and long points (San Jose and Lima in Peru).
I'm having some issue with the fill when incorporating both Peru and Ecuador into my map.
library(ggplot2)
library(ggmap)
library(maps)
library(mapdata)
peru_ecuador <- map_data("world",c("peru", "ecuador"))
# Add study site points (San Jose and Lima)
points <- data.frame(
long = c(-79.81, -77.04),
lat = c(-6.77, -12.04),
names = c("San Jose", "Lima"),
stringsAsFactors = FALSE
)
# Plot the map
ggplot() +
geom_polygon(data = peru_ecuador, aes(x=long, y = lat), fill = "grey40", color
= "grey90", alpha = 1) +
geom_point(data = points, aes(x = long, y = lat), color = "red", size = 2,
alpha = 0.8) +
geom_text(aes(x = long, y = lat, label = c("San Jose", "Lima")), data =
points, size = 2, hjust = 1.3) +
geom_area(x = 10) +
coord_fixed(1.3) +
labs(x = "Longitude", y = "Latitude", size = 2) +
theme_bw(base_size = 5)
I would also really love some advise on how best to resize the plot area window of the map. As in change the x and y axis width and length. When I plot just a map of Peru, some of my map information is cut off by the size of the plot area. Please see below:
peru <- map_data("world","peru")
ggplot() +
geom_polygon(data = peru, aes(x=long, y = lat), fill = "grey40", color =
"grey90", alpha = 1) +
geom_point(data = points, aes(x = long, y = lat), color = "red", size = 2,
alpha = 0.8) +
geom_text(aes(x = long, y = lat, label = c("San Jose", "Lima")), data =
points, size = 2, hjust = 1.3) +
geom_area(x = 10) +
coord_fixed(1.3) +
labs(x = "Longitude", y = "Latitude", size = 2) +
theme_bw(base_size = 5)

Resources