0

I don't have a solution for my problem. I want to present three different median lines from a dataset which works without a problem. Now I would like to add a ribbon for the IQR or errorbars which would require calculation of upper and lower borders. This does not work.

Those are my variables

otherside_surgery_yesno - three groups here Jahre - those are the years I want to show on the x-axis po_constant_impaired_score_a - this is the value I would like to show on y-axis

The code below works nicely but I can't find any simple solution adding IQR as ribbon or errorbars.

both_sides %>% 
  ggplot() +
  # RTSA
  stat_summary(data = both_sides %>% filter(is.na(otherside_surgery_yesno)),
                 aes(x = Jahre, 
                   y = po_constant_impaired_score_a),
              fun = median, 
              geom = "line",
              color = "red") +
  # Healthy without surgery
  stat_summary(data = both_sides %>% filter(otherside_surgery_yesno == "0"),
                 aes(x = Jahre, 
                   y = po_constant_impaired_score_a),
              fun = median, 
              geom = "line",
              color = "darkgreen") +
  stat_summary(data = both_sides %>% filter(!is.na(otherside_surgery_yesno)),
                 aes(x = Jahre, 
                   y = po_constant_impaired_score_a),
              fun = median, 
              geom = "line",
              color = "blue") +
  theme_classic() +
  ylab("Constant Score absolute") +
  xlab("Time (years)")
calculate_lower <- function(data) {
  return(quantile(data, 0.25))
}

calculate_upper <- function(data) {
  return(quantile(data, 0.75))
}

geom_errorbar(
  aes(ymin = calculate_lower(data), ymax = calculate_upper(data)),
  width = 0.2
)

Philipp
  • 9
  • 3
  • Please use `dput` to provide a minimal subset of your input data: https://stackoverflow.com/help/minimal-reproducible-example ; that said, `geom_quantile` might be helpful: https://ggplot2.tidyverse.org/reference/geom_quantile.html – I_O Jul 09 '23 at 10:47

2 Answers2

1

you could use geom_quantile like so:

library(ggplot2)

iris |>
  ggplot(aes(Sepal.Length, Petal.Length)) +
  geom_point() +
  geom_quantile(quantiles = .25 * 1:3)

geom_quantile

I_O
  • 4,983
  • 2
  • 2
  • 15
1

If you want a ribbon rather than lines with stat_quantile, you will need to use geom = "ribbon" and, inside aes, you can calculate the ymax and ymin of the ribbon using after_stat(y) and after_stat(quantile).

Here's an example which additionally labels the quantiles using geomtextpath and includes some opinionated styling.

library(ggplot2)
library(geomtextpath)

iris |>
  ggplot(aes(Sepal.Length, Petal.Length)) +
  stat_quantile(quantiles = c(0.25, 0.5, 0.75), geom = 'ribbon',
                fill = 'steelblue', alpha = 0.05,
                aes(ymin = after_stat(y)[after_stat(quantile) == 0.25],
                    ymax = after_stat(y)[after_stat(quantile) == 0.75])) +
  stat_quantile(geom = 'textpath', quantiles = 0.5, color = 'steelblue4',
                aes(label = 'Median'), hjust = 0.25, linetype = 2,
                size = 6) +
  stat_quantile(quantiles = 0.25, geom = 'textpath', color = 'steelblue4',
                aes(label = 'Lower IQR'), hjust = 0.45, text_only = TRUE,
                vjust = 1.2, size = 5) +
  stat_quantile(quantiles = 0.75, geom = 'textpath', color = 'steelblue4',
                aes(label = 'Upper IQR'), hjust = 0, vjust = -0.2, 
                text_only = TRUE, size = 5) +
  stat_quantile(quantiles = c(0, 0.25, 0.75, 1), color = 'steelblue4', 
                alpha = 0.2) +
  geom_point(alpha = 0.5, color = 'steelblue4') +
  coord_cartesian(ylim = c(0, 8)) +
  labs(x = 'Sepal Length', y = 'Petal Length', title = 'Quantiles') +
  theme_minimal(base_size = 16) +
  theme(text = element_text(color = '#406080', face = 2),
        axis.text = element_text(color = '#507080', face = 2),
        plot.background = element_rect(color = NA, fill = '#F8F9FA'),
        plot.title = element_text(hjust = 0.5),
        plot.title.position = 'plot')

enter image description here

Allan Cameron
  • 147,086
  • 7
  • 49
  • 87