首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >重新排列“ggplot2”图例以混合和匹配不同的级别

重新排列“ggplot2”图例以混合和匹配不同的级别
EN

Stack Overflow用户
提问于 2020-09-27 06:02:43
回答 2查看 92关注 0票数 7

我有以下数据:

代码语言:javascript
复制
df1 <- structure(list(Wastewater_Treatment_Plant = c("D_S1_L001_R1_001", 
"D_S1_L001_R1_001", "D_S1_L001_R1_001", "D_S1_L001_R1_001", "D_S1_L001_R1_001", 
"D_S1_L001_R1_001", "D_S1_L001_R1_001", "D_S1_L001_R1_001", "D_S1_L001_R1_001", 
"D_S1_L001_R1_001", "D_S1_L001_R1_001", "D_S1_L001_R1_001", "D_S1_L001_R1_001", 
"D_S1_L001_R1_001", "D_S1_L001_R1_001", "D_S1_L001_R1_001", "D_S1_L001_R1_001", 
"D_S1_L001_R1_001"), Domain = c("Archaea", "Archaea", "Archaea", 
"Archaea", "Archaea", "Bacteria", "Bacteria", "Bacteria", "Bacteria", 
"Bacteria", "Bacteria", "Bacteria", "Eukaryota", "Eukaryota", 
"Eukaryota", "Eukaryota", "Other Sequences", "Viruses"), Phylum = c("Crenarchaeota", 
"Euryarchaeota", "Korarchaeota", "Nanoarchaeota", "Thaumarchaeota", 
"Acidobacteria", "Actinobacteria", "Aquificae", "Bacteroidetes", 
"Candidatus Poribacteria", "Chlamydiae", "Chlorobi", "Streptophyta", 
"Xanthophyceae", "unclassified (derived from Eukaryota)", "unclassified (derived from Fungi)", 
"unclassified (derived from other sequences)", "unclassified (derived from Viruses)"
), Alignment_Length = c(3573, 34060, 257, 22, 525, 85973, 670251, 
8825, 1040376, 1273, 5962, 41954, 13026, 5, 15129, 48, 528, 3451
), Relative_Alignment_Length = c(0.00185587444253646, 0.0176913192031323, 
0.000133489989289636, 1.14271586162334e-05, 0.000272693557887388, 
0.044655777623338, 0.348139294985867, 0.00458384885401182, 0.540388253296476, 
0.000661216950839325, 0.00309675998499926, 0.0217915914811571, 
0.00676591673341166, 2.59708150368941e-06, 0.00785824921386343, 
2.49319824354184e-05, 0.000274251806789602, 0.00179250565384643
), ymax = c(0.00185587444253646, 0.0195471936456687, 0.0196806836349584, 
0.0196921107935746, 0.019964804351462, 0.0646205819748, 0.412759876960667, 
0.417343725814679, 0.957731979111154, 0.958393196061993, 0.961489956046993, 
0.98328154752815, 0.990047464261561, 0.990050061343065, 0.997908310556929, 
0.997933242539364, 0.998207494346154, 1), ymin = c(0, 0.00185587444253646, 
0.0195471936456687, 0.0196806836349584, 0.0196921107935746, 0.019964804351462, 
0.0646205819748, 0.412759876960667, 0.417343725814679, 0.957731979111154, 
0.958393196061993, 0.961489956046993, 0.98328154752815, 0.990047464261561, 
0.990050061343065, 0.997908310556929, 0.997933242539364, 0.998207494346154
)), row.names = c(NA, -18L), class = c("tbl_df", "tbl", "data.frame"
))
Domain_Colors <- c("orange", "blue", "grey", "green", "purple")
Phyla_Colors <- c("#FEEDDE", "#FDBE85", "#FD8D3C", "#E6550D", "#A63603", "#440154FF", 
"#443A83FF", "#31688EFF", "#21908CFF", "#35B779FF", "#8FD744FF", 
"#FDE725FF", "#4D4D4D", "#969696", "#C3C3C3", "#E6E6E6", "green1", 
"purple1")

我已经创建了以下图表:

代码语言:javascript
复制
if (!require (dplyr)) {
  install.packages("dplyr")
}
library (dplyr)
if (!require (ggnewscale)) {
  install.packages("ggnewscale")
}
library (ggnewscale)
if (!require (ggplot2)) {
  install.packages("ggplot2")
}
library (ggplot2)
if (!require (tidyr)) {
  install.packages("tidyr")
}
library (tidyr)
ggplot(df1) +
  geom_rect(aes(fill = Domain, ymax = ymax, ymin = ymin, xmax = 2, xmin = 0)) +
  scale_fill_manual(aesthetics = "fill", values = Domain_Colors, breaks = unique(df1$Domain), name = "Domain") +
  new_scale_fill() +
  geom_rect(aes(fill = Phylum, ymax = ymax, ymin = ymin, xmax = 4, xmin = 2)) +
  scale_fill_manual(aesthetics = "fill", values = Phyla_Colors, breaks = unique(df1$Phylum), name = "Phylum") +
  coord_polar(theta = "y") +
  theme_void()

有没有办法重新排列图例,以便在每个域下面列出属于特定域的门?换句话说,我想把属性域(及其相关颜色)放在属于它的每一组门的头部。

此外,最好在图例中保留图例标题“域”和“门”,与不同的域和门相对应。

说到底,图例应该是这样的:

谢谢!

EN

回答 2

Stack Overflow用户

发布于 2020-09-27 16:36:51

也许这就是你要找的。要按域对phyla进行分组,您可以

  1. 分别绘制每个域(通过拆分或筛选您的数据集),并为每个域添加新的填充比例。
  2. 由于这是大量的手动工作(复制并粘贴代码5次),因此我使用一个函数为每个域添加图层,并使用imap对域进行循环。
  3. 为了获得域和门的正确颜色,我将所有颜色放在一个命名矢量中。
  4. 设置填充比例的分隔符,以确保域位于每个图例的开头<代码>H29scale_fill_manual.

中使用code>的

  • 参数来设置图例的顺序

最后,我不确定你所说的“……在图例中保留图例标题‘域’和‘门’是什么意思”。因此,我只需将域名放在图例标题中。

代码语言:javascript
复制
Domain_Colors <- c("orange", "blue", "grey", "green", "purple")
Phyla_Colors <- c("#FEEDDE", "#FDBE85", "#FD8D3C", "#E6550D", "#A63603", "#440154FF", 
                  "#443A83FF", "#31688EFF", "#21908CFF", "#35B779FF", "#8FD744FF", 
                  "#FDE725FF", "#4D4D4D", "#969696", "#C3C3C3", "#E6E6E6", "green1", 
                  "purple1")

Domain_Colors <- setNames(Domain_Colors, unique(df1$Domain))
Phyla_Colors <- setNames(Phyla_Colors, unique(df1$Phylum))

colors <- c(Domain_Colors, Phyla_Colors)
breaks_colors <- names(colors)

library(ggplot2)
library(ggnewscale)
library(purrr)
library(dplyr)

layers_help <- function(d, .domain, .order) {
  d <- filter(d, Domain == .domain)
  list(
    geom_rect(data = d, aes(fill = Domain, ymax = ymax, ymin = ymin, xmax = 2, xmin = 0)),
    geom_rect(data = d, aes(fill = Phylum, ymax = ymax, ymin = ymin, xmax = 4, xmin = 2)),
    scale_fill_manual(aesthetics = "fill", breaks = breaks_colors, values = colors, 
                      guide = guide_legend(title = .domain, order = as.integer(.order))),
    new_scale_fill()
  )
}

ggplot(df1) +
  imap(setNames(unique(df1$Domain), seq_along(unique(df1$Domain))), ~ layers_help(df1, .x, .y)) +
  coord_polar(theta = "y") +
  theme_void() +
  theme(legend.text=element_text(size = 4), legend.title=element_text(size = 6))

票数 3
EN

Stack Overflow用户

发布于 2020-09-27 22:10:06

再试一次。由于答案采用了与第一个不同的方法,因此我将其作为第二个答案发布。此外,即使是第二种解决方案也不是完美的。的主要缺点是它只适用于等宽字体

一般的想法是坚持使用您的绘图代码,但填充数据,以便每个域包含相同数量的门或类别。这样做可以按域按列排列门类。对于空的或辅助的类别,我将填充颜色设置为透明,并使用labeller函数将标签设置为空字符串,以便它们不会出现在图例中。

然而,棘手的部分是将域图例的图例键与门图例的键对齐。问题是图例的宽度由标签的长度和所选的字体决定。要使所有标签的长度相同,我们可以添加额外的空格。但是,标签的宽度仍将根据所选字体的不同而不同(默认情况下:"sans")。不幸的是,除了等宽字体的情况外,我不知道有什么简单的方法来解决这个问题。在这种情况下,长度等同于宽度,只需向标签添加额外的空格就足以确保域图例的项与门图例中的项对齐。

代码语言:javascript
复制
library(ggplot2)
library(ggnewscale)
library(tidyr)
library(dplyr)
library(stringr)

d <- df1 %>% 
  group_by(Domain) %>% 
  mutate(rank = row_number(Phylum),
         max_len = max(nchar(Phylum))
         ) %>% 
  ungroup() %>% 
  complete(Domain, rank, fill = list(ymin = 0, ymax = 0, xmin = 0, xmax = 0, Phylum = "empty")) %>% 
  fill(max_len) %>% 
  mutate(Phylum = if_else(Phylum == "empty", paste0(Domain, rank), Phylum),
         Phylum = if_else(str_detect(Phylum, "\\d$"), str_pad(Phylum, max_len, "left"), str_pad(Phylum, max_len, "right")),
         Domain = str_pad(Domain, max_len, "right"))

is_empty <- str_detect(d$Phylum, "\\d$")
empty_cat <- d$Phylum[is_empty]
non_empty_cat <- d$Phylum[!is_empty]

Domain_Colors <- c("orange", "blue", "grey", "green", "purple")
Phyla_Colors <- c("#FEEDDE", "#FDBE85", "#FD8D3C", "#E6550D", "#A63603", "#440154FF", 
                  "#443A83FF", "#31688EFF", "#21908CFF", "#35B779FF", "#8FD744FF", 
                  "#FDE725FF", "#4D4D4D", "#969696", "#C3C3C3", "#E6E6E6", "green1", 
                  "purple1")

Domain_Colors <- setNames(Domain_Colors, unique(d$Domain))
Phyla_Colors <- setNames(Phyla_Colors, non_empty_cat)

colors <- c(Domain_Colors, Phyla_Colors)
colors <- setNames(colors, names(colors))
colors <- c(colors, setNames(rep("transparent", length(empty_cat)), empty_cat))

breaks_phylum <- d %>% 
  arrange(Domain, rank) %>%
  pull(Phylum)
breaks <- c(unique(d$Domain), breaks_phylum)

mylabels <- function(breaks) {
  if_else(str_detect(breaks, "\\d$"), "", breaks)
}

ggplot(d) +
  geom_rect(aes(fill = Domain, ymax = ymax, ymin = ymin, xmax = 2, xmin = 0)) +
  scale_fill_manual(aesthetics = "fill", breaks = breaks, values = colors, labels = mylabels, 
                    guide = guide_legend(title = "Domain", order = 1, nrow = 1)) +
  new_scale_fill() +
  geom_rect(aes(fill = Phylum, ymax = ymax, ymin = ymin, xmax = 2, xmin = 0)) +
  scale_fill_manual(aesthetics = "fill", breaks = breaks, values = colors, labels = mylabels,
                    guide = guide_legend(title = "Phylum", order = 0, nrow = 7)) +
  coord_polar(theta = "y") +
  theme_void(base_family = "mono") +
  theme(legend.text=element_text(size = 4), 
        legend.title=element_text(size = 6, vjust = 1), 
        legend.position = "bottom", 
        legend.box = "vertical",
        legend.box.just = "left")

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64082907

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档