如何在ggplot2中为每个分面标签指定不同的背景颜色?

4
这些数据将被用来制作一个图表:
  mtcars %>%
  gather(-mpg, key = "var", value = "value") %>%
  ggplot(aes(x = value, y = mpg)) +
  geom_point() +
  facet_wrap(~ var, scales = "free") +
  theme_bw()

如何更改面板标题的灰色颜色,例如

 panels of am and hp   green 
 panels of gear drat disp   red 
 panels  of vs wt   blue
 panels cyl qsec carb black 

添加图例

      green  = area 
      red=  bat
      blue= vege
      black = indus

请查看这个问题 - Dion Groothof
看起来这可能是你问题的答案:https://dev59.com/WWIk5IYBdhLWcg3wRMJQ#21589891 - René
@René,您提供的链接指向相同的帖子。 - Dion Groothof
1个回答

5

不幸的是,回答 OP 的问题的方式仍然相当 hacky。

如果您不喜欢像 gtable hacks 这样的东西……这里有另一种非常 hacky 的方法来实现。享受奇怪的旅程吧。

TL;DR - 这里的想法是使用一个矩形 geom 在绘图区域之外 来绘制每个 facet 标签框的颜色。

下面是基本的绘图。OP 想要 (1) 更改 facet 标签后面的灰色颜色(称为 "strip" 标签)为特定的颜色,具体取决于 facet 标签,然后 (2) 添加一个图例。

首先,我只引用了聚合数据框作为df,所以现在的绘图代码看起来像这样:

df <- mtcars %>% gather(-mpg, key = "var", value = "value")

ggplot(df, aes(x = value, y = mpg)) +
  geom_point() +
  facet_wrap(~ var, scales = "free") +
  theme_bw()

enter image description here

如何重新着色每个面板的标签?

正如其他答案中提到的那样,通过theme()元素strip.backgroundstrip.text,可以很容易地一次性更改所有面板标签的颜色(以及标签文本):

plot + theme(
  strip.background = element_rect(fill="blue"), 
  strip.text=element_text(color="white"))

enter image description here

当然,我们不能为所有的facet标签这样做,因为`strip.background`和`element_rect()`无法发送矢量或将映射应用于美学。
这里的想法是使用某些可以将美学映射到数据(因此根据数据进行更改)的东西 - 使用一个geom。在这种情况下,我将使用`geom_rect()`在每个facet中绘制一个矩形,然后根据OP在问题中陈述的标准对该矩形进行着色。此外,以这种方式使用`geom_rect()`还会自动为我们创建图例,因为我们将使用映射和`aes()`指定颜色。我们需要做的就是允许`ggplot2`绘制图层超出绘图区域,使用一些手动微调来正确地放置它,它就可以工作了!

黑客

首先,创建一个单独的数据集,其中包含名为var的列,其中包含所有分面名称。然后,var_color指定了OP为每个分面给出的名称。我们使用scale_fill_manual()函数指定颜色。最后,在这里小心使用coord_cartesian()很重要。我们需要这个函数有两个原因:
  1. 将绘图中的面板区域裁剪为仅包含。如果没有指定y限制,则面板将自动调整大小以容纳rect几何图形。
  2. 关闭裁剪。这允许在面板外绘制的图层可见。
然后,我们需要将strip.background设置为透明(这样我们就可以看到盒子的颜色),然后我们就可以开始了。希望您可以在下面跟随。我为了更清晰地表示所有代码如下:
library(ggplot2)
library(tidyr)
library(dplyr)

# dataset for plotting
df <- mtcars %>% gather(-mpg, key = "var", value = "value")

# dataset for facet label colors
hacky_df <- data.frame(
  var = c("am", "carb", "cyl", "disp", "drat", "gear", "hp", "qsec", "vs", "wt"),
  var_color = c("area", "indus", "indus", "bat", "bat", "bat", "area", "indus", "vege", "vege")
)

# plot code
plot_new <-
  ggplot(df) +    # don't specify x and y here.  Otherwise geom_rect will complain.
  geom_rect(
    data=hacky_df,
    aes(xmin=-Inf, xmax=Inf,
        ymin=36, ymax=42,     # totally defined by trial-and-error
        fill=var_color, alpha=0.4)) +
  geom_point(aes(x = value, y = mpg)) +     
  coord_cartesian(clip="off", ylim=c(10, 35)) +
  facet_wrap(~ var, scales = "free") +
  scale_fill_manual(values = c("area" = "green", "bat" = "red", "vege" = "blue", "indus" = "black")) +
  
  theme_bw() +
  theme(
    strip.background = element_rect(fill=NA),
    strip.text = element_text(face="bold")
  )

plot_new

enter image description here


1
谢谢,这种方法唯一的问题是当y轴在变量之间完全不同的时候,我们无法使用aes(xmin=-Inf, xmax=Inf, ymin=36, ymax=42)。你知道如何分配每个变量的最大值吗? - bic ton
这需要一些工作,但完全可行。您可以在hacky_df中定义yminymax的值作为新列,然后映射该列,而不是在aes()中定义它们的值。例如:将bottom = c(...)top = c(...)添加到hacky_df中,然后用ymin = bottom替换ymin = 36,用ymax = top替换ymax = 42 - chemdork123
是的,您需要将 ylim(...) 部分保留在 coord_cartesian() 中。否则,比例尺会自动调整以使矩形保持在绘图的尺寸内。您可以根据数据设置尺寸:例如 ylim = c(max(mtcars$mpg), min(mtcars$mpg)) - chemdork123
谢谢,但这不会是每个变量的最大值和最小值。它将是所有变量的最小值和最大值。 - bic ton
你可以选择使用 patchworkgrid.arrange()cowplot() 来组合单独的图表或图表列表,这样你就可以单独控制每个图表。 - chemdork123
显示剩余3条评论

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