Ggplot2 Heatmap with Colors for Ranged Values

ggplot2 heatmap with colors for ranged values

You have several options for something like this, but here is one as a starting point.

First, use cut to create a factor from Y with the appropriate ranges:

dat$Y1 <- cut(dat$Y,breaks = c(-Inf,-3:3,Inf),right = FALSE)

Then plot using a palette from RColorBrewer:

ggplot(data =  dat, aes(x = Row, y = Col)) + 
geom_tile(aes(fill = Y1), colour = "white") +
scale_fill_brewer(palette = "PRGn")

Sample Image

This color scheme is more purple than blue on the low end, but it's the closest I could find among the brewer palette's.

If you wanted to build your own, you could simply use scale_fill_manual and specify your desired vector of colors for the values argument.

Make ggplot2 heatmap with different colors for values over/under thresholds

This approach is a potential solution, but the figure looks a little 'weird' as the colors (Perc Diff) and label (stuff) sometimes match, sometimes don't match.

Regardless, here is how I would split the dataset into 3 'groups' for plotting (<= -100 , > -100 & < 100, >= 100):

ggplot(plot30) +
geom_tile(data = plot30 %>% filter(Perc_Diff < 100 & Perc_Diff > -100),
aes(x = Comp_Data,
y = factor(Station, levels = unique(Station)),
fill = Perc_Diff), color='black') +
geom_tile(data = plot30 %>% filter(Perc_Diff <= -100),
aes(x = Comp_Data,
y = factor(Station, levels = unique(Station))),
fill = "blue", color='black') +
geom_tile(data = plot30 %>% filter(Perc_Diff >= 100),
aes(x = Comp_Data,
y = factor(Station, levels = unique(Station))),
fill = "yellow", color='black') +
geom_text(aes(x = Comp_Data,
y = factor(Station, levels = unique(Station)),
label = stuff)) +
scale_fill_gradient2(low = "green", mid = 'white', high = "red",
limits=c(min(plot30$Perc_Diff,na.rm=T),
max(plot30$Perc_Diff,na.rm=T))) +
ggtitle(paste('30 Day Precipitation Comparison (Inches) for', "date_30",'to',"date_1",'\nCell Values Represent Differences (SD Mesonet minus QPE; Inches)')) +
theme(legend.key.height = unit(3, "cm")) +
theme(axis.title = element_blank()) +
theme(plot.title = element_text(hjust = 0.5)) +
theme(panel.background = element_blank()) +
theme(axis.ticks = element_blank()) +
theme(axis.text.y = element_text(margin = margin(r = 0))) +
theme(legend.title = element_blank()) +
theme(legend.text = element_text(colour="black", size = 14, face = "bold")) +
theme(axis.text = element_text(size = 12, colour = "black", face='bold'))

example_1.png

Plotting heatmap with large range with ggplot2

As pointed out in the comments, it seems unlikely that your desired palette can be fully automated. However, it is not too hard to manually create a bespoke palette.

In the following, I've taken some base R colour names and interpolated these using the built in function colorRampPalette, wrapped in a helper f just for convenience.

In this way, you can create whatever palette you like:

library(ggplot2)

data <- c(1:5, 30:40, 58, 200:210, 400)

f <- function(n, col1, col2 = NULL) colorRampPalette(c(col1, col2))(n)

colours <- c(
f(5, "white", "cyan"),
f(11, "blue", "purple"),
f(1, "violet"),
f(11, "pink", "red"),
f(1, "black")
)

ggplot(NULL, aes(x = factor(data), y = 1, fill = factor(data))) +
geom_tile() +
scale_fill_manual(values = colours) +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) # Just to fit reprex

Sample Image

Created on 2020-05-22 by the reprex package (v0.3.0)

Obviously, you'll have to play around with the actual colour values to get something that looks good for your data. Note that you don't need to use the colour names defined by R. colorRampPalette (and hence f) also takes hex colours, for instance, which you can grab from ColorBrewer, if you particularly like some of those.

ggplot2 heatmap with fixed scale colorbar between graphs

You need to set the same range (limits of color bar) for all of them and also specify the colors.

rng = range(matrixA, matrixB, matrixC)

And add this to your ggplot code:

g + scale_fill_gradient2(low="green", mid="lightblue", high="red", #colors in the scale
midpoint=mean(rng), #same midpoint for plots (mean of the range)
breaks=seq(0,1,0.25), #breaks in the scale bar
limits=c(floor(rng[1]), ceiling(rng[2])))

Example:

Below is an example that helps you to get what you want:

x <- matrix(60:85, 5)/100
y <- matrix(65:95, 5)/100
z <- matrix(50:100, 5)/100


rng = range(c((x), (y), (z)))

library(reshape)
library(ggplot2)

ggplot(data = melt(x)) + geom_tile(aes(x=X1,y=X2,fill = value)) +
scale_fill_gradient2(low="green", mid="lightblue", high="red", #colors in the scale
midpoint=mean(rng), #same midpoint for plots (mean of the range)
breaks=seq(0,1,0.25), #breaks in the scale bar
limits=c(floor(rng[1]), ceiling(rng[2]))) + #same limits for plots
ggtitle("X")

