I have a model including a three-way interaction term (XYZ). I have used this model to create predictions across the parameter space. Thus, I have four pieces of information to convey: X, Y, Z, and Probability. If I had a simple interaction, I would plot a heatmap with X~Y and color would be Probability, but now I need that as a 3D plot.
example_results <- expand.grid(x = 1:8,
y = seq(from = -1.85, to = 3.58, length.out = 15),
z = seq(from = 0, to = 2.41, length.out = 15)) %>%
mutate(probability = sample(seq(from = 0, to = 1, length.out = 3000), 1800))
plot_ly
seems to understand its own relationships within data, whereas I want just to plot my results. rayshader
seemed perfect, but is apparently unable to decouple height (z) from fill (probability). rasterVis
objects to cuts.
I will greatly appreciate any advice on how to plot all the information in one image in R.
Thanks!
You can do this using rayshader
and ggplot2
. One problem is that the example data you have posted uses expand.grid()
. Each value of x
and y
has every value of z
, so you won't see a difference in heights with this data. I'll just select random rows for each value of x
and y
for demonstration purposes:
library(dplyr)
dat <- example_results |>
group_by(x, y) |>
filter(row_number() == sample(row_number(), 1))
Once you've done this you can use ggplot2
to create two separate 2d heatmaps, one for the height and one for the fill. Make sure to set color
in both to the height value (z
in this case):
library(ggplot2)
heatmap_fill <- ggplot(dat) +
geom_tile(aes(x, y, fill = probability, color = z)) +
theme_void() +
theme(legend.position = "none")
heatmap_height <- ggplot(dat) +
geom_tile(aes(x, y, fill = z, color = z)) +
theme_void() +
theme(legend.position = "none")
Then you can just use rayshader
to render these, providing the fill heatmap as the ggobj
and the height heatmap as ggobj_height
. I've turned off shadows in this case so it renders quickly:
library(rayshader)
plot_gg(
ggobj = heatmap_fill,
ggobj_height = heatmap_height,
multicore = TRUE, width = 5, height = 5,
shadow = FALSE,
raytrace = FALSE,
scale = 500, windowsize = c(1280, 720), zoom = 0.85,
phi = 90, theta = 0
)
Output:
The quality is much better than this - I had to make it very small and reduce the colours to 64 get it under the 2mb image upload limit. See here for the higher quality version.