Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How can I insert complex horizontal bar labels in R?

I have the following sample dataset. The basis is a survey conducted at two time points. The survey results are differentiated by two groups (group1 and group2):

df <- structure(list(label2plot = c("yes", "no", "yes", "no",
"yes", "no", "yes", "no"), gruppe = c("group1", "group1",
"group2","group2", "group1", "group1", "group2", "group2"), 
cohort = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L), levels = c("20172018", "20192020"), class = "factor"), var_abs = c(4979L,
 3214L, 129L, 130L, 5476L, 3556L, 89L, 74L), var_rel = c(0.789565,
 0.8035, 0.871622, 0.8125, 0.793163, 0.805254, 0.839623,
 0.860465)), class = "data.frame", row.names = c(NA, -8L))

From this, I create bar charts. For each group, there is a separate chart that I place side by side.

var_label <- "blabla"
title <- "blublub"
subtitle <- "blablub"
val_label <- c("yes", "no")

packages2check <- c("ggplot2", "stringr")

for (package in packages2check) {
  if (!requireNamespace(package, quietly = TRUE)) {
    install.packages(package)
    library(package, character.only = TRUE)
  } else {
    library(package, character.only = TRUE)
  }
}

ggplot() +
  geom_bar (
    data = df,
    aes(
      x = factor(label2plot, levels = val_label),
      y = var_rel,
      group = cohort,
      fill = label2plot
    ),
    stat = "identity",
    position = position_dodge(),
    color = "white",
    linewidth = 0.5
  ) +
  scale_y_continuous(
    labels = scales::percent,
    limits = c(0, 1.15),
    breaks = seq(0, 1, 0.2)
  ) +
  theme_classic() +
  theme(
    legend.position = "none",
    plot.title = element_text(hjust = 0.5,
                              size = 14,
                              face = "bold"),
    plot.subtitle = element_text(hjust = 0.5),
    plot.caption = element_text(hjust = 0.5),
  ) +
  scale_fill_manual(values = c("yes" = "#AFCDE4", "no" = "#389DC3")) +
  geom_text(
    data = df,
    size = 3,
    position = position_dodge2(preserve = 'single', width = 0.9),
    hjust = 0.5,
    vjust = -0.5,
    color = "black",
    aes(
      x = factor(label2plot, levels = val_label),
      y = var_rel,
      label = paste0(sprintf("%.1f", var_rel * 100), "%", "\n(N=", var_abs, ")")
    )
  ) +
  labs(
    subtitle = paste(subtitle),
    title = str_wrap(title, 45),
    x = var_label,
    y =  "",
    fill = ""
  ) +
  facet_wrap( ~ gruppe)

In the individual charts, the results for "yes" and "no" at both time points are displayed. There will be more time points in the future. However, since there are only two time points now, the results for "yes" and "no" are represented with two bars of the same color.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I can insert the labels for the time points (or cohorts) into the bars vertically as I want. However, the label is only displayed in the left of each respective bar, not in the right bar as well.

It should look like the example chart. How do I do that?
It should look like this

>Solution :

Bottom line: you need position= to be the same as previous, and can place them using y = min(var_rel)/2.

I’ll shortcut a bit by bringing the factor(.) outside of ggplot2, define the x= and y= aesthetics in the main ggplot(.) call, and all geoms benefit from the simplification. One benefit of this is that by using factor, you are imposing specific order on the lebels. However, with mixed use of factors and non-factors (i.e., fill=label2plot) then how they are ordered in all portions of the plot may be inconsistent (e.g., a legend). Perhaps that doesn’t apply here (yet?), but it’s often a good practice to get into.

gg <- df |>
  transform(label2plot = factor(label2plot, levels = val_label)) |>
  ggplot(aes(x = label2plot, y = var_rel)) +
  geom_bar (
    aes(
      group = cohort,
      fill = label2plot
    ),
    stat = "identity",
    position = position_dodge(),
    color = "white",
    linewidth = 0.5
  ) +
  scale_y_continuous(
    labels = scales::percent,
    limits = c(0, 1.15),
    breaks = seq(0, 1, 0.2)
  ) +
  theme_classic() +
  theme(
    legend.position = "none",
    plot.title = element_text(hjust = 0.5,
                              size = 14,
                              face = "bold"),
    plot.subtitle = element_text(hjust = 0.5),
    plot.caption = element_text(hjust = 0.5),
  ) +
  scale_fill_manual(values = c("yes" = "#AFCDE4", "no" = "#389DC3")) +
  geom_text(
    size = 3,
    position = position_dodge2(preserve = 'single', width = 0.9),
    hjust = 0.5,
    vjust = -0.5,
    color = "black",
    aes(
      label = paste0(sprintf("%.1f", var_rel * 100), "%", "\n(N=", var_abs, ")")
    )
  ) +
  labs(
    subtitle = paste(subtitle),
    title = str_wrap(title, 45),
    x = var_label,
    y =  "",
    fill = ""
  ) +
  facet_wrap( ~ gruppe)

From here, we can simply do:

gg +
  geom_text(
    aes(y = min(var_rel)/2, label = cohort),
    angle = 90, position = position_dodge2(preserve = 'single', width = 0.9)
  )

enter image description here

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading