how to plot subsequent bars in a bar plot with ggplot2

44 Views Asked by At

I have the following dataframe called df1

Define the dataframe

df1 <- data.frame(
  trait = c("CRP", "CRP", "CRP", "TotChol", "TotChol", "TotChol", "RBC", "RBC", "RBC", "glucose", "glucose", "glucose"),
  Variable = c("PRSeur_r2_PGScatalog", "PRSeur_r2_mol", "moliPRS_eurPRS", 
               "PRSeur_r2_PGScatalog", "PRSeur_r2_mol", "moliPRS_eurPRS", 
               "PRSeur_r2_PGScatalog", "PRSeur_r2_mol", "moliPRS_eurPRS", 
               "PRSeur_r2_PGScatalog", "PRSeur_r2_mol", "moliPRS_eurPRS"),
  Value = c(14, 3.5, 3.9, 11, 9, 9.4, 15, 7, 8.11, 3, 1.3, 1.4)
)

Print the dataframe

print(df)

And I wrote the following code to have a bar plot:

ggplot(df1, aes(x = trait, y = Value, fill = Variable)) +
  geom_bar(stat = "identity", position = position_dodge(width = 0.9), col = "black") +
  geom_text(aes(label = paste0(Value, "%")), 
            position = position_dodge(width = 0.8), 
            vjust = -0.5, size = 3) + # Add percentages upon each bar
  scale_x_discrete(labels = c("CRP", 
                              "TotChol",
                              "RBC")) +
  scale_fill_manual(values = c("#39568CFF",
                               "#20A387FF", 
                               "#FDE725FF"),
                    labels = c("PRSeur_r2_moli" = "X",
                               "PRSeur_r2_PGScatalog" = "Y",
                               "moliPRS_eurPRS" = "Z")) +
  theme_bw() +
  theme(
    axis.text.y = element_text(size = 10),
    axis.text.x = element_text(size = 10),
    axis.title = element_text(size = 10, face = "bold"),
    legend.text = element_text(size = 10),
    panel.border = element_blank(),
    text = element_text(family = "Times New Roman")
  ) +
  labs(title = "",
       x = "",
       y = "r2",
       fill = NULL)

I have the following plot: enter image description here

I would like to create subsequent bar plots, maintaining the same size and position per each bar, as follows:

enter image description here enter image description here enter image description here

How can I do it with ggplot2 in R?

2

There are 2 best solutions below

0
stefan On BEST ANSWER

Put your plotting code in a function, set the Value for the undesired categories to NA and to silent the warnings about removed missing set na.rm=TRUE in the geoms:

library(ggplot2)

plot_fun <- function(include = NULL) {
  if (!is.null(include)) {
    df1 <- df1 |>
      transform(
        Value = ifelse(Variable %in% include, Value, NA)
      )
  }

  ggplot(df1, aes(x = trait, y = Value, fill = Variable)) +
    geom_bar(
      stat = "identity",
      position = position_dodge(width = 0.9),
      col = "black",
      na.rm = TRUE
    ) +
    geom_text(aes(label = paste0(Value, "%")),
      position = position_dodge(width = 0.8),
      vjust = -0.5, size = 3,
      na.rm = TRUE
    ) +
    scale_x_discrete(labels = c(
      "CRP",
      "TotChol",
      "RBC"
    )) +
    theme_bw() +
    theme(
      axis.text.y = element_text(size = 10),
      axis.text.x = element_text(size = 10),
      axis.title = element_text(size = 10, face = "bold"),
      legend.text = element_text(size = 10),
      panel.border = element_blank(),
      text = element_text(family = "Times New Roman")
    ) +
    labs(
      title = "",
      x = "",
      y = "r2",
      fill = NULL
    ) +
    scale_fill_manual(
      values = c(
        "#39568CFF",
        "#20A387FF",
        "#FDE725FF"
      ),
      labels = c(
        "PRSeur_r2_mol" = "X",
        "PRSeur_r2_PGScatalog" = "Y",
        "moliPRS_eurPRS" = "Z"
      )
    )
}

df1$Variable <- factor(
  df1$Variable,
  levels = c("PRSeur_r2_PGScatalog", "PRSeur_r2_mol", "moliPRS_eurPRS")
)

plot_fun("PRSeur_r2_PGScatalog")

plot_fun(c("PRSeur_r2_mol", "PRSeur_r2_PGScatalog"))

plot_fun()

0
zephryl On

Accumulate versions of your dataframe with "omitted" values and labels set to 0 and "", bind these into a single df with an index column, then facet by index:

library(ggplot2)
library(dplyr)

# change to factor with levels matching OP's plots
df1$Variable <- factor(
  df1$Variable,
  levels = c("PRSeur_r2_PGScatalog", "PRSeur_r2_mol", "moliPRS_eurPRS")
)

included <- Reduce(\(x, y) c(x, y), levels(df1$Variable), accumulate = TRUE)

dfs <- lapply(included, \(incl) {
  mutate(
    df1, 
    Value = if_else(Variable %in% incl, Value, 0),
    Label = if_else(Variable %in% incl, paste0(Value, "%"), "")
  )
})

df2 <- bind_rows(dfs, .id = "Step")

ggplot(df2, aes(x = trait, y = Value, fill = Variable)) +
  geom_bar(stat = "identity", position = position_dodge(width = 0.9), col = "black") +
  geom_text(aes(label = Label), 
            position = position_dodge(width = 0.8), 
            vjust = -0.5, size = 3) + # Add percentages upon each bar
  scale_x_discrete(labels = c("CRP", 
                              "TotChol",
                              "RBC")) +
  scale_fill_manual(values = c("#39568CFF",
                               "#20A387FF", 
                               "#FDE725FF"),
                    labels = c("PRSeur_r2_mol" = "X",    # fixed typo
                               "PRSeur_r2_PGScatalog" = "Y",
                               "moliPRS_eurPRS" = "Z")) +
  theme_bw() +
  facet_wrap(vars(Step), ncol = 1) +
  theme(
    axis.text.y = element_text(size = 10),
    axis.text.x = element_text(size = 10),
    axis.title = element_text(size = 10, face = "bold"),
    legend.text = element_text(size = 10),
    panel.border = element_blank(),
    strip.text = element_blank()
  ) +
  labs(title = "",
       x = "",
       y = "r2",
       fill = NULL)