如何将两个数据框组合成一个图表,其中每个 class 有两个并排的堆叠条形图?

How to combine two data frames into one graph where I will have two stacked bars side by side for each class?

我专门为此注册的

基本上我有两个数据框,它们具有完全相同的信息,但来自两个不同的年份。

这里是其中一个数据帧的 head():

species dbh_cm height_m         f plot dbh_m           ba
1       1    0.7     1.34 7.1627066   16 0.007 3.848451e-05
2       3    1.9     1.95 2.0018036   16 0.019 2.835287e-04
3       3    4.0     3.05 0.9120516   16 0.040 1.256637e-03
4       1    3.5     2.27 1.0072122   16 0.035 9.621128e-04
5       3    0.6     1.52 6.9312671   16 0.006 2.827433e-05
6       3    4.2     2.70 0.9406631   16 0.042 1.385442e-03
        volume class     Sp
1 0.0003693754 (0,5] Spruce
2 0.0011067593 (0,5]  Larch
3 0.0034956596 (0,5]  Larch
4 0.0021997474 (0,5] Spruce
5 0.0002978850 (0,5]  Larch
6 0.0035187332 (0,5]  Larch

为了绘制每一个图表,我使用了:

ggplot(data=trees_b, aes(x=class, fill = Sp)) + 
  geom_bar(stat = "count") +
  labs( x = "DBH classes [cm]", y = "Number of trees [n]", fill="Species") +
  scale_x_discrete(labels=c("(0,5]" = "2.5","(5,10]" = "7.5", "(10,15]" = "12.5",
                            "(15,20]" = "17.5", "(20,25]" = "22.5", "(25,30]" = "27.5",
                            "(30,35]" = "32.5", "(35,40]" = "37.5", "(40,45]" = "42.5",
                            "(45,50]" = "47.5", "(50,55]" = "52.5", "(55,60]" = "57.5",
                            "(60,65]" = "62.5", "(65,70]" = "67.5","(70,75]" = "72.5",
                            "(75,80]" = "77.5", "(80,85]" = "82.5")) +
  scale_fill_viridis(direction = -1, discrete = T) +
  theme(axis.text.x = element_text( size = 15),
        axis.text.y = element_text (size = 15),
        axis.title = element_text(size = 15),
        legend.text = element_text (size = 15),
        legend.title = element_text (size = 16, face = "bold"))

我知道代码不是最干净的,但它完美地满足了我的需要,就是这样:

enter image description here

现在我想基本上将两个图合二为一进行比较,有没有办法做到这一点?

组合图表的一种方法是使用分面。为此,我使用 dplyr::bind_rows 按行绑定数据集,这使得向数据中添加标识符列变得容易,然后可以将其用作分面变量:

注意:我还添加了一个简单的函数来计算 class 均值。

trees_b <- trees_a

trees <- list(a = trees_a, b = trees_b) |>
  dplyr::bind_rows(.id = "id")

library(ggplot2)
library(viridis)
#> Loading required package: viridisLite

class_mean <- function(x) {
  sapply(stringr::str_extract_all(x, "\d+"), function(x) mean(as.numeric(x)))
}

ggplot(data = trees, aes(x = class, fill = Sp)) +
  geom_bar(stat = "count") +
  labs(x = "DBH classes [cm]", y = "Number of trees [n]", fill = "Species") +
  scale_x_discrete(labels = class_mean) +
  scale_fill_viridis(direction = -1, discrete = T) +
  theme(
    axis.text.x = element_text(size = 15),
    axis.text.y = element_text(size = 15),
    axis.title = element_text(size = 15),
    legend.text = element_text(size = 15),
    legend.title = element_text(size = 16, face = "bold")
  ) +
  facet_wrap(~id)

编辑 正如您在评论中澄清的那样,您需要一个堆叠和闪避的条形图。实现这一目标的一种方法是通过“看起来不像刻面的刻面”技巧。基本思想是根据映射到 x 的变量进行分面,而不是将分面变量映射到 x。之后,我们通过主题选项使用一些样式来摆脱分面外观。有关更多选项,请查看 ggplot2 - bar plot with both stack and dodge.

ggplot(data = trees, aes(x = id, fill = Sp)) +
  geom_bar(stat = "count") +
  labs(x = "DBH classes [cm]", y = "Number of trees [n]", fill = "Species") +
  scale_fill_viridis(direction = -1, discrete = T) +
  theme(
    axis.text.x = element_text(size = 15),
    axis.text.y = element_text(size = 15),
    axis.title = element_text(size = 15),
    legend.text = element_text(size = 15),
    legend.title = element_text(size = 16, face = "bold")
  ) +
  facet_wrap(~class, labeller = labeller(class = class_mean), strip.position = "bottom", nrow = 1) +
  theme(strip.placement = "outside", strip.background.x = element_blank(), panel.spacing.x = unit(0, "pt"))

数据

trees_a <- structure(list(
  species = c(1L, 3L, 3L, 1L, 3L, 3L), dbh_cm = c(
    0.7,
    1.9, 4, 3.5, 0.6, 4.2
  ), height_m = c(
    1.34, 1.95, 3.05, 2.27,
    1.52, 2.7
  ), f = c(
    7.1627066, 2.0018036, 0.9120516, 1.0072122,
    6.9312671, 0.9406631
  ), plot = c(16L, 16L, 16L, 16L, 16L, 16L),
  dbh_m = c(0.007, 0.019, 0.04, 0.035, 0.006, 0.042), ba = c(
    3.848451e-05,
    0.0002835287, 0.001256637, 0.0009621128, 2.827433e-05, 0.001385442
  ), volume = c(
    0.0003693754, 0.0011067593, 0.0034956596, 0.0021997474,
    0.000297885, 0.0035187332
  ), class = c(
    "(0,5]", "(0,5]", "(0,5]",
    "(0,5]", "(0,5]", "(0,5]"
  ), Sp = c(
    "Spruce", "Larch", "Larch",
    "Spruce", "Larch", "Larch"
  )
), class = "data.frame", row.names = c(
  "1",
  "2", "3", "4", "5", "6"
))