lostpineapple45
lostpineapple45

Reputation: 93

Two continuous color gradients separated discretely in an R ggplot

I have a heat map of US data by state (using dummy data), and I'm trying to get it to run a color gradient continuously from dark red to light red from [0,50] and from light green to dark green from (50,100].

If I try using one gradient from red to green it gets quite brown in the middle and if I run from red to white to green it becomes tough to read with the middle colors. Can anyone help me find a way to perform two continuous color gradients on the same map?

Here is my code:

library(ggplot2)
library(fiftystater)
library(colorplaner)
library(RColorBrewer)



# prepare data frame
data("fifty_states") 


dft <- data.frame(state=tolower(rownames(USArrests)), USArrests)
names(dft)[names(dft)=='Murder'] <- 'Var1'
dft<-dft[,-c(3:5)]


# create data
dft$Var1 <- runif(50,0, 100)






# map to each state's data
p <- ggplot(dft, aes(map_id = state)) + 
# map points to the fifty_states shape data
  geom_map(aes(fill = Var1), map = fifty_states, color = 'gray') + 
  expand_limits(x = fifty_states$long, y = fifty_states$lat) +
  coord_map() +
  scale_x_continuous(breaks = NULL) + 
  scale_y_continuous(breaks = NULL) +
  labs(x = "", y = "") +
  theme(legend.position = "bottom", 
        panel.background = element_blank())

p+ fifty_states_inset_boxes() 

Going from red to white to green continuously

pc <- p+scale_fill_gradient2(low='darkred',
                             mid = 'white', 
                             high='darkgreen', 
                             midpoint = 50)

pc + fifty_states_inset_boxes() + theme(legend.position = "right")

I found this palette stuff online, but am totally new to it and wasn't able to find a solution playing with it. But it could be useful and I just don't know enough about it.

#TEST

palette <- colorRampPalette(rev(brewer.pal(11,"Spectral")))

pcn <- p+scale_fill_gradientn(colours = palette(4))

pcn + fifty_states_inset_boxes() + theme(legend.position = "right")

Upvotes: 2

Views: 1052

Answers (1)

missuse
missuse

Reputation: 19716

Here is the idea by Andrew Gustar explained a bit further:

pc <- p + scale_fill_gradientn(colors = c("darkred", "tomato1","palegreen", "darkgreen"),
                             values = scales::rescale(c(min(dft$Var1),
                                                      (max(dft$Var1)-min(dft$Var1))/3,
                                                      (max(dft$Var1)-min(dft$Var1))*2/3,
                                                      max(dft$Var1))))

pc + fifty_states_inset_boxes() + theme(legend.position = "right")

enter image description here

This is equivalent to: values = c(0, 1/3, 2/3, 1)

scale_fill_gradientn takes a vector of any number of colors and maps them to the values in your data - you can control the mapping with the values argument which takes the range 0 - 1. scales::rescale scales an arbitrary range vector to 0 - 1 range.

It's can be visually pleasing to use

quantile(dft$Var1, seq(0, 1, length.out = n)) #n depending on the number of colors

to define the values. Example:

pc <- p+scale_fill_gradientn(colors = c("darkred", "tomato1","palegreen", "darkgreen"),
                             values = scales::rescale(quantile(dft$Var1, seq(0, 1, length.out=4))))

pc + fifty_states_inset_boxes() + theme(legend.position = "right")

enter image description here

Finally, as Andrew Gustar suggested values = c(0, 0.5, 0.5001, 1)) would provide the gradient you asked in the OP: from dark red to light red from [0,50] and from light green to dark green from (50,100]. Giving:

enter image description here

Upvotes: 3

Related Questions