Edit boundaries in a map with ggplot2 - r

I have created a map with ggplot2. So far I am happy with my plot but I was wondering whether it is possible to edit the boundaries that separate each of the regions within the map. I know that adding geom_path() you can explicitly incorporate them but I have not figured out how to edit the level of thickness. Is anyone familiar with how to do this? Many thanks in advance.
The code I have used is the following:
library(ggplot2)
library(RColorBrewer)
ex_sector = ggplot(data_mapping, aes(long, lat, group=group, fill = entry_cat)) +
scale_fill_brewer(type = "seq", palette = "Greens") + geom_polygon() + geom_path(colour = "black")
ggsave("test_fill.png", ex_sector, scale = 0.5)
An the output is:

Related

ggplot2 plotting coordinates on map using geom_point, unwanted lines appearing between points

I am trying to plot a set of lat/long coordinates on a map of the USA using ggplot2, here is my code:
states <- map_data("state")
usamap <- ggplot(states, aes(long, lat, group=1)) +
geom_polygon(fill = "white", colour = "black") +
geom_point(data = data_masks2, aes(x = lng, y = lat), alpha = 1, size = 1) +
theme_cowplot()
However, when I plot usamap I am getting strange lines connecting some of the points (seen below), and I am unsure why. Why are these appearing, and how do I get rid of them?
Thanks in advance
There's a very helpful vignette available here for creating maps, but the issue is with your geom_polygon() line. You definitely need this (as it's the thing responsible for drawing your state lines), but you have the group= aesthetic wrong. You need to set group=group to correctly draw the lines:
ggplot(states, aes(long, lat, group=group)) +
geom_polygon(fill = "white", colour = "black")
If you use group=1 as you have, you get the lines:
ggplot(states, aes(long, lat, group=1)) +
geom_polygon(fill = "white", colour = "black")
Why does this happen? Well, it's how geom_polygon() (and ggplot in general) works. The group= aesthetic tells ggplot what "goes together" for a geom. In the case of geom_polygon(), it tells ggplot what collection of points need to be connected in order to draw a single polygon- which in this case is a single state. When you set group=1, you are assigning every point in the dataset to belong to the same polygon. Believe it or not, the map with the weird lines is actually composed of a single polygon, with points that are drawn in sequence as they are presented.
Have a look at your states dataset and you will see that there is states$group, which is specifically designed to allow you to group the points that belong to each state together. Hence, we arrive at the somewhat confusing statement: group=group. This means "Set the group= aesthetic to the value of the group column in states, or states$group."

Draw legend with geom_sf when no aesthetic is specified

When drawing maps using ggplot/geom_sf, any layer mapped to an aesthetic is represented in the legend. I am also aware that using show.legend = ... can be used to force legend representation and to manipulate the symbology used (point, line, polygon). However, when plotting simple objects without the need to further map them to an aesthetic, i.e. using colour/fill to show aditional information, no legend entry is given. This also seems to be the case when using show.legend = TRUE. I found this question on GitHub: https://github.com/tidyverse/ggplot2/issues/3636 . I am not quite sure, whether the person asking was undestood correctly, but there didn't seem to be a good answer. So, using his code:
library(ggplot2)
library(sf)
nc <- st_read(system.file("shape/nc.shp", package = "sf"))
ggplot(nc) + geom_sf(show.legend = TRUE)
fails to produce a legend. I would like the legend to simply show a line in the same colour as shown in the map and give a name for that layer. I can add a legend, using this workaround:
ggplot() +
geom_sf(aes(fill = "US State borders"), nc, show.legend = "line")
However, this now changes the colour of the plotted layer. Ok, so let's try to specify a colour:
ggplot() +
geom_sf(aes(fill = "US State borders"), nc, fill = "grey", show.legend = "line")
Whoops, lost the legend again, probably because I have now specified fill twice. Is this really not possible using ggplot/geom_sf?
If I understand the question correctly, it should work if you specify the fill color in scale_fill_manual():
ggplot() +
geom_sf(aes(fill = "US State borders"), nc, show.legend = "line") +
scale_fill_manual(values = 'grey') +
labs(fill = '') # removing legend title

