Secondary legend on chloropleth for points and polygons, ggplot - r

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:

Related

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 do I add a legend using aes, ggplot2 and maps?

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

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

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)

Recentering state abbreviation on ggplot2

So I modified the shape profile to add Hawaii and Alaska and so my data frame is using a different long, lat coordinates than the stock state coordinates provided by maps package (map_data("state")) shown below
states <- data.frame(state.center, state.abb)
states
x y state.abb
1 -86.7509 32.5901 AL
2 -127.2500 49.2500 AK
3 -111.6250 34.2192 AZ
4 -92.2992 34.7336 AR
5 -119.7730 36.5341 CA
My data frame have coordinates as follow.
When I plot it using the code below I get a map without any state abbreviation labels.
p <- function(data, brks, title) {
ggp <- ggplot() +
geom_polygon(data = data, aes(x = long, y = lat, group = group,
fill = IMSUB), color = "black", size = 0.15) +
scale_fill_gradient2(limits=c(-1,1), breaks = c(-1, 0, 1), labels=c("Trump", 0, "Clinton"), low = "red", mid = "white",
high = "blue", midpoint = 0, space = "Lab",
na.value = "grey50", guide = "colourbar") +
theme_nothing(legend = TRUE) + labs(title = title, fill = "") +
geom_text(data = states, aes(x = x, y = y, label = state.abb), size = 3)
return(ggp)
}
i feel like I can replace the coordinates in states data frame with one in us50 but I am not sure how to replace them correctly.
Did you try it with the size inside the aes()?
geom_text(data=state, aes(x y, label = state.abb, size=3)
If not, this other method will likely work instead, just replace the geom_text line:
with(states, annotate(geom="text", x = x y=y, label = state.abb, size = 3))
It should apply annotation using states, as text with x & y as your lat and long..That should work.

Resources