How do I add a legend using aes, ggplot2 and maps? - r

I'm trying to make a map with points plotted for the Canadian prairie provinces, but I'm having no luck adding in a legend to my map. I'm very new to mapping in r, so I'm not understanding how I should include aes to get a legend. My data for siteDataTrees is from an excel csv file and the top looks like this:
siteDataTrees
and the data for siteDataBoth is also from a csv file and the top looks like this:
siteDataBoth.
Here's what I have so far for my code:
library(maps)
library(ggplot2)
library(sf)
prairies1 <- map("worldHires","Canada", xlim = c(-120,-87), ylim = c(49,61),
plot = FALSE, fill = TRUE)
prairies <- st_as_sf(prairies1)
ggplot(data = prairies) +
geom_sf() +
geom_point(data = siteDataTrees, aes(x = long, y = lat), size = 2.5, pch = 21,
fill = "purple", show.legend = TRUE) +
geom_point(data = siteDataBoth, aes(x = long, y = lat), size = 2.5, pch = 21,
fill = "light green", show.legend = TRUE) +
geom_text(data = locations, aes(x = long, y = lat, label = name),
size = 2, col = "black", check_overlap = FALSE) +
annotation_scale(location = "tr", width_hint = 0.2) +
ggtitle("Climate Stations and Tree Chronology Locations for South AB") +
labs(x = "latitude", y = "longitude") +
theme(legend.position = "right") +
coord_sf(xlim = c(-115, -110), ylim = c(48.9, 50.49), expand = FALSE)
I've also included a map to show what it looks like without the legend.
How should I take the data frame prairies and use it with aes to include a legend? Is there another way to add in a legend in ggplot2 without using the aes function? Thank you in advance for your help and please let me know if something is missing as this is my first posting

Let me give you a couple of examples on how to work out a legend using a slightly modified example from r-spatial.
First we prepare the data:
library(maps)
library(ggplot2)
library(sf)
library(rnaturalearth)
library(rnaturalearthdata)
world <- ne_countries(scale = "medium", returnclass = "sf")
(sites <- data.frame(longitude = c(-80.144005, -80.109),
latitude = c(26.479005,26.83),
type = c("tree", "station")))
Now we plot. Case 1: color is not an issue
ggplot(data = world) +
geom_sf() +
geom_point(data = sites,
aes(x = longitude, y = latitude, fill = type),
size = 4,
shape = 23) +
coord_sf(xlim = c(-88, -78), ylim = c(24.5, 33), expand = FALSE) +
theme(legend.position = "bottom")
Case 2: fill color is an issue.
Here we can use a named vectors to pass the colors and the labels we want by type of point. For example:
mapfill <- c('tree' = "forestgreen", 'station' = "purple")
maplab <- c('tree' = "trees in prairies", 'station' = "Stations in prairies")
Then we plot combining both mapfill and maplab:
ggplot(data = world) +
geom_sf() +
geom_point(data = sites, aes(x = longitude, y = latitude, fill = type), size = 4,
shape = 23) +
scale_fill_manual(values = mapfill, labels = maplab) +
coord_sf(xlim = c(-88, -78), ylim = c(24.5, 33), expand = FALSE) +
theme(legend.position = "bottom")
Remark 1 If you do not want type in the legend title you can either delete it using legend. title = element_blank() within theme
Remark 2 If, instead of fill, you are using color, use function scale_color_manual. If you are combining both fill and color do the same with scale_***_manual
In spirit of full disclosure, if you do not mind the colors and you want a quick fix (and I cannot stress this enough) you can also code fill = "TextYouWantInLegend" within aes. See following example:
ggplot(data = world) +
geom_sf() +
geom_point(data = sites[1,], aes(x = longitude, y = latitude, fill = "toto"), size = 4,
shape = 23) +
geom_point(data = sites[2,], aes(x = longitude, y = latitude, fill = "koko"), size = 4,
shape = 23) +
coord_sf(xlim = c(-88, -78), ylim = c(24.5, 33), expand = FALSE) +
theme(legend.position = "bottom")

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

How to use several symbols, colour, and fill in ggmap without changing the legend colour in R?