Add a box for the NA values to the ggplot legend for a continuous map

I have got a map with a legend gradient and I would like to add a box for the NA values. My question is really similar to this one and this one. Also I have read this topic, but I can't find a "nice" solution somewhere or maybe there isn't any?
Here is an reproducible example:
library(ggplot2)
map <- map_data("world")
map$value <- setNames(sample(-50:50, length(unique(map$region)), TRUE),
unique(map$region))[map$region]
map[map$region == "Russia", "value"] <- NA
ggplot() +
geom_polygon(data = map,
aes(long, lat, group = group, fill = value)) +
scale_fill_gradient2(low = "brown3", mid = "cornsilk1", high = "turquoise4",
limits = c(-50, 50),
na.value = "black")
So I would like to add a black box for the NA value for Russia. I know, I can replace the NA's by a number, so it will appear in the gradient and I think, I can write a workaround like the following, but all this workarounds do not seem like a pretty solution for me and also I would like to avoid "senseless" warnings:
ggplot() +
geom_polygon(data = map,
aes(long, lat, group = group, fill = value)) +
scale_fill_gradient2(low = "brown3", mid = "cornsilk1", high = "turquoise4",
limits = c(-50, 50),
na.value = "black") +
geom_point(aes(x = -100, y = -50, size = "NA"), shape = NA, colour = "black") +
guides(size = guide_legend("NA", override.aes = list(shape = 15, size = 10)))
Warning messages:
1: Using size for a discrete variable is not advised.
2: Removed 1 rows containing missing values (geom_point).
One approach is to split your value variable into a discrete scale. I have done this using cut(). You can then use a discrete color scale where "NA" is one of the distinct colors labels. I have used scale_fill_brewer(), but there are other ways to do this.
map$discrete_value = cut(map$value, breaks=seq(from=-50, to=50, length.out=8))
p = ggplot() +
geom_polygon(data=map, aes(long, lat, group=group, fill=discrete_value)) +
scale_fill_brewer(palette="RdYlBu", na.value="black") +
coord_quickmap()
ggsave("map.png", plot=p, width=10, height=5, dpi=150)
Another solution
Because the original poster said they need to retain the color gradient scale and the colorbar-style legend, I am posting another possible solution. It has 3 components:
We need to trick ggplot into drawing a separate color scale by using aes() to map something to color. I mapped a column of empty strings using aes(colour="").
To ensure that we do not draw a colored boundary around each polygon, I specified a manual color scale with a single possible value, NA.
Finally, guides() along with override.aes is used to ensure the new color legend is drawn as the correct color.
p2 = ggplot() +
geom_polygon(data=map, aes(long, lat, group=group, fill=value, colour="")) +
scale_fill_gradient2(low="brown3", mid="cornsilk1", high="turquoise4",
limits=c(-50, 50), na.value="black") +
scale_colour_manual(values=NA) +
guides(colour=guide_legend("No data", override.aes=list(colour="black")))
ggsave("map2.png", plot=p2, width=10, height=5, dpi=150)
It's possible, but I did it years ago. You can't use guides. You have to set individually the continuous scale for the values as well as the discrete scale for the NAs. This is what the error is telling you and this is how ggplot2 works. Did you try using both scale_continuous and scale_discrete since your set up is rather awkward, instead of simply using guides which is basically used for simple plot designs?

`fill` scale is not shown in the legend

