2

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

JRR
  • 578
  • 5
  • 21

1 Answers1

2

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)

jared_mamrot
  • 22,354
  • 4
  • 21
  • 46
  • This is all a great help! Thank you. I definitely think the 1800-2000 range is going to be the right way to go. I guess with the "real" data I'm working with the maroon line is flatter so I was hoping to adjust the scaling rather than shifting the line but this definitely satisfies the question given the provided example. – JRR Sep 02 '21 at 04:54