I'm using ggmap to plot some filled points across the ocean but they overlap so I used colour=black to give them an outline. When I use pch=21 the legend doesn't change and the points are outlined in black like I want. But, I am trying to get 3 different symbols on the map as well. When I specify the different symbols my points in the legend all turn black.
Here is some sample data and the code I used to get the map with the correct legend but wrong symbols
#library
library(ggmap)
library(mapdata)
library(ggplot2)
#sample
mapoc_temp = data.frame(longitude= c(-64.5, -63.1, -62.4, -62.2, -66.0, -61.9),
latitude= c(42.7, 44.8, 45.8, 45.6, 43.0, 40.2),
Zone = sample(c(1,4,6,7), 6, replace = T),
location = sample(c(1,2,3), 6, replace = T))
#map
canada = map_data("worldHires")
ggplot(data = canada) +
borders("world", xlim = c(-130, -60), ylim = c(20, 50), colour = "black", fill = "grey50") +
geom_polygon(data = canada, aes(x=long, y = lat, group = group), fill = "grey50") +
#coordinates of my map
coord_sf(xlim=c(-84, -41), ylim=c(24,51), expand = FALSE) +
#map the receiver locations
geom_point(data = mapoc_temp,
mapping = aes(x = longitude,
y = latitude,
fill = Zone),
pch = 21,
size = 15, colour = "black") +
#fill the zones
scale_color_manual(values=c("#01579B", "#4FC3F7", "#ffa600", "#ff6361")) +
scale_fill_manual(values=c("#01579B", "#4FC3F7", "#ffa600", "#ff6361"))
and this is what the map looks like
When I try to add the symbols, I get the correct symbols but my legend isn't correct anymore. Below is the code and image.
ggplot(data = canada) +
borders("world", xlim = c(-130, -60), ylim = c(20, 50), colour = "black", fill = "grey50") +
geom_polygon(data = canada, aes(x=long, y = lat, group = group), fill = "grey50") +
#coordinates of my map
coord_sf(xlim=c(-84, -41), ylim=c(24,51), expand = FALSE) +
#map the receiver locations
geom_point(data = mapoc_temp,
mapping = aes(x = longitude,
y = latitude,
fill = as.factor(Zone)),
pch = pch = if_else(mapoc_temp$location == 1,25,
if_else(mapoc_temp$location == 3, 23, 21)),
size = 15, colour = "black") +
scale_x_continuous(label = abs) +
scale_y_continuous(label = abs) +
#fill the zones in with viridis
scale_color_manual(values=c("#01579B", "#4FC3F7", "#ffa600", "#ff6361")) +
scale_fill_manual(values=c("#01579B", "#4FC3F7", "#ffa600", "#ff6361"))
Does anyone know how to fix the legend in the second image so that the points are the correct colours? I don't need the symbols to be in the legend
Actually, your issue is due to a bug described here: https://github.com/tidyverse/ggplot2/issues/2322.
To go over, you can do:
ggplot(data = canada) +
borders("world", xlim = c(-130, -60), ylim = c(20, 50), colour = "black", fill = "grey50") +
geom_polygon(data = canada, aes(x=long, y = lat, group = group), fill = "grey50") +
#coordinates of my map
coord_sf(xlim=c(-84, -41), ylim=c(24,51), expand = FALSE) +
#map the receiver locations
geom_point(inherit.aes = FALSE, data = mapoc_temp,
mapping = aes(x = longitude,
y = latitude,
fill = factor(Zone),
shape = factor(location)),
size = 5) +
scale_x_continuous(label = abs) +
scale_y_continuous(label = abs) +
#fill the zones in with viridis
scale_fill_manual(name = "Zone", values=c("#01579B", "#4FC3F7", "#ffa600", "#ff6361"), breaks = c("1","4","6","7")) +
scale_shape_manual(values = c("1" = 21, "2" = 22, "3" = 24))+
guides(fill = guide_legend(override.aes=list(shape=21)), shape = FALSE)
As mentioned by #Edward, you can get rid of the shape legend by adding guides(shape = FALSE).
Does it answer your question ?
I don't have your data, so I will use the good ol' mtcars dataset. The trick is to assign the shapes manually, otherwise, ggplot will complain "A continuous variable can not be mapped to shape".
mtcars$shape <- ifelse(mtcars$cyl==4, 21, ifelse(mtcars$cyl==6, 23, 25))
ggplot(mtcars, aes(wt, mpg)) +
geom_point(aes(fill = factor(cyl), shape=factor(cyl)), col="black", size=3) +
scale_shape_manual(values=c(21,23,25))
For your own data, try:
mapoc_temp$shape <- factor(mapoc_temp$location + 20)
geom_point(data = mapoc_temp,
mapping = aes(x = longitude,
y = latitude,
fill = factor(Zone),
shape= shape),
size = 15, colour = "black") +
scale_shape_manual(values=c(21,22,23)) + # Must be same length as unique location.
guides(shape=FALSE) + # If you don't want an extra shape legend.
guides(fill = guide_legend(override.aes=list(shape=21))) # A necessary fudge

r showing shape file incorrectly while scaling up the dimensions in ggplot2

I am trying to open world map and to increase its dimension to look only on Europe.When I plot all map in ggplot?, there is no problem
:
shape <- readOGR(dsn = "/home/user/QGis/50m_physical", layer = "ne_50m_land")
map_2 <- ggplot() +
geom_polygon(data = shape,
aes(x = long, y = lat, group = group),
colour = "black",
fill = NA)
When I try to increase dimensions,
shape <- readOGR(dsn = "/home/user/QGis/50m_physical", layer = "ne_50m_land")
map_2 <- ggplot() +
geom_polygon(data = shape,
aes(x = long,
y = lat,
group = group),
colour = "black",
fill = NA)+
scale_x_continuous(name="Longitude", limits=c(-40, 90))+
scale_y_continuous(name="Latitude", limits=c(30, 80))
it shows me some additional lines:
How can I solve this problem?
I can't reproduce your example, since I do not have the data.
However I suspect that replacing
scale_x_continuous(name="Longitude", limits=c(-40, 90))+
scale_y_continuous(name="Latitude", limits=c(30, 80))
with
coord_cartesian(xlim =c(-40, 90), ylim = c(30, 80))
fixes the problem

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