Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

error bars in x and y (feature request) #3213

Closed
courtiol opened this issue Mar 28, 2019 · 5 comments
Closed

error bars in x and y (feature request) #3213

courtiol opened this issue Mar 28, 2019 · 5 comments
Labels
feature a feature request or enhancement layers 📈

Comments

@courtiol
Copy link

Dear all,

Following a discussion at community.rstudio with @eipi10 and @tp2750, I hereby file a feature request to help creating a double error bar (i.e. in x and y).

The idea could be to provide a new geom_* or stat_* that directly provide error bars in x and y, as it seems otherwise surprisingly tedious to code (unless one uses ggstance). The situation can be useful when users call geom_point on a dataset that has groups inside it (e.g. species in iris).

Here is a slightly modified version of @eipi10's code (using ggstance) which illustrates the point when error bars represent 95%CI:

library(ggplot2)
library(rlang)
library(dplyr)

fnc <- function(data, group, x, y, adj = 1) {
  
  group <- enquo(group)
  x <- enquo(x)
  y <- enquo(y)
  
  # Set size of whisker end caps
  w_vertical   <- data %>% pull(!!y) %>% range %>% diff/100*adj
  w_horizontal <- data %>% pull(!!x) %>% range %>% diff/100*adj
  
  # If grouping variable is numeric, turn it into a factor
  if(data %>% pull(!!group) %>% is.numeric) {
    data <- data %>% mutate(!!quo_name(group) := factor(!!group))
  } 
  
  # Generate column names for the x and y means that we'll calculate below
  x_mean <- paste0(quo_text(x), "_mean")
  y_mean <- paste0(quo_text(y), "_mean")
  
  left_join(data, 
            data %>%
              group_by(!!group) %>%
              summarise_at(vars(!!x, !!y), funs(mean = mean))
  ) %>% 
    ggplot(aes(colour = !!group)) +
    geom_point(aes(x = !!x, y = !!y), shape = 1) +
    geom_point(aes(x = !!sym(x_mean), y = !!sym(y_mean)), shape = 18, size = 3) +
    stat_summary(fun.data = mean_se, fun.args = list(mult = 1.96),
                 aes(x = !!sym(x_mean), y = !!y),
                 geom = "errorbar", width = w_horizontal) +
    ggstance::stat_summaryh(fun.data = ggstance::mean_se_h, fun.args = list(mult = 1.96),
                  aes(x = !!x, y = !!sym(y_mean)),
                  geom="errorbarh", width = w_vertical) +
    theme_bw()
}

fnc(iris, Species, Petal.Length, Sepal.Length)
![image](https://user-images.githubusercontent.com/7499666/55148649-e69c2a00-5148-11e9-8b6a-c34dbe4e80af.png)

fnc(iris, Species, Petal.Length, Sepal.Length) + facet_wrap(~ Species)
![image](https://user-images.githubusercontent.com/7499666/55148693-fca9ea80-5148-11e9-86d9-8621fef70135.png)

(not sure the figure will display, but it is easy to run)

Perhaps it could also be a feature request for ggstance instead... but I post this here only for now.

@courtiol courtiol changed the title geom bars in x and y (feature request) error bars in x and y (feature request) Mar 28, 2019
@ptoche
Copy link

ptoche commented Mar 28, 2019

reprex below for reference:

library(reprex)
library(ggplot2)
library(rlang)
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

fnc <- function(data, group, x, y, adj = 1) {
    
    group <- enquo(group)
    x <- enquo(x)
    y <- enquo(y)
    
    # Set size of whisker end caps
    w_vertical   <- data %>% pull(!!y) %>% range %>% diff/100*adj
    w_horizontal <- data %>% pull(!!x) %>% range %>% diff/100*adj
    
    # If grouping variable is numeric, turn it into a factor
    if(data %>% pull(!!group) %>% is.numeric) {
        data <- data %>% mutate(!!quo_name(group) := factor(!!group))
    } 
    
    # Generate column names for the x and y means that we'll calculate below
    x_mean <- paste0(quo_text(x), "_mean")
    y_mean <- paste0(quo_text(y), "_mean")
    
    left_join(data, 
              data %>%
                  group_by(!!group) %>%
                  summarise_at(vars(!!x, !!y), funs(mean = mean))
    ) %>% 
        ggplot(aes(colour = !!group)) +
        geom_point(aes(x = !!x, y = !!y), shape = 1) +
        geom_point(aes(x = !!sym(x_mean), y = !!sym(y_mean)), shape = 18, size = 3) +
        stat_summary(fun.data = mean_se, fun.args = list(mult = 1.96),
                     aes(x = !!sym(x_mean), y = !!y),
                     geom = "errorbar", width = w_horizontal) +
        ggstance::stat_summaryh(fun.data = ggstance::mean_se_h, fun.args = list(mult = 1.96),
                                aes(x = !!x, y = !!sym(y_mean)),
                                geom="errorbarh", width = w_vertical) +
        theme_bw()
}

fnc(iris, Species, Petal.Length, Sepal.Length)
#> Warning: funs() is soft deprecated as of dplyr 0.8.0
#> please use list() instead
#> 
#> # Before:
#> funs(name = f(.)
#> 
#> # After: 
#> list(name = ~f(.))
#> This warning is displayed once per session.
#> Joining, by = "Species"

fnc(iris, Species, Petal.Length, Sepal.Length) + facet_wrap(~ Species)
#> Joining, by = "Species"

Created on 2019-03-28 by the reprex package (v0.2.1)

@courtiol
Copy link
Author

Thanks @ptoche... I should have done that.

@thomasp85 thomasp85 added the feature a feature request or enhancement label Apr 11, 2019
@hadley
Copy link
Member

hadley commented Jun 18, 2019

I think this would be most natural in an extension package (maybe in ggstance?); otherwise I think we'd need to make bidirectional versions of geom_crossbar(), geom_errorbar(), geom_linerange() and geom_pointrange().

@hadley hadley closed this as completed Jun 18, 2019
@courtiol
Copy link
Author

For reference: @tp2750 has recently coded the discussed feature in a separate 📦 : ggerr

@lock
Copy link

lock bot commented Apr 18, 2020

This old issue has been automatically locked. If you believe you have found a related problem, please file a new issue (with reprex) and link to this issue. https://reprex.tidyverse.org/

@lock lock bot locked and limited conversation to collaborators Apr 18, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
feature a feature request or enhancement layers 📈
Projects
None yet
Development

No branches or pull requests

5 participants