基于多面图中变量值的颜色轴文本

Color axis text based on variable value in a faceted plot

我有两个多面图,当给定变量的值为 NA 或 0 时,我希望轴文本为灰色。这目前适用于单个图,但当我对它们进行多面化时,文本颜色不匹配与酒吧价值。请参阅下面的代表:

# create df
text <-   
"   country          domain var_name    perc           color
        A             'domain c           Val2      NA            grey
        A             'domain c'           Val1      NA            grey
        A             'domain c'           Val3 0.01670          orange
        A             'domain c'           Val8 0.00000            grey
        A             'domain c'           Val9      NA            grey
        A             'domain c'          Val11 0.02510          orange
        A             'domain c'          Val19 0.01890          orange
        A           'domain d'          Val16 0.04840          purple
        A            'domain a'           Val5 0.00776 darkolivegreen4
       A            'domain a'           Val6 0.02390 darkolivegreen4
       A            'domain a'           Val7 0.00247 darkolivegreen4
       A            'domain a'          Val10 0.03840 darkolivegreen4
       A            'domain a'          Val13 0.02490 darkolivegreen4
       A            'domain a'          Val18      NA            grey
       A            'domain b'           Val4 0.01630            navy
       A             'domain b'          Val14 0.01610            navy
       A             'domain b'          Val12 0.05180            navy
       A             'domain b'          Val17 0.01770            navy
       A             'domain b'          Val15 0.03550            navy
       B             'domain c'           Val2 0.01440          orange
       B             'domain c'           Val1      NA            grey
       B             'domain c'           Val3 0.02590          orange
       B             'domain c'           Val8 0.00000            grey
       B             'domain c'           Val9     NaN            grey
       B             'domain c'          Val11 0.02900          orange
       B             'domain c'          Val19 0.00000            grey
       B 'domain d'          Val16 0.00261          purple
       B            'domain a'           Val5 0.10900 darkolivegreen4
       B            'domain a'           Val6 0.00702 darkolivegreen4
       B            'domain a'           Val7 0.01330 darkolivegreen4
       B            'domain a'          Val10 0.00861 darkolivegreen4
       B            'domain a'          Val13 0.06050 darkolivegreen4
       B            'domain a'          Val18 0.07770 darkolivegreen4
       B            'domain b'           Val4 0.00797            navy
       B             'domain b'          Val14 0.05230            navy
       B             'domain b'          Val12 0.04290            navy
       B             'domain b'          Val17 0.03190            navy
       B             'domain b'          Val15 0.06940            navy" 

tbl <- read.table(text = text, header = T, fill = T) 

# overwrite coord_polar function
cp <- coord_polar(theta = "x")
cp$is_free <- function() TRUE

# plot
p <-
  ggplot(tbl, aes(x = forcats::as_factor(var_name), y = perc)) +
  cp +
  geom_bar(stat = "identity", aes(fill = color)) +
  scale_y_continuous(labels = scales::label_percent()) + 
  scale_fill_identity(name = "Domain") +
  facet_grid(. ~ country, scales = "fixed") +
  theme_bw() +
  theme(aspect.ratio = 1,
        strip.text = element_text(size = 16),
        axis.title = element_text(size = 18),
        title = element_text(size = 20),
        axis.text.x = element_text(colour = tbl$color, face = "bold"),
        legend.text = element_text(size = 14))

p

生成这张图片:

请注意,对于国家 B,当该变量的数量明显非零时,Var18 是灰色的。这是因为 A 国的那个值是 0。

我想避免使用 Grid::,但非常感谢任何有关如何克服此问题的建议!

所以我找到了一种使用网格修复轴颜色和比例图的方法。基于上述代表:

# Generate a function to get the legend of one of the ggplots
get_legend<-function(myggplot){
    tmp <- ggplot_gtable(ggplot_build(myggplot))
    leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
    legend <- tmp$grobs[[leg]]
    return(legend)
  }

# From the full dataset, find the value of the country with the highest percent of any var_name

max <- round(max(tbl$perc), digits = 2)

# create a sequence of length 6 from 0 to the largest perc value
max_seq <- seq(0, max, length = 6)

# initiate empty list 
my_list <- list()

# list of countries to loop through
my_sub <- c("A", "B")

现在我们遍历每个国家,将每个国家的地块保存到空列表中。

