日志转换后,如何在ggplot的图例中保留0值?

时间:2019-03-04 16:27:11

标签: r ggplot2

如果我在trans="log"中使用scale_fill_viridis或其他连续比例,如何在图例上添加NA或“ 0”标签

> 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

enter image description here

我想要

enter image description here

1 个答案:

答案 0 :(得分:1)

注意:以下代码在R 3.5.1和ggplot2 3.1.0中运行。您可能使用的是ggplot2软件包的旧版本,因为您的代码使用scale_fill_viridis而不是scale_fill_viridis_c

TL; DR解决方案

我非常确定这不是正统的,但是假设您的图名为p,设置为:

p$scales$scales[[1]]$is_discrete <- function() TRUE

将获得图例中的NA值,而无需更改任何现有的填充美学映射。

演示:

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

without NA mapping

with NA mapping

说明

我通过将p转换为grob对象(通过ggplotGrob)并在影响绘图过程中图例生成部分的函数上运行debug()来深入研究绘图机制。

在通过ggplot2:::ggplot_gtable.ggplot_builtggplot2:::build_guidesggplot2:::guides_train进行调试之后,我进入了ggplot2:::guide_train.legend,这是ggplot2包中未导出的函数:

> 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
}

key$.label <- scale$get_labels(breaks)步骤之前,我一直看到key看起来像这样:

> key
     fill   .label
1  gray50 NA label
2 #440154        1
3 #72CC59        5
4 #FDE725        8

但是scale$is_discrete()FALSE,所以!scale$is_discrete()TRUE,并且在下一步中,key中与NA值对应的行将被删除,因为对数转换后填充刻度的中断中有一个NA值:

> scale$get_breaks()
[1]       NA 0.000000 1.609438 2.079442

因此,如果我们可以让scale$is_discrete()的评估结果为TRUE而不是FALSE,则将跳过此步骤,最后得到包括NA值的完整图例