Here is my dummy code:
set.seed(1)
df <- data.frame(xx=sample(10,6),
yy=sample(10,6),
type2=c('a','b','a','a','b','b'),
type3=c('A','C','B','A','B','C')
)
ggplot(data=df, mapping = aes(x=xx, y=yy)) +
geom_point(aes(shape=type3, fill=type2), size=5) +
scale_shape_manual(values=c(24,25,21)) +
scale_fill_manual(values=c('green', 'red'))
Resulting plot has a legend but it's 'type2' section doesn't reflect scale of fill value - is it by design?
I know this is an old thread, but I ran into this exact problem and want to post this here for others like me. While the accepted answer works, the less risky, cleaner method is:
library(ggplot2)
ggplot(data=df, mapping = aes(x=xx, y=yy)) +
geom_point(aes(shape=type3, fill=type2), size=5) +
scale_shape_manual(values=c(24,25,21)) +
scale_fill_manual(values=c(a='green',b='red'))+
guides(fill=guide_legend(override.aes=list(shape=21)))
The key is to change the shape in the legend to one of those that can have a 'fill'.
Here's a different workaround.
library(ggplot2)
ggplot(data=df, mapping = aes(x=xx, y=yy)) +
geom_point(aes(shape=type3, fill=type2), size=5) +
scale_shape_manual(values=c(24,25,21)) +
scale_fill_manual(values=c(a='green',b='red'))+
guides(fill=guide_legend(override.aes=list(colour=c(a="green",b="red"))))
Using guide_legend(...) with override_aes is a way to influence the appearance of the guide (the legend). The hack is that here we are "overriding" the fill colors in the guide with the colors they should have had in the first place.
I played with the data and came up with this idea. I first assigned shape in the first geom_point. Then, I made the shapes empty. In this way, outlines stayed in black colour. Third, I manually assigned specific shape. Finally, I filled in the symbols.
ggplot(data=df, aes(x=xx, y=yy)) +
geom_point(aes(shape = type3), size = 5.1) + # Plot with three types of shape first
scale_shape(solid = FALSE) + # Make the shapes empty
scale_shape_manual(values=c(24,25,21)) + # Assign specific types of shape
geom_point(aes(color = type2, fill = type2, shape = type3), size = 4.5)
I'm not sure if what you want looks like this?
ggplot(df,aes(x=xx,y=yy))+
geom_point(aes(shape=type3,color=type2,fill=type2),size=5)+
scale_shape_manual(values=c(24,25,21))

Why does coord_map produce a weird output?

I'm trying to draw a world map using ggplot. My code is in my gist file. The output is correct when I don't use coord_map but very strange when I use coord_map :
ggplot(data = test, aes(fill = x)) +
geom_map(aes(map_id = id), map =world.ggmap, color = "white") +
expand_limits(x = world.ggmap$long, y = world.ggmap$lat) +
theme_tufte() +
coord_map()
ggplot(data = test, aes(fill = x)) +
geom_map(aes(map_id = id), map =world.ggmap, color = "white") +
expand_limits(x = world.ggmap$long, y = world.ggmap$lat) +
theme_tufte()
I've got the same error when I use data from the maps package :
library(ggplot2)
library(maps)
world <- map_data("world")
ggplot() +
geom_map( data=world, aes(x=long, y=lat, group = group, map_id = region),colour="white", fill="grey10", map = world ) +
coord_map()
Does anyone has an answer ?
I had a similar problem before, due to longitude values outside the range [-180,180]. In your example the data do not have this problem but my trick seems to work also here. In my case I just used 'xlim' to exclude the problematic data.
This solution seems to work in your case also (I used the code from your gist):
map+coord_map(xlim=c(-180,180))
It produces the following map:
There is still a problem with Antarctica, you can also consider clipping it too if you don't need this area:
map+coord_map(xlim=c(-180,180), ylim=c(-60, 90))
Another solution is to use wrld_simpl from maptools instead, but it retains issues with Antarctica.
require(maptools)
require(ggmap)
md <- map_data("world2")
data(wrld_simpl)
ggplot(wrld_simpl, aes(group = group, x = long, y = lat)) +
geom_map() +
coord_map()
I'm sure that is quite late but the same problem is still happening in ggplot.
If you're trying to zoom-in use the following approach.
ggplot()+...+xlim(c(-100, -25))+ ylim(c(-60, 20))
Good luck!

Resources