首页 > 解决方案 > 日志转换后如何在 ggplot 的图例中保留 0 值?

问题描述

如果我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

在此处输入图像描述

我想

在此处输入图像描述

标签: rggplot2

解决方案


注意:下面的代码在 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

没有 NA 映射

带有 NA 映射

说明

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

通过ggplot2:::ggplot_gtable.ggplot_builtggplot2:::build_guides和调试后ggplot2:::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()is FALSE,所以!scale$is_discrete()is TRUE,并且对应于 NA 值的行在key下一步中被删除,因为在对数转换后填充比例的中断中有一个 NA 值:

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

因此,如果我们可以用scale$is_discrete()评估来TRUE代替FALSE,这一步将被跳过,我们最终得到包括 NA 值的完整图例。


推荐阅读