Search code examples
rggplot2limitaxisfacet-grid

programmatically setting individual axis limits in facets


I need help on setting the individual x-axis limits on different facets as described below.

A programmatical approach is preferred since I will apply the same template to different data sets.

  • first two facets will have the same x-axis limits (to have comparable bars)
  • the last facet's (performance) limits will be between 0 and 1, since it is calculated as a percentage

I have seen this and some other related questions but couldn't apply it to my data.

Thanks in advance.

df <- 
  data.frame(
    call_reason = c("a","b","c","d"),
    all_records = c(100,200,300,400),
    problematic_records = c(80,60,100,80))
df <- df %>% mutate(performance = round(problematic_records/all_records, 2))


df
    call_reason all_records problematic_records performance
               a         100                  80        0.80
               b         200                  60        0.30
               c         300                 100        0.33
               d         400                  80        0.20

df %>% 
  gather(key = facet_group, value = value, -call_reason)  %>% 
  mutate(facet_group = factor(facet_group,
  levels=c('all_records','problematic_records','performance'))) %>% 
  ggplot(aes(x=call_reason, y=value)) +
  geom_bar(stat="identity") + 
  coord_flip() +
  facet_grid(. ~ facet_group)

enter image description here


Solution

  • So here is one way to go about it with facet_grid(scales = "free_x"), in combination with a geom_blank(). Consider df to be your df at the moment before piping it into ggplot.

    ggplot(df, aes(x=call_reason, y=value)) +
      # geom_col is equivalent to geom_bar(stat = "identity")
      geom_col() +
      # geom_blank includes data for position scale training, but is not rendered
      geom_blank(data = data.frame(
        # value for first two facets is max, last facet is 1
        value = c(rep(max(df$value), 2), 1),
        # dummy category
        call_reason = levels(df$call_reason)[1],
        # distribute over facets
        facet_group = levels(df$facet_group)
        )) +
      coord_flip() +
      # scales are set to "free_x" to have them vary independently
      # it doesn't really, since we've set a geom_blank
      facet_grid(. ~ facet_group, scales = "free_x")
    

    enter image description here

    As long as your column names remain te same, this should work.

    EDIT:

    To reorder the call_reason variable, you could add the following in your pipe that goes into ggplot:

    df %>% 
      gather(key = facet_group, value = value, -call_reason)  %>% 
      mutate(facet_group = factor(facet_group,
                                  levels=c('all_records','problematic_records','performance')),
             # In particular the following bit:
             call_reason = factor(call_reason, levels(call_reason)[order(value[facet_group == "performance"])]))