How can I add on the graph legend an NA or "0" label if I used trans="log"
in the scale_fill_viridis
or another continuous scale
> d1
persona num.de.puntos puntos
1 p1 1 3
2 p1 2 4
3 p1 3 0
4 p1 4 4
5 p1 5 2
6 p2 1 2
7 p2 2 3
8 p2 3 0
9 p2 4 0
10 p2 5 4
11 p3 1 0
12 p3 2 1
13 p3 3 0
14 p3 4 5
15 p3 5 8
p <- ggplot(d1, aes(persona, num.de.puntos, fill = puntos)) +
scale_fill_viridis(trans="log", option ="D", direction=1, na.value = "gray50",
breaks=c(0,1,5,8),
name="Number of people",
guide=guide_legend(label.position = "bottom",
title.position = 'top',
nrow=1,
label.theme = element_text(size = 6,
face = "bold",
color = "black"),
title.theme = element_text(size = 6,
face = "bold",
color = "black"))) +
geom_tile(colour="grey", show.legend = TRUE)
p
I want
The logarithm of zero is not defined -- its mathematically impossible to plot zero on a log scale. Instead of entering zero, you can enter a low value (say -10 on the log scale), and then use custom ticks to label the graph correctly (so it is labeled "0" rather than "-10".
%>% is a pipe operator reexported from the magrittr package. Start by reading the vignette. Adding things to a ggplot changes the object that gets created. The print method of ggplot draws an appropriate plot depending upon the contents of the variable.
You can place the legend literally anywhere. To put it around the chart, use the legend. position option and specify top , right , bottom , or left . To put it inside the plot area, specify a vector of length 2, both values going between 0 and 1 and giving the x and y coordinates.
To change the Size of Legend, we have to add guides() and guide_legend() functions to the geom_point() function.
Note: Code below is run in R 3.5.1 and ggplot2 3.1.0. You might be using an older version of the ggplot2 package, since your code uses scale_fill_viridis
instead of scale_fill_viridis_c
.
TL;DR solution:
I'm pretty sure this is not orthodox, but assuming your plot is named p
, setting:
p$scales$scales[[1]]$is_discrete <- function() TRUE
will get the NA value in your legend without changing any of the existing fill aesthetic mappings.
Demonstration:
p <- ggplot(d1, aes(persona, num.de.puntos, fill = puntos)) +
scale_fill_viridis_c(trans="log", option ="D", direction=1,
na.value = "gray50", # optional, change NA colour here
breaks = c(0, 1, 5, 8),
labels = c("NA label", "1", "5", "8"), # optional, change NA label here
name="Number of people",
guide=guide_legend(label.position = "bottom",
title.position = 'top',
nrow=1,
label.theme = element_text(size = 6,
face = "bold",
color = "black"),
title.theme = element_text(size = 6,
face = "bold",
color = "black"))) +
geom_tile(colour = "grey", show.legend = TRUE)
p # no NA mapping
p$scales$scales[[1]]$is_discrete <- function() TRUE
p # has NA mapping
Explanation:
I dug deep into the plotting mechanics by converting p
into a grob object (via ggplotGrob
), & running debug()
on functions that affect the legend generation part of the plotting process.
After debugging through ggplot2:::ggplot_gtable.ggplot_built
, ggplot2:::build_guides
, and ggplot2:::guides_train
, I got to ggplot2:::guide_train.legend
, an un-exported function from the ggplot2
package:
> ggplot2:::guide_train.legend
function (guide, scale, aesthetic = NULL)
{
breaks <- scale$get_breaks()
if (length(breaks) == 0 || all(is.na(breaks))) {
return()
}
key <- as.data.frame(setNames(list(scale$map(breaks)), aesthetic %||%
scale$aesthetics[1]), stringsAsFactors = FALSE)
key$.label <- scale$get_labels(breaks)
if (!scale$is_discrete()) {
limits <- scale$get_limits()
noob <- !is.na(breaks) & limits[1] <= breaks & breaks <=
limits[2]
key <- key[noob, , drop = FALSE]
}
if (guide$reverse)
key <- key[nrow(key):1, ]
guide$key <- key
guide$hash <- with(guide, digest::digest(list(title, key$.label,
direction, name)))
guide
}
I saw that up until the key$.label <- scale$get_labels(breaks)
step, key
looks like this:
> key
fill .label
1 gray50 NA label
2 #440154 1
3 #72CC59 5
4 #FDE725 8
But scale$is_discrete()
is FALSE
, so !scale$is_discrete()
is TRUE
, and the row in key
corresponding to the NA value gets dropped in the next step, since there is an NA value in the fill scale's breaks after log transformation:
> scale$get_breaks()
[1] NA 0.000000 1.609438 2.079442
Thus, if we can have scale$is_discrete()
evaluate to TRUE
instead of FALSE
, this step would be skipped, and we end up with the full legend including the NA value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With