为ggplot2堆积条形图中的每个条形创建不同的颜色比例尺

6

我有一个堆叠条形图,看起来像这样:

每个药物的患者数量按药物类别

虽然颜色看起来很好,但是使用许多相似的颜色表示不同的药物会令人困惑。我希望在图表中为每个条形图使用单独的调色板,例如,class1可以使用“Blues”调色板,而class2可以使用“BuGn”调色板(调色板名称在此处找到)。

我发现一些人手动编码每个条形图的颜色(例如此处),但我不确定我所要求的是否可能 - 这些条形图需要基于调色板,因为每个药物类别中有太多药物。

创建上述图表的代码:

library(ggplot2)
library(plyr)
library(RColorBrewer)

drug_name <- c("a", "a", "b", "b", "b", "c", "d", "e", "e", "e", "e", "e", "e",
           "f", "f", "g", "g", "g", "g", "h", "i", "j", "j", "j", "k", "k",
           "k", "k", "k", "k", "l", "l", "m", "m", "m", "n", "o")
df <- data.frame(drug_name)

#get the frequency of each drug name
df_count <- count(df, 'drug_name')

#add a column that specifies the drug class
df_count$drug_class <- vector(mode='character', length=nrow(df_count))

df_count$drug_class[df_count$drug_name %in% c("a", "c", "e", "f")] <- 'class1'

df_count$drug_class[df_count$drug_name %in% c("b", "o")] <- 'class2'

df_count$drug_class[df_count$drug_name %in% c("d", "h", "i")] <- 'class3'

df_count$drug_class[df_count$drug_name %in% c("g", "j", "k", "l", "m", "n")] <- 'class4'

#expand color palette (from http://novyden.blogspot.com/2013/09/how-to-expand-color-palette-with-ggplot.html)

colorCount = length(unique(df_count$drug_name))
getPalette = colorRampPalette(brewer.pal(9, "Set1"))

test_plot <- ggplot(data = df_count, aes(x=drug_class, y=freq, fill=drug_name) ) + geom_bar(stat="identity") + scale_fill_manual(values=getPalette(colorCount))

test_plot

您可以查看使用ggplot在一个堆叠条形图中使用多个颜色比例尺。乍一看,它似乎是一个类似的情况。 - Henrik
2个回答

7

由于颜色太多,您的图形可能变得混乱。最好只用药物名称和计数标记每个条形部分。下面的代码展示了如何为每个条形制作单独的调色板以及如何给条形添加标签。

首先,添加一列用于定位条形标签:

library(dplyr) # for the chaining (%>%) operator

## Add a column for positioning drug labels on graph
df_count = df_count %>% group_by(drug_class) %>%
  mutate(cum.freq = cumsum(freq) - 0.5*freq)

其次,创建调色板。下面的代码使用了四个不同的Colorbrewer调色板,但您可以使用任何组合的调色板创建函数或方法来精细控制颜色。

## Create separate palette for each drug class

# Count the number of colors we'll need for each bar
ncol = table(df_count$drug_class)

# Make the palettes
pal = mapply(function(x,y) brewer.pal(x,y), ncol, c("BrBG","OrRd","YlGn","Set2"))
pal[[2]] = pal[[2]][1:2]  # We only need 2 colors but brewer.pal creates 3 minimum
pal = unname(unlist(pal)) # Combine palettes into single vector of colors

ggplot(data = df_count, aes(x=drug_class, y=freq, fill=drug_name) ) + 
  geom_bar(stat="identity", colour="black", lwd=0.2) + 
  geom_text(aes(label=paste0(drug_name,": ", freq), y=cum.freq), colour="grey20") +
  scale_fill_manual(values=pal) +
  guides(fill=FALSE)

输入图像描述

有许多策略和函数用于创建色板。这里介绍另一种方法,使用 hcl 函数:

lum = seq(100, 50, length.out=4)    # Vary the luminance for each bar
shift = seq(20, 60, length.out=4)  # Shift the hues for each bar

pal2 = mapply(function(n, l, s) hcl(seq(0 + s, 360 + s, length.out=n+1)[1:n], 100, l), 
              ncol, lum, shift)
pal2 = unname(unlist(pal2))

4
上述各种调色板并没有按照不同类别一致转换 - 相反,它们根据命名向量(a,b,c...)绘制,因此被分割成了各个不同的类别。有关详细信息,请参见??scale_fill_manual
为了将它们“匹配”到每组条形图,我们需要按类别对data.frame进行排序,并将调色板与名称适当对齐。 创建重复的调色板以测试正确(预期)的排序。
 repeating.pal = mapply(function(x,y) brewer.pal(x,y), ncol,        c("Set2","Set2","Set2","Set2"))

 repeating.pal[[2]] = repeating.pal[[2]][1:2]  # We only need 2 colors but brewer.pal creates 3 minimum

 repeating.pal = unname(unlist(repeating.pal))

按照班级对数据进行排序(按照我们想要的颜色顺序保持顺序!)
 df_count_sorted <- df_count[order(df_count$drug_class),]

复制药品名称的原始排序。
 df_count_sorted$labOrder <- df_count$drug_name

添加测试颜色板。

 df_count$colours<-repeating.pal

修改绘图例程,使用fill=labOrder参数。

ggplot(data = df_sorted, aes(x=drug_class, y=freq, fill=labOrder) ) + 
geom_bar(stat="identity", colour="black", lwd=0.2) + 
geom_text(aes(label=paste0(drug_name,": ", freq), y=cum.freq),     colour="grey20") +
scale_fill_manual(values=df_sorted$colours) +
guides(fill=FALSE)

Palette follows expected order


这太棒了。我已经想出了一种(有点)解决方法,但并没有完全解决问题。我在 @eipi10 的答案基础上进行了改进,用 pal <- colorRampPalette(brewer.pal(9,"Greens"))(41) 替换了之前定义的 pal - epi_n00b

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接