rggplot2scaleaxesmultiple-axes

ggplot: scale second axis with error bars


I am attempting to graph two scatter plots with associated error bars using ggplot2. I would like the top of left axis to be ~0 and range down to -2000 and for the bottom of the right axis to be 0 and range up to about 0.15.

I can re-scale the axes for the points themselves following the instructions here but I am having trouble generalizing the instructions to include error bars.

Here is my current plot

enter image description here

Here is my code

library(tidyverse)
library(ggplot2)

deciles <- data.frame(count = 1:10,
                  coef_maroon = c(0.005, 0.015, 0.015, 0.02, 0.03, 0.07, 0.09, 0.12, 0.12, 0.13),
                  ci_upper_maroon = c(0.008, 0.02, 0.025, 0.03, 0.04, 0.09, 0.11, 0.14, 0.13, 0.15),
                  ci_lower_maroon = c(0.001, 0.01, 0.005, 0, 0.01, 0.05, 0.07, 0.11, 0.11, 0.12),
                  coef_navy= c(0, -200, -400, -600, -800, -700, -900, -900, -1100, -1700),
                  ci_upper_navy = c(100, -100, -300, -500, -700, -600, -800, -700, -900, -1600),
                  ci_lower_navy = c(-100, -500, -700, -900, -850, -800, -950, -1000, -1200, -1900))

scl = with(deciles, max(abs(coef_navy))/max(abs(coef_maroon)))

ggplot(deciles) + 
  geom_point(aes(x = count, y = coef_navy, color = 'navy')) + 
  geom_point(aes(x = count, y = coef_maroon*scl-1200, color = 'maroon')) +
  geom_errorbar(aes(x = count, ymin = ci_lower_navy, ymax = ci_upper_navy, color = 'navy'), width = 0) +     
  geom_errorbar(aes(x = count, ymin = ci_lower_maroon*scl-1200, ymax = ci_upper_maroon*scl-1200, color = 'maroon', width = 0)) +   
  labs(x = "Group", y = "") +
  scale_color_manual(values = c('maroon', 'navy')) + 
  scale_y_continuous(sec.axis = sec_axis(~(.+1200)/scl, name = "2nd axis"))

My question is how can I scale my axes such that the downward trending plot (left axis) "starts" in the top left corner and the upward trending plot (right axis) starts in the bottom left?

As you can see, there is much dead space in the top of the left axis and the right axis need not range as low as -0.05 because the smallest maroon value is just above 0.

Thank you


Solution

  • Does adjusting the scaling factor (1200 to 1900) work for you?

    library(tidyverse)
    
    deciles <- data.frame(count = 1:10,
                          coef_maroon = c(0.005, 0.015, 0.015, 0.02, 0.03, 0.07, 0.09, 0.12, 0.12, 0.13),
                          ci_upper_maroon = c(0.008, 0.02, 0.025, 0.03, 0.04, 0.09, 0.11, 0.14, 0.13, 0.15),
                          ci_lower_maroon = c(0.001, 0.01, 0.005, 0, 0.01, 0.05, 0.07, 0.11, 0.11, 0.12),
                          coef_navy= c(0, -200, -400, -600, -800, -700, -900, -900, -1100, -1700),
                          ci_upper_navy = c(100, -100, -300, -500, -700, -600, -800, -700, -900, -1600),
                          ci_lower_navy = c(-100, -500, -700, -900, -850, -800, -950, -1000, -1200, -1900))
    
    scl = with(deciles, max(abs(coef_navy))/max(abs(coef_maroon)))
    
    ggplot(deciles) + 
      geom_point(aes(x = count, y = coef_navy, color = 'navy')) + 
      geom_point(aes(x = count, y = coef_maroon*scl-1900, color = 'maroon')) +
      geom_errorbar(aes(x = count, ymin = ci_lower_navy, ymax = ci_upper_navy, color = 'navy'), width = 0) +     
      geom_errorbar(aes(x = count, ymin = ci_lower_maroon*scl-1900, ymax = ci_upper_maroon*scl-1900, color = 'maroon', width = 0)) +   
      labs(x = "Group", y = "") +
      scale_color_manual(values = c('maroon', 'navy')) + 
      scale_y_continuous(sec.axis = sec_axis(~(.+1900)/scl, name = "2nd axis"))
    

    Created on 2021-09-02 by the reprex package (v2.0.1)

    Also, depending on how relevant the x-axis values are, you could consider nudging the values so they don't overlap, e.g.

    library(tidyverse)
    
    deciles <- data.frame(count = 1:10,
                          coef_maroon = c(0.005, 0.015, 0.015, 0.02, 0.03, 0.07, 0.09, 0.12, 0.12, 0.13),
                          ci_upper_maroon = c(0.008, 0.02, 0.025, 0.03, 0.04, 0.09, 0.11, 0.14, 0.13, 0.15),
                          ci_lower_maroon = c(0.001, 0.01, 0.005, 0, 0.01, 0.05, 0.07, 0.11, 0.11, 0.12),
                          coef_navy= c(0, -200, -400, -600, -800, -700, -900, -900, -1100, -1700),
                          ci_upper_navy = c(100, -100, -300, -500, -700, -600, -800, -700, -900, -1600),
                          ci_lower_navy = c(-100, -500, -700, -900, -850, -800, -950, -1000, -1200, -1900))
    
    scl = with(deciles, max(abs(coef_navy))/max(abs(coef_maroon)))
    
    ggplot(deciles) + 
      geom_point(aes(x = count, y = coef_navy, color = 'navy'),
                 position = position_nudge(x = -0.05)) + 
      geom_point(aes(x = count, y = coef_maroon*scl-1900, color = 'maroon'),
                 position = position_nudge(x = 0.05)) +
      geom_errorbar(aes(x = count, ymin = ci_lower_navy,
                        ymax = ci_upper_navy, color = 'navy', width = 0),
                    position = position_nudge(x = -0.05)) +     
      geom_errorbar(aes(x = count, ymin = ci_lower_maroon*scl-1900,
                        ymax = ci_upper_maroon*scl-1900,
                        color = 'maroon', width = 0),
                    position = position_nudge(x = 0.05)) +   
      labs(x = "Group", y = "") +
      scale_color_manual(values = c('maroon', 'navy')) + 
      scale_y_continuous(sec.axis = sec_axis(~(.+1900)/scl, name = "2nd axis"))
    

    Created on 2021-09-02 by the reprex package (v2.0.1)

    You can further trim the 'blank space' at the top if you adjust the expand() option in scale_y_continuous:

    library(tidyverse)
    
    deciles <- data.frame(count = 1:10,
                          coef_maroon = c(0.005, 0.015, 0.015, 0.02, 0.03, 0.07, 0.09, 0.12, 0.12, 0.13),
                          ci_upper_maroon = c(0.008, 0.02, 0.025, 0.03, 0.04, 0.09, 0.11, 0.14, 0.13, 0.15),
                          ci_lower_maroon = c(0.001, 0.01, 0.005, 0, 0.01, 0.05, 0.07, 0.11, 0.11, 0.12),
                          coef_navy= c(0, -200, -400, -600, -800, -700, -900, -900, -1100, -1700),
                          ci_upper_navy = c(100, -100, -300, -500, -700, -600, -800, -700, -900, -1600),
                          ci_lower_navy = c(-100, -500, -700, -900, -850, -800, -950, -1000, -1200, -1900))
    
    scl = with(deciles, max(abs(coef_navy))/max(abs(coef_maroon)))
    
    ggplot(deciles) + 
      geom_point(aes(x = count, y = coef_navy, color = 'navy'),
                 position = position_nudge(x = -0.05)) + 
      geom_point(aes(x = count, y = coef_maroon*scl-1900, color = 'maroon'),
                 position = position_nudge(x = 0.05)) +
      geom_errorbar(aes(x = count, ymin = ci_lower_navy,
                        ymax = ci_upper_navy, color = 'navy', width = 0),
                    position = position_nudge(x = -0.05)) +     
      geom_errorbar(aes(x = count, ymin = ci_lower_maroon*scl-1900,
                        ymax = ci_upper_maroon*scl-1900,
                        color = 'maroon', width = 0),
                    position = position_nudge(x = 0.05)) +   
      labs(x = "Group", y = "") +
      scale_color_manual(values = c('maroon', 'navy')) + 
      scale_y_continuous(sec.axis = sec_axis(~(.+1900)/scl, name = "2nd axis"),
                         expand = c(0.01,0.01))
    

    Created on 2021-09-02 by the reprex package (v2.0.1)