【问题标题】:ggplot2: Fix colors to factor levelsggplot2:将颜色固定到因子水平
【发布时间】:2017-09-12 09:32:35
【问题描述】:

我正在做一个更大的项目,为此我在 ggplot2 中创建了几个图。这些图涉及在几个不同的谨慎类别(想想:国家、物种、类型)中绘制几个不同的结果。我想完全修复离散类型到颜色的映射,以便 Type=A 始终显示为红色,Type=B 始终显示为蓝色,等等,无论存在哪些其他因素。我知道scale_fill_manual(),我可以在其中手动提供颜色值,然后使用drop = FALSE,这有助于处理未使用的因子水平。但是,我发现这非常麻烦,因为每个绘图都需要一些手动工作来处理以正确的方式对因子进行排序、对颜色值进行排序以匹配因子排序、删除未使用的级别等。

我正在寻找一种方法,我可以将一次全局因子级别映射到特定颜色(A=绿色、B=蓝色、C=红色、...),然后只需去绘制我喜欢的任何东西,然后 ggplot 选择正确的颜色。

这里有一些代码来说明这一点。

# Full set with 4 categories
df1 <- data.frame(Value = c(40, 20, 10, 60), 
                  Type = c("A", "B", "C", "D"))

ggplot(df1, aes(x = Type, y = Value, fill = Type)) + geom_bar(stat = "identity")


# Colors change complete because only 3 factor levels are present
df2 <- data.frame(Value = c(40, 20, 60), 
                  Type = c("A", "B", "D"))

ggplot(df2, aes(x = Type, y = Value, fill = Type)) + geom_bar(stat = "identity")


# Colors change because factor is sorted differently
df3 <- data.frame(Value = c(40, 20, 10, 60), 
                  Type = c("A", "B", "C", "D"))
df3$Type <- factor(df3$Type, levels = c("D", "C", "B", "A"), ordered = TRUE)

ggplot(df3, aes(x = Type, y = Value, fill = Type)) + geom_bar(stat = "identity")

【问题讨论】:

    标签: r ggplot2 colors


    【解决方案1】:

    确保先将该列转换为Factor,然后创建一个变量来存储每个因子的颜色值...

    df$color <- as.factor(df$color, levels = c(1, 0))
    cbPallete <- c("1"= "green", "0"="red")
    
    ggplot(data = df) + geom_bar(x = df$x, 
                                 y = df$y,
                                 fill = df$color) +
    scale_fill_manual(values = cbPallete)
    

    【讨论】:

      【解决方案2】:

      另一种选择是通过如下定义默认色标使drop = F 成为默认值:

      scale_colour_discrete <- function(...)
        scale_colour_manual(..., drop = F)
      scale_fill_discrete <- function(...)
        scale_fill_manual(..., drop = F)
      

      这样颜色对于不同的因素总是一致的。

      【讨论】:

        【解决方案3】:

        如果您愿意,您可以定义自己的自定义比例。如果您查看scale_fill_manual 的来源,

        scale_fill_manual
        #> function (..., values) 
        #> {
        #>     manual_scale("fill", values, ...)
        #> }
        #> <environment: namespace:ggplot2>
        

        其实很简单:

        library(ggplot2)
        
        scale_fill_chris <- function(...){
            ggplot2:::manual_scale(
                'fill', 
                values = setNames(c('green', 'blue', 'red', 'orange'), LETTERS[1:4]), 
                ...
            )
        }
        
        df1 <- data.frame(Value = c(40, 20, 10, 60), 
                          Type = c("A", "B", "C", "D"))
        
        ggplot(df1, aes(x = Type, y = Value, fill = Type)) + 
            geom_col() + 
            scale_fill_chris()
        

        df2 <- data.frame(Value = c(40, 20, 60), 
                          Type = c("A", "B", "D"))
        
        ggplot(df2, aes(x = Type, y = Value, fill = Type)) + 
            geom_col() + 
            scale_fill_chris()
        

        df3 <- data.frame(Value = c(40, 20, 10, 60), 
                          Type = c("A", "B", "C", "D"))
        df3$Type <- factor(df3$Type, levels = c("D", "C", "B", "A"), ordered = TRUE)
        
        ggplot(df3, aes(x = Type, y = Value, fill = Type)) + 
            geom_col() + 
            scale_fill_chris()
        

        【讨论】:

          【解决方案4】:

          您可以制作自定义绘图功能(包括scale_fill_manual 和合理的默认颜色)以避免重复代码:

          library(ggplot2)
          custom_plot <- function(.data,
            colours = c("A" = "green", "B" = "blue", "C" = "red", "D" = "grey"))  {
            ggplot(.data, aes(x=Type, y=Value, fill= Type)) + geom_bar(stat="identity") +
             scale_fill_manual(values = colours)
          }
          
          df1 <- data.frame(Value=c(40, 20, 10, 60), Type=c("A", "B", "C", "D"))
          df2 <- data.frame(Value=c(40, 20, 60), Type=c("A", "B", "D"))
          df3 <- data.frame(Value=c(40, 20, 10, 60), Type=c("A", "B", "C", "D"))
          df3$Type <- factor(df3$Type, levels=c("D", "C", "B", "A"), ordered=TRUE)
          
          custom_plot(df1)
          custom_plot(df2)
          custom_plot(df3)
          

          【讨论】:

          • 啊!所以 scale_fill_manual() 可以 处理命名向量!这正是我一直在寻找的。谢谢克里斯托弗。
          猜你喜欢
          • 2020-07-11
          • 2012-07-02
          • 2019-08-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-12-07
          • 1970-01-01
          相关资源
          最近更新 更多