What I'm trying to do is to have a variable binwidth in a ggplot2 contour plot, that is the distance between the different "equi-level lines".
Here is a minimal working example from the documentation, with a constant binwidth:
# Generate data
library(reshape2) # for melt
volcano3d <- melt(volcano)
names(volcano3d) <- c("x", "y", "z")
# Basic plot
v <- ggplot(volcano3d, aes(x, y, z = z))
v + stat_contour(aes(colour=..level..), binwidth = 2)
Use the breaks argument, for example:
v <- ggplot(volcano3d, aes(x, y, z = z))
v + stat_contour(aes(colour= ..level..), breaks = c(100, 101, 102, 105, 110, 150, 175))
Related
I found this figure: Heatmap with variable box sizes in this article: https://journals.sagepub.com/doi/10.1177/2378023118805646
Does anyone know how to make a heatmap where the size of the boxes varies?
This
# Library
library(ggplot2)
# Dummy data
x <- LETTERS[1:20]
y <- paste0("var", seq(1,20))
data <- expand.grid(X=x, Y=y)
data$Z <- runif(400, 0, 5)
# Heatmap
ggplot(data, aes(X, Y, fill= Z)) +
geom_tile()
gives me a heatmap, but no clue how to fix the axes scales so that they follow a different variable.
Thanks
Hasan
A heatmap with varying box sizes can be achieved via geom_rect. Depending on your data this requires more or less manual work to set up or compute the boundaries of the boxes, i.e. the values used for the xmin, xmax, ymin and ymax aesthetics. Try this:
# Library
library(ggplot2)
set.seed(42)
# Dummy data
x <- LETTERS[1:5]
y <- paste0("var", seq(1,5))
# Lower and upper bounds of rectangles
xx <- setNames(cumsum(runif(5)), x)
xx1 <- setNames(c(0, xx[1:4]), x)
yy <- setNames(cumsum(runif(5)), y)
yy1 <- setNames(c(0, yy[1:4]), y)
data <- expand.grid(X=x, Y=y)
data$Z <- runif(25, 0, 5)
data$xmax <- xx[data$X]
data$ymax <- yy[data$Y]
data$xmin <- xx1[data$X]
data$ymin <- yy1[data$Y]
# Heatmap
ggplot(data, aes(fill= Z)) +
geom_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax), color = "white") +
scale_x_continuous(breaks = (xx1 + xx) / 2, labels = x) +
scale_y_continuous(breaks = (yy1 + yy) / 2, labels = y) +
scale_fill_viridis_b()
Created on 2020-05-16 by the reprex package (v0.3.0)
I wonder how to get data labels on lines in ggplot2 for contours. Thanks
require(grDevices) # for colours
x <- seq(-4*pi, 4*pi, len = 27)
y <- seq(-4*pi, 4*pi, len = 27)
r <- sqrt(outer(x^2, y^2, "+"))
rx <- range(x <- 10*1:nrow(volcano))
ry <- range(y <- 10*1:ncol(volcano))
ry <- ry + c(-1, 1) * (diff(rx) - diff(ry))/2
plot(
x = 0
, y = 0
, type = "n"
, xlim = rx
, ylim = ry
, xlab = ""
, ylab = ""
)
contour(
x = x
, y = y
, z = volcano
, add = TRUE
)
library(ggplot2)
library(reshape2)
volcano3d <- melt(volcano)
names(volcano3d) <- c("x", "y", "z")
# Basic plot
v <- ggplot(volcano3d, aes(x, y, z = z))
v + stat_contour()
using directlabels package and picking solution from this
# Basic plot
v <- ggplot(volcano3d, aes(x, y, z = z))
library(directlabels)
v2 <- v + stat_contour(aes(colour = ..level..))
direct.label(v2, method="bottom.pieces")
This is an old question already answered, but I do a lot of contour plots and I think that there is an easier and more versatile way to do this using the package metR (https://rdrr.io/github/eliocamp/metR/f/vignettes/Visualization-tools.Rmd). This package has the function geom_label_contour() that provides an easy way to plot labels of contours. Also provides a lot of functions to plot maps.
library(ggplot2)
library(reshape2)
library(metR)
volcano3d <- melt(volcano)
colnames(volcano3d) <- c('x','y','z')
ggplot(data = volcano3d, aes(x=x,y=y,z=z)) + geom_contour() +
geom_label_contour()
Suppose I want to plot the following data:
# First set of X coordinates
x <- seq(0, 10, by = 0.2)
# Angles from 0 to 90 degrees
angles <- seq(0, 90, length.out = 10)
# Convert to radian
angles <- deg2rad(angles)
# Create an empty data frame
my.df <- data.frame()
# For each angle, populate the data frame
for (theta in angles) {
y <- sin(x + theta)
tmp <- data.frame(x = x, y = y, theta = as.factor(theta))
my.df <- rbind(my.df, tmp)
}
x1 <- seq(0, 12, by = 0.3)
y1 <- sin(x1 - 0.5)
tmp <- data.frame(x = x1, y = y1, theta = as.factor(-0.5))
my.df <- rbind(my.df, tmp)
ggplot(my.df, aes(x, y, color = theta)) + geom_line()
That gives me a nice plot:
Now I want to draw a heat map out of this data set. There are tutorials here and there that do it using geom_tile to do it.
So, let's try:
# Convert the angle values from factors to numerics
my.df$theta <- as.numeric(levels(my.df$theta))[my.df$theta]
ggplot(my.df, aes(theta, x)) + geom_tile(aes(fill = y)) + scale_fill_gradient(low = "blue", high = "red")
That does not work, and the reason is that my x coordinates do not have the same step:
x <- seq(0, 10, by = 0.2) vs x1 <- seq(0, 12, by = 0.3)
But as soon as I use the same step x1 <- seq(0, 12, by = 0.2), it works:
I real life, my data sets are not regularly spaced (these are experimental data), but I still need to display them as a heat map. How can I do?
You can use akima to interpolate the function into a form suitable for heat map plots.
library(akima)
library(ggplot2)
my.df.interp <- interp(x = my.df$theta, y = my.df$x, z = my.df$y, nx = 30, ny = 30)
my.df.interp.xyz <- as.data.frame(interp2xyz(my.df.interp))
names(my.df.interp.xyz) <- c("theta", "x", "y")
ggplot(my.df.interp.xyz, aes(x = theta, y = x, fill = y)) + geom_tile() +
scale_fill_gradient(low = "blue", high = "red")
If you wish to use a different resolution you can change the nx and ny arguments to interp.
Another way to do it with just ggplot2 is to use stat_summary_2d.
library(ggplot2)
ggplot(my.df, aes(x = theta, y = x, z = y)) + stat_summary_2d(binwidth = 0.3) +
scale_fill_gradient(low = "blue", high = "red")
I am trying to plot some extra points onto an existing contour plot with ggplot2:
require(ggplot2)
library(reshape2) # for melt
volcano3d <- melt(volcano)
names(volcano3d) <- c("x", "y", "z")
v <- ggplot(volcano3d, aes(x, y, z = z))
v <- v + stat_contour()
print(v)
newdata <- data.frame(x = runif(7)*60, y = runif(7)*60)
v <- v + geom_point(data=newdata, aes(x, y))
print(v)
The first print is ok, but the second is just blank. Why?
Here is a code snippet from the docs site:
# Generate data
library(reshape2) # for melt
volcano3d <- melt(volcano)
names(volcano3d) <- c("x", "y", "z")
# Basic plot
v <- ggplot(volcano3d, aes(x, y, z = z))
v + stat_contour(binwidth = 10)
Output:
What if I want to draw contour lines at custom levels? For example, in the volcano3d data set, I want these levels to be indicate: z == 120, 140, 160.
Replace binwidth= with argument breaks= and provide breakpoint you need.
ggplot(volcano3d, aes(x, y, z = z)) +
stat_contour(breaks=c(120,140,160))