Separate legend for `z`
Thank you for the nice extension. I would like to map fill to a different variable, how can I show legends for both fill and z?
I tried something like:
ggplot(df3d, aes(x, -y, z = z, fill = density)) +
geom_oblicuboids(angle=45, show.legend = TRUE) +
coord_fixed() +
scale_fill_nord(palette="lumina",name = "Density", discrete=F) +
labs(
title = "3D Oblique Plot: Height = Mahalanobis distance, Color = Density",
x = "Grid X index",
y = "Grid Y index"
) +
theme(
panel.grid = element_blank(),
panel.background = element_blank()
)
It throws a warning:
Warning message:
`show.legend` must be a logical vector.
Could you please elaborate on how to set a logical vector in such case?
Well, perhaps it is very difficult to show a legend for z after all. Please feel free to close this issue if it is not useful.
- Do you know of any examples of a custom geom creating a legend for an aesthetic not in base
{ggplot2}? - Probably not impossible to do but I'm not sure exactly how using the
{ggplot2}"guide" system built-in to{ggplot2}or in extension packages like{legendry} - #14 is an open issue for a separate
zaxis which also seems like it would be very difficult to implement
- You can use
guide_custom()to add arbitrary newzlegend elements but you'd need to manually construct your own "grob" for the legend - Currently this package does not provide a separate "scale" for the
zaesthetic so I don't think you can use normal "guides" with it - The
zaesthetic forgeom_oblicubes()currently needs to be integer valued and often (usually?) will not correspond to the "raw" values you actually care about (e.g. elevation) which is why in the examples we usefill = rawinstead offill = z
I am not quite familiar with custom geom. At least in my case, mapping fill to a different variable is helpful to interpret my data.
I experimented a bit:
library(grid)
breaks <- c(1, 2, 3, 4)
legend_df <- data.frame(
x = 1,
y = 2 * seq_along(breaks) - 5,
z = breaks,
fill = nord:::nord_pal("lumina")(length(breaks))
)
cube_grobs <- lapply(split(legend_df, seq_along(breaks)), function(d) {
oblicubesGrob(
x = d$x,
y = d$y,
z = d$z,
width = unit(0.8, "lines"),
xo = unit(0, "lines"),
yo = unit(0, "lines"),
angle = 45,
scale = 0.5,
gp = gpar(fill = d$fill, col = "black")
)
})
legend_grob <- grid::gTree(children = do.call(gList, cube_grobs), cl = "cube_legend")
p + guides(
height = guide_custom(
grob = legend_grob,
title = "Height\n(M-dist)",
width = unit(1, "cm"),
height = unit(2, "cm")
)
) +
theme(legend.position = "right")
This is what I got:
Not sure how to get the heights right, they look truncated.
What about creating stacks of cubes? Something like:
legend_grob <- oblicubesGrob(
x = 1,
y = rep.int(seq.int(1, by = 2, length.out = 4L), 1:4),
z = sequence(1:4, 1),
gp = gpar(fill = rep.int(palette.colors(4L), 1:4), col = "black"),
width = unit(0.8, "lines"),
x0 = unit(0, "lines"),
y0 = unit(0, "lines"),
angle = 45,
scale = 0.5
)
That's indeed a good idea, stacks clearly indicate differences in magnitudes.
With your suggestion, I tried also the oblicuboids geom:
cube_legend <- oblicuboidsGrob(
x = 1,
y = rep.int(seq.int(1, by = 2, length.out = 4L), 1:4),
z = sequence(1:4, 1) / 4,
gp = gpar(fill = "gray", col = "black"),
width = unit(0.8, "lines"),
xo = unit(0, "lines"),
yo = unit(0, "lines"),
angle = 45,
scale = 0.5
)
stack_ys <- seq.int(1, by = 2, length.out = 4L)
labels <- as.character(seq.int(1, by = 1, length.out = 4L) / 4)
text_grobs <- mapply(function(lab, ypos) {
textGrob(
label = lab,
x = unit(3, "lines"),
y = unit(ypos, "lines"),
just = "left",
gp = gpar(fontsize = 10)
)
}, lab = labels, ypos = stack_ys, SIMPLIFY = FALSE)
cube_stacks <- grobTree(
cube_legend,
do.call(gList, text_grobs)
)
p + guides(
height = guide_custom(
grob = cube_stacks,
title = "Height\n(M-dist)",
width = unit(2, "cm"),
height = unit(4, "cm")
)
) +
theme_minimal(base_size = 12) +
theme(legend.position = "right")
Yields:
Still a bit difficult for eyeballing. But I guess that's the problem of '3D'.
Will try to wrap it up to something like cube_z_legend() so we can call it by p + cube_z_legend()