for(i in my_sub){

  ### Wrangle
  tbl_sub <-
      tbl %>%
      dplyr::mutate(country = as.factor(country),
                    domain = as.factor(domain)) %>%       
      dplyr::filter(country == i),
      dplyr::mutate(perc = ifelse(is.na(perc), 0, perc))

  # Create custom coord_polar arguments 
  cp <- coord_polar(theta = "x", clip = "off")
  cp$is_free <- function() TRUE

  p <-
    ggplot(dplyr::filter(tbl_sub, country == i), 
           aes(x = forcats::as_factor(var_name), 
               y = perc)) +
           cp +
           geom_bar(stat = "identity", aes(fill = color)) +
           facet_grid(. ~ country, scales = "fixed") +
           scale_y_continuous(breaks = c(max_seq), 
                              labels = scales::label_percent(), 
                              limits = c(0, max(max_seq))) +
           scale_fill_identity(guide = "legend", 
                               name = "Domain", 
                               labels = c(darkolivegreen4 = "domain a", 
                                          orange = "domain c", 
                                          navy = "domain b" , 
                                          purple = "domain d", 
                                          grey = "not applicable")) +
           labs(x = "",
                y = "") +
           theme_bw() +
           theme(aspect.ratio = 1,
                 panel.border = element_blank(),
                 strip.text = element_text(size = 16),
                 axis.title = element_text(size = 18),
                 title = element_text(size = 20),
                 axis.text.x = element_text(colour = tbl_new$color, face = "bold"),
                 legend.text = element_text(size = 14))

  my_list[[i]] <- p

  }

现在我们在列表中有了绘图,我们想玩转图例并使用 grid:: 和 gridExtra 将所有内容绘制在一起。

# pull legend from first ggplot in the list 
legend <- get_legend(my_list[[1]])

# remove legends from all the plots in the list
for(i in 1:length(my_list)){
  my_list[[i]] <- my_list[[i]] + theme(legend.position = "none")
}

# plot everything together
p <- grid.arrange(arrangeGrob(
  grobs = my_list,
  nrow = round(length(my_sub)/2, 0),
  left = textGrob("Y axis",
                    gp = gpar(fontsize = 20),
                    rot = 90),
  bottom = textGrob("X axis",
                      gp = gpar(fontsize = 20),
                      vjust = -3),
  top = textGrob("Big plot",
                   gp = gpar(fontsize = 28, vjust = 2))),
  legend = legend,
  widths = c(9,1,1),
  clip = F)

这会产生这张图片:

这些图按比例缩放到具有最大 perc 值 (0 - 11%) 的国家/地区,并且每个国家/地区都有唯一的灰色值,具体取决于 perc 列中是否有 0 或 NA。

我敢肯定还有更简单的解决方案,但现在这对我有用!

遵循 Z.Lin 的建议并使用 geom_text 会更快一些。这是一个快速的解决方法,但并不理想,因为文本不会在最边缘结束,而且无论出于何种原因,我都无法让 clip = off 在 coord_polar 中工作。

(我对数据做了一些修改,因为它很难阅读)

library(ggplot2)

maxval <- max(tbl$perc, na.rm = T)

ggplot(tbl, aes(x = var_name, y = perc)) +
  coord_polar(theta = "x") +
  geom_col(aes(fill = color)) +
  geom_text(aes(x = var_name, y = maxval + 0.02, color = color, label = var_name),
              size = 10*5/14) +
  scale_fill_identity(name = "Domain") +
  scale_color_identity(name = "Domain") +
  facet_grid(. ~ country, scales = "fixed") +
  theme_minimal(base_size = 10) +
  theme(axis.text.x = element_blank())

#> Warning: Removed 6 rows containing missing values (position_stack).

数据

text <-   
  "country          domain var_name    perc           color
        A             domainc           Val2      NA            grey
        A             domainc           Val1      NA            grey
        A             domainc           Val3 0.01670          orange
        A             domainc           Val8 0.00000            grey
        A             domainc           Val9      NA            grey
        A             domainc          Val11 0.02510          orange
        A             domainc          Val19 0.01890          orange
        A           domaind          Val16 0.04840          purple
        A            domaina           Val5 0.00776 darkolivegreen4
       A            domaina           Val6 0.02390 darkolivegreen4
       A            domaina           Val7 0.00247 darkolivegreen4
       A            domaina          Val10 0.03840 darkolivegreen4
       A            domaina          Val13 0.02490 darkolivegreen4
       A            domaina          Val18      NA            grey
       A            domainb           Val4 0.01630            navy
       A             domainb          Val14 0.01610            navy
       A             domainb          Val12 0.05180            navy
       A             domainb          Val17 0.01770            navy
       A             domainb          Val15 0.03550            navy
       B             domainc           Val2 0.01440          orange
       B             domainc           Val1      NA            grey
       B             domainc           Val3 0.02590          orange
       B             domainc           Val8 0.00000            grey
       B             domainc           Val9     NaN            grey
       B             domainc          Val11 0.02900          orange
       B             domainc          Val19 0.00000            grey
       B            domaind          Val16 0.00261          purple
       B            domaina           Val5 0.10900 darkolivegreen4
       B            domaina           Val6 0.00702 darkolivegreen4
       B            domaina           Val7 0.01330 darkolivegreen4
       B            domaina          Val10 0.00861 darkolivegreen4
       B            domaina          Val13 0.06050 darkolivegreen4
       B            domaina          Val18 0.07770 darkolivegreen4
       B            domainb           Val4 0.00797            navy
       B             domainb          Val14 0.05230            navy
       B             domainb          Val12 0.04290            navy
       B             domainb          Val17 0.03190            navy
       B             domainb          Val15 0.06940            navy" 

tbl <- data.table::fread(text = text, header = T, fill = T)