如何为ggplot2中具有稳定映射的分类变量分配颜色?

Posted

技术标签:

【中文标题】如何为ggplot2中具有稳定映射的分类变量分配颜色?【英文标题】:How to assign colors to categorical variables in ggplot2 that have stable mapping? 【发布时间】:2011-10-18 15:23:55 【问题描述】:

上个月我一直在学习 R。

这是我的问题:

在 ggplot2 中为具有稳定映射的分类变量分配颜色的好方法是什么?我需要在一组具有不同子集和不同数量的分类变量的图表中使用一致的颜色。

例如,

plot1 <- ggplot(data, aes(xData, yData,color=categoricaldData)) + geom_line()

categoricalData 有 5 个级别。

然后

plot2 <- ggplot(data.subset, aes(xData.subset, yData.subset, 
                                 color=categoricaldData.subset)) + geom_line()

categoricalData.subset 有 3 个级别。

但是,两个集合中的特定级别最终会以不同的颜色结束,这使得一起阅读图表变得更加困难。

我需要在数据框中创建颜色矢量吗?还是有其他方法可以将特定颜色分配给类别?

【问题讨论】:

【参考方案1】:

对于像 OP 中的确切示例这样的简单情况,我同意蒂埃里的答案是最好的。但是,我认为指出另一种方法会很有用,当您尝试在多个数据帧之间保持一致的配色方案时,这些方法并非都是通过子集单个大数据帧获得的。如果从单独的文件中提取多个数据框中的因子水平并且并非所有因子水平都出现在每个文件中,那么管理多个数据框中的因子水平可能会变得乏味。

解决此问题的一种方法是创建自定义手动色标,如下所示:

#Some test data
dat <- data.frame(x=runif(10),y=runif(10),
        grp = rep(LETTERS[1:5],each = 2),stringsAsFactors = TRUE)

#Create a custom color scale
library(RColorBrewer)
myColors <- brewer.pal(5,"Set1")
names(myColors) <- levels(dat$grp)
colScale <- scale_colour_manual(name = "grp",values = myColors)

然后根据需要在绘图上添加色标:

#One plot with all the data
p <- ggplot(dat,aes(x,y,colour = grp)) + geom_point()
p1 <- p + colScale

#A second plot with only four of the levels
p2 <- p %+% droplevels(subset(dat[4:10,])) + colScale

第一个情节是这样的:

第二个情节是这样的:

这样您就不需要记住或检查每个数据框以查看它们是否具有适当的级别。

【讨论】:

这可行,但可能过于复杂。我认为您不需要为此创建手动比例。您只需要一个factor,它在所有地块之间都是通用的。 @Andrie - 对于单个子集,是的。但是,如果您要处理大量并非都是通过对一个原始数据框进行子集化创建的数据集,我发现这种策略要简单得多。 @joran 谢谢乔兰。这对我有用!它创建了一个具有正确数量的因子的图例。我喜欢这种方法,并且获得跨不同数据集的颜色映射非常值得这三行。 我需要:库(“RColorBrewer”) 完美运行!我在fillScale &lt;- scale_fill_manual(name = "grp",values = myColors) 中添加了将其与条形图一起使用。【参考方案2】:

最简单的解决方案是将分类变量转换为子集之前的因子。底线是您需要一个在所有子集中具有完全相同水平的因子变量。

library(ggplot2)
dataset <- data.frame(category = rep(LETTERS[1:5], 100), 
    x = rnorm(500, mean = rep(1:5, 100)), y = rnorm(500, mean = rep(1:5, 100)))
dataset$fCategory <- factor(dataset$category)
subdata <- subset(dataset, category %in% c("A", "D", "E"))

带有字符变量

ggplot(dataset, aes(x = x, y = y, colour = category)) + geom_point()
ggplot(subdata, aes(x = x, y = y, colour = category)) + geom_point()

带有因子变量

ggplot(dataset, aes(x = x, y = y, colour = fCategory)) + geom_point()
ggplot(subdata, aes(x = x, y = y, colour = fCategory)) + geom_point()

【讨论】:

最简单的方法是使用限制 可以在这方面提供一个例子哈德利?我不确定如何将限制与因子一起使用。 @Thierry 谢谢。我很高兴在我的第一篇文章中得到回复。并感谢蒂埃里或添加可重现的代码,因为我应该在我的帖子中......我的分类变量是正确的类型 - 因素。另一个问题是我希望图例不显示未使用的因素。 R 在构建图例时会忽略未使用的字符变量。然而,未使用的因素仍然存在。如果我使用以下方法删除它们: subdata$category @Thierry - 在我手中,使用 ggplot2_0.9.3.1,这种方法(不再?)不起作用;分配给 fCategory 的颜色在两个图之间是不同的。但是,很高兴@wintour,我认为@hadley 建议 + scale_colour_discrete(drop=TRUE,limits = levels(dataset$fCategory)) 保留颜色|因素关联,但是,除了在我手中,drop=TRUE NOT 是有效的尊重(我希望它能够从传说中删除级别)。 Drat ...还是我? @malcook,而不是 drop = TRUE,您需要通过“breaks”指定要保留的级别:github.com/hadley/ggplot2/issues/1433【参考方案3】:

我处于malcook 在his comment 中指出的相同情况:不幸的是Thierry 的answer 不适用于ggplot2 版本0.9.3.1。

png("figure_%d.png")
set.seed(2014)
library(ggplot2)
dataset <- data.frame(category = rep(LETTERS[1:5], 100),
    x = rnorm(500, mean = rep(1:5, 100)),
    y = rnorm(500, mean = rep(1:5, 100)))
dataset$fCategory <- factor(dataset$category)
subdata <- subset(dataset, category %in% c("A", "D", "E"))

ggplot(dataset, aes(x = x, y = y, colour = fCategory)) + geom_point()
ggplot(subdata, aes(x = x, y = y, colour = fCategory)) + geom_point()

这是第一个数字:

还有第二个图:

我们可以看到颜色不会保持固定,例如 E 从洋红色切换到蓝色。

正如malcook in his comment 和hadley in his comment 所建议的那样,使用limits 的代码可以正常工作:

ggplot(subdata, aes(x = x, y = y, colour = fCategory)) +       
    geom_point() + 
    scale_colour_discrete(drop=TRUE,
        limits = levels(dataset$fCategory))

给出下图,正确:

这是sessionInfo()的输出:

R version 3.0.2 (2013-09-25)
Platform: x86_64-pc-linux-gnu (64-bit)

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] methods   stats     graphics  grDevices utils     datasets  base     

other attached packages:
[1] ggplot2_0.9.3.1

loaded via a namespace (and not attached):
 [1] colorspace_1.2-4   dichromat_2.0-0    digest_0.6.4       grid_3.0.2        
 [5] gtable_0.1.2       labeling_0.2       MASS_7.3-29        munsell_0.4.2     
 [9] plyr_1.8           proto_0.3-10       RColorBrewer_1.0-5 reshape2_1.2.2    
[13] scales_0.2.3       stringr_0.6.2 

【讨论】:

你应该把它作为一个新问题发布,引用这个问题并说明为什么这里的解决方案不起作用。 here 提出了类似的问题,但我想指出接受的答案很好。 所以我知道这是旧的,但我想知道是否有办法做到这一点而无需在图例中使用额外的颜色。 要从图例中删除未使用的级别,现在应该添加 limit=force。 github.com/tidyverse/ggplot2/issues/4556【参考方案4】:

根据 joran 的非常有帮助的回答,我能够想出这个解决方案,为布尔因子(TRUEFALSE)提供稳定的色阶。

boolColors <- as.character(c("TRUE"="#5aae61", "FALSE"="#7b3294"))
boolScale <- scale_colour_manual(name="myboolean", values=boolColors)

ggplot(myDataFrame, aes(date, duration)) + 
  geom_point(aes(colour = myboolean)) +
  boolScale

由于 ColorBrewer 对二进制色标的帮助不是很大,因此需要手动定义两种所需的颜色。

这里mybooleanmyDataFrame 中包含TRUE/FALSE 因子的列的名称。在本例中,dateduration 是要映射到绘图的 x 和 y 轴的列名。

【讨论】:

另一种方法是将“as.character()”应用于列。这将使它成为一个与 scale_*_manual 一起工作的字符串列【参考方案5】:

这是一篇旧帖子,但我一直在寻找同样问题的答案,

为什么不试试这样的:

scale_color_manual(values = c("foo" = "#999999", "bar" = "#E69F00"))

如果您有分类值,我看不出这不起作用的原因。

【讨论】:

这实际上是 Joran 的回答所做的,但使用 myColors &lt;- brewer.pal(5,"Set1"); names(myColors) &lt;- levels(dat$grp) 来避免手动编码级别。 然而,Joran 的回答并没有硬编码颜色的值。在某些情况下,您需要给定因子的特定颜色值。 虽然在某些情况下我得到了“硬编码”的不利影响,但我认为开发人员/编码人员添加的抽象层常常使他们的工作更难访问,而不是更多。在这种情况下,意图是 100% 明确的。此外,很容易想到如何制作一个实用函数,该函数在此示例的基础上进行扩展,返回特定颜色的命名向量。

以上是关于如何为ggplot2中具有稳定映射的分类变量分配颜色?的主要内容,如果未能解决你的问题,请参考以下文章

带有 facet_grid 的 ggplot2 中具有多个分类变量的堆积条形图

R语言创建自定义颜色(分类变量与颜色形成稳定映射)实战:设置因子变量(分类变量)到可视化颜色的稳定映射

如何为静态变量分配内存?

在 DataBricks 中,如何为变量分配来自外部文件的字符串值?

如何为具有多种父类型的子场景编写 EF 代码优先映射

如何为具有映射到多个柴油列的自定义字段的类型派生 Queryable?