Reputation: 473
I use ggplot2
and a package called rnaturalearth
to develop a map of European countries, with different colour for each country dependent on each country's score.
The problem: I want to define which value ggplot2
uses when defining colours for each country. Now, ggplot2
uses the lowest and highest values to define the extremes of the scale; I want to define the extremes by myself (that is, use lower and higher extreme values and thereby manipulate the colours).
Data:
Data <- structure(list(iso_a2 = structure(c("AT", "BE", "CH", "CZ", "DE",
"DK", "ES", "FI", "FR", "GB", "GR", "HU", "IE", "IT", "LU", "NL",
"NO", "PL", "PT", "SE", "SI"), label = "Country", format.stata = "%2s"),
values = c(0.498210763764124, 0.39731454174295, 1.28199768407053,
-0.645219093750782, 0.0505441315876436, 1.91304897270232,
0.0802428116303039, 1.40711329859048, 0.0627266707521129,
0.191581882192026, 0.181001731032278, 0.356882787996765,
0.168525492955127, 0.276086485962419, 1.12477750307519, 0.892265586989629,
1.22957941831254, -0.942690852748792, -0.412722832958249,
1.34589962077675, -0.484403677107108)), row.names = c(NA,
-21L), class = c("data.frame"))
This is the code I'm currently running:
# Load packages
library(tidyverse)
library(rnaturalearth)
# Use map from rnaturalearth, restrict to European countries
world <- ne_countries(scale = "medium", returnclass = "sf")
Europe <- world[which(world$continent == "Europe"), ]
# Add Data to the map
Data <- merge(Europe, Data, by = "iso_a2", all = TRUE)
# Draw map with colours
ggplot(Data) +
geom_sf(aes(fill = -values), size = 0.25) +
coord_sf(xlim = c(-10.8, 32), ylim = c(35, 71.3), expand=FALSE) +
theme(legend.position = "none") +
theme(
axis.text.x = element_blank(),
axis.text.y = element_blank(),
axis.ticks = element_blank(),
panel.grid.major = element_blank(),
panel.background = element_blank()) +
scale_fill_continuous(na.value = "grey90")
The result is:
I would like to manipulate these colours not by defining the colours per se, but by manipulating the scale ggplot2
uses (now presumable going from the lowest to the highest value in data$values
).
Manipulating the colours directly by using scale_fill_gradient
would not be a good idea since I am developing several maps and the whole idea is that a specific value should result in the same colour independently of what values are represented in the specific map.
EDIT. I have decided to use a simple solution, adding two rows to the data frame with constant extreme values across all maps.
Something like:
df_high <- data.frame("SJ", 1.63, 2.2)
df_low <- data.frame("AZ", -1.5, -2.02)
names(df_high) <- c("cntry", "values_1", "values_2")
names(df_low) <- c("cntry", "values_1", "values_2")
new_map_2010 <- rbind(old_map_2010, df_high, df_low)
new_map_2012 <- rbind(old_map_2012, df_high, df_low)
This is not a programmer's solution, but it is easier for me than what appears to be the alternative solution. Consequently, I am not able to decide whether the solution below by @Pedro Alencar works or not.
So PLEASE, if anyone tries Pedro Alencar's suggestion and finds it works, please tell me and I will accept his solution. For now, I can only upvote it.
(My own solution can easily be adapted by using code to identify the highest and lowest values across all data frames, then add new rows with these values - and add these specific rows to all data frames. All done with code, but still not really a programmer's solution...)
Upvotes: 2
Views: 204
Reputation: 1089
Create a data frame with values (rounded) and colours:
df_colors <- data.frame(values_round = seq(round(min(Data$values, na.rm = T),2),
round(max(Data$values, na.rm = T),2),
by = 0.01))
df_colors$color <- grDevices::colorRampPalette(brewer.pal(9, "Blues"))(nrow(df_colors))
df_colors$values_round <- as.integer(df_colors$values_round*100)
See that I turned the values to integer. This is because I was facing some rounding errors.
Then create a new column values_round
in your original data frame (Data
) and left_join
with df_colors
:
Data$values_round <- as.integer(round(Data$values, 2)*100)
Data <- left_join(Data, df_colors, by = 'values_round')
Now you can plot:
ggplot(Data) +
geom_sf(aes(fill = color), size = 0.25) +
coord_sf(xlim = c(-10.8, 32), ylim = c(35, 71.3), expand=FALSE) +
theme(legend.position = "none") +
theme(
axis.text.x = element_blank(),
axis.text.y = element_blank(),
axis.ticks = element_blank(),
panel.grid.major = element_blank(),
panel.background = element_blank()) +
scale_colour_identity(aesthetics = "fill")
Note that you'll need to identify the maximum and minimum for your entire dataset in order to get a fixed df_colors
.
Upvotes: 1