ggplot(data = melt(y)) + geom_tile(aes(x=X1,y=X2,fill = value)) +
scale_fill_gradient2(low="green", mid="lightblue", high="red",
midpoint=mean(rng),
breaks=seq(0,1,0.25),
limits=c(floor(rng[1]), ceiling(rng[2]))) +
ggtitle("Y")

ggplot(data = melt(z)) + geom_tile(aes(x=X1,y=X2,fill = value)) +
scale_fill_gradient2(low="green", mid="lightblue", high="red",
midpoint=mean(rng),
breaks=seq(0,1,0.25),
limits=c(floor(rng[1]), ceiling(rng[2]))) +
ggtitle("Z")

This will give you:



Customize colors in ggplot heatmap using scale_colour_gradient

You need scale_fill_gradient.

ggplot(df, aes(sample1, sample2, fill = association)) +
geom_tile(color = "white") +
scale_fill_gradient(
name = "Cor", # changes legend title
low = "gray",
high = "red",
limit = c(min(df$association), 1),
space = "Lab",
guide = "colourbar"
) + theme_minimal() +
theme(
axis.title.x = element_blank(),
axis.title.y = element_blank(),
axis.text.x = element_text(
angle = 45,
vjust = 1,
size = 12,
hjust = 1
)
) +
coord_fixed() +
coord_flip()

Sample Image

R ggplot2 heatmap, force discrete scale with custom range, add grid to map

Here are some modifications

p_min_expd0 <- ggplot(melted_min_expd0, aes(looses, winning)) +
geom_tile(aes(fill = cut(times, breaks=0:5, labels=1:5)), colour = "grey") +
ggtitle("Min function, exp decay off") +
scale_y_discrete(limits=c("preferential", "heterophily", "homophily")) +
scale_fill_manual(drop=FALSE, values=colorRampPalette(c("white","red"))(5), na.value="#EEEEEE", name="Times") +
xlab("(x) looses against (y)") + ylab("(y) winning over (x)")

Since you want a discrete scale, you can take care of your first two "wishes" by doing the conversion yourself with cut(). This makes a discrete variable from a continuous one. Since we are using a deiscrete scale now, we must set the color ramp ourselves with the scale_fill_manual. The "grid" color is set with the colour= parameter in geom_tile. The NA color is set with scale_fill_maual(na.value=).

Sample Image

R heatmap: assign colors to values

If you want to have discrete intervals and scale, you should get the values of df$Z into integer factors and then use scale_fill_manual to get the desired colour scheme.

data$Z <- factor(round(data$Z))

# Heatmap
ggplot(data, aes(X, Y, fill= Z)) +
geom_tile(color = "white",
lwd = 0.5,
linetype = 1)+
scale_fill_manual(values = c('red', 'green', 'yellow', 'blue'))

#or simply

ggplot(data, aes(X, Y, fill= factor(round(data$Z)))) +
geom_tile(color = "white",
lwd = 0.5,
linetype = 1)+
scale_fill_manual(values = c('red', 'green', 'yellow', 'blue'), name = 'Z')

Sample Image

To transform the Z values into strings you can use:

library(plyr)

data$Z <- factor(round(data$Z))

ata$Z <- revalue(data$Z, c('-1'='negative'))
data$Z <- revalue(data$Z, c('0' = 'no'))
data$Z <- revalue(data$Z, c('1' = 'yes'))
data$Z <- revalue(data$Z, c('2' = 'other'))

# Heatmap
ggplot(data, aes(X, Y, fill= Z)) +
geom_tile(color = "white",
lwd = 0.5,
linetype = 1)+
scale_fill_manual(values = c('red', 'green', 'yellow', 'blue'), name = 'Z')

Sample Image

R: Heatmap with colour based on groups, NA values in grey and characters included

Your first issue can be solved by converting Values to a numeric, i.e. mapping as.numeric(Values) on alpha.

Concerning the second issue. As you map X on fill the tiles are colored according to X. If you want to fill NAs differently as well as tiles where X==Y then you have to define your fill colors accordingly. To this end my approach adds a column fill to the df and makes use of scale_fill_identity.

Note that I moved the alpha and fill into geom_tile so that these are not passed on to geom_text...

... and following the suggestion by @AllanCameron I reversed the order of `Y' so that the plot is in line with your desired output.

library(ggplot2)
library(dplyr)

X <- rep(c('Apple', "Banana", "Pear"), each=3)
Y <- rep(c('Apple', "Banana", "Pear"), times=3)
Y <- factor(Y, levels = c("Pear", "Banana", "Apple"))

Values<- c('Apple', 2,3,NA, "Banana", 3,1,2,"Pear")

Data <- data.frame(X,Y,Values)
Data <- Data %>%
mutate(fill = case_when(
is.na(Values) ~ "grey",
X == Y ~ "white",
X == "Apple" ~ "red",
X == "Banana" ~ "yellow",
X == "Pear" ~ "green"
))

ggplot(Data, mapping = aes(x=X, y=Y)) +
geom_tile(aes(fill=fill, alpha=as.numeric(Values)), colour="white") +
ylab("Y") +
xlab("X")+
scale_fill_identity("Assay") +
scale_alpha("Value")+
ggtitle("Results Summary")+
theme(strip.text.y.left = element_text(angle = 0))+
geom_text(aes(label=if_else(!is.na(Values), Values, "NA")))
#> Warning in FUN(X[[i]], ...): NAs introduced by coercion

Sample Image



Related Topics



Leave a reply



Submit