【问题标题】:Manually position labels in ggplot legend在 ggplot 图例中手动定位标签
【发布时间】:2018-12-05 11:16:30
【问题描述】:

我想知道是否可以在 ggplot 的图例中手动定位标签?

我的例子是这样的:我有一个国家数据,我正在为每个大陆做一个 100% 堆积的条形图,所以我有:

dt <- data.table(continent = c(rep('Africa', 2), rep('Asia', 3), rep('Europe', 4)),
                 country = c('Nigeria', 'Kenya',
                             'China', 'India', 'Japan',
                             'Germany', 'Sweden', 'Spain', 'Croatia'),
                 value = runif(9, 0, 10),
                 number=(1:9))


ggplot(data=dt, 
       aes(x = continent, y = value, fill = as.factor(number))) +
  geom_bar(stat = "identity", position = "fill", color='white', width=0.3 ) + 
  labs(x = '', y = 'Percentage') +
  scale_y_continuous(expand=c(0,0)) +
  scale_fill_manual('Country',
                    labels = dt[, country],
                    values = (grDevices::colorRampPalette(c('#BB16A3', '#f8e7f5')))(9)) +
  theme(legend.position='bottom', aspect.ratio = 1) +
  guides(fill = guide_legend(title.position="top", title.hjust = 0.5, reverse=T)) +
  coord_flip()

所以我的问题是,是否可以重新定位图例中的标签,以便每个大陆的国家/地区位于单独的列中?还是单独一行?

谢谢!

【问题讨论】:

    标签: r ggplot2


    【解决方案1】:

    我注意到每个大陆有不同数量的国家/地区。 ggplot() 可以按行或按列填充图例矩阵,但我从未见过每行/列中有不同数量的单元格的锯齿状矩阵。

    虽然看起来像锯齿状的图例矩阵,但也有可能破解。这里有一些实现。如果您想按特定顺序对大陆/国家标签进行排序,或者改变图例键之间的间距等,您可能希望调整参数。

    准备工作

    # define fill mapping so that it can be re-used for both top plot & legend
    scale_fill_country <- 
      scale_fill_manual(labels = dt[, country],
                        values = (grDevices::colorRampPalette(c('#BB16A3', '#f8e7f5')))(9))
    
    # create top plot (without any legend)
    gg.plot <- ggplot(data = dt, 
                      aes(x = continent, y = value, fill = as.factor(number))) +
      #note: geom_col is equivalent to geom_bar(stat = "identity")
      geom_col(position = "fill", color='white', width=0.3 ) + 
      labs(x = '', y = 'Percentage') +
      scale_y_continuous(expand=c(0,0)) +
      scale_fill_country +
      theme_classic() +
      theme(legend.position = "none") +
      coord_flip()
    

    修改图例的数据源

    library(dplyr)
    dt.legend <- dt %>% 
    
      # pad with empty rows so that there are equal number of countries under
      # each continent
      group_by(continent) %>% 
      arrange(country) %>% 
      mutate(country.id = seq(1, n())) %>% 
      ungroup() %>% 
      tidyr::complete(continent, country.id, fill = list(country = " ")) %>%
    
      # make each empty row distinct (within the same continent), & sort them
      # after the original rows
      rowwise() %>%
      mutate(country = ifelse(country == " ", 
                              paste0(rep.int(" ", country.id), collapse = ""),
                              country)) %>%
      ungroup() %>%
      mutate(country = forcats::fct_reorder(country, country.id))
    
    > dt.legend
    # A tibble: 12 x 5
       continent country.id country   value number
       <chr>          <int> <fct>     <dbl>  <int>
     1 Africa             1 Kenya    2.02        2
     2 Africa             2 Nigeria  7.17        1
     3 Africa             3 "   "   NA          NA
     4 Africa             4 "    "  NA          NA
     5 Asia               1 China    3.21        3
     6 Asia               2 India    5.59        4
     7 Asia               3 Japan    9.31        5
     8 Asia               4 "    "  NA          NA
     9 Europe             1 Croatia  0.0131      9
    10 Europe             2 Germany  0.0775      6
    11 Europe             3 Spain    3.98        8
    12 Europe             4 Sweden   0.703       7
    

    第 1 版:每个大陆在一个,标签下面图例键(如果您不希望显示与每一行关联的大陆标签,请将 axis.text.y = element_blank() 添加到 theme()

    gg.legend.rows1 <- ggplot(data = dt.legend,
                             aes(x = country, y = continent,
                                 fill = as.factor(number))) +
      geom_tile(color = "white", size = 2) +
      facet_wrap(~ continent, scales = "free", ncol = 1) +
      scale_y_discrete(expand = c(0, 0)) +
      scale_fill_country +
      theme_minimal() +
      theme(axis.title = element_blank(),
            strip.text = element_blank(),
            panel.grid = element_blank(),
            legend.position = "none")
    
    cowplot::plot_grid(gg.plot, gg.legend.rows1,
                       ncol = 1,
                       rel_heights = c(1, 0.3))
    

    第 2 版:每个大陆在一个中,标签位于右侧 传奇的关键(我想不出一种方法来获得大陆标签的这种方法,但我认为这个问题无论如何都不需要......)

    gg.legend.rows2 <- ggplot(data = dt.legend,
           aes(x = "", y = country, fill = as.factor(number))) +
      geom_tile() +
      scale_y_discrete(position = "right", expand = c(0, 0)) +
      facet_wrap(~ interaction(continent, country, lex.order = TRUE), 
                 scales = "free") +
      scale_fill_country +
      theme_minimal() +
      theme(axis.title = element_blank(),
            axis.text.x = element_blank(),
            strip.text = element_blank(),
            panel.grid = element_blank(),
            panel.spacing = unit(0, "pt"),
            legend.position = "none")
    
    cowplot::plot_grid(gg.plot, gg.legend.rows2,
                       axis = "l", align = "v",
                       ncol = 1,
                       rel_heights = c(1, 0.2))
    

    第 3 版:每个大陆在一个中,标签位于右侧 图例键(如果您不希望显示与每列关联的大陆标签,请将 axis.text.x = element_blank() 添加到 theme()

    gg.legend.columns <- ggplot(data = dt.legend,
                                aes(x = continent, y = forcats::fct_rev(country), 
                                    fill = as.factor(number))) +
      geom_tile(color = "white", size = 2) +
      facet_wrap(~ continent, scales = "free", nrow = 1) +
      scale_x_discrete(position = "top", expand = c(0, 0)) +
      scale_y_discrete(position = "right", expand = c(0, 0)) +
      scale_fill_country +
      theme_minimal() +
      theme(axis.title = element_blank(),
            strip.text = element_blank(),
            panel.grid = element_blank(),
            legend.position = "none")
    
    cowplot::plot_grid(gg.plot, gg.legend.columns, 
                       axis = "l", align = "v",
                       ncol = 1, 
                       rel_heights = c(1, 0.3))
    

    【讨论】:

    • 绝妙的答案!
    • 亲爱的farazan,如果它可以作为您的解决方案,请检查答案中的勾号。它可以帮助其他人了解问题是否已解决。
    猜你喜欢
    • 2014-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多