1

I have adjusted the secondary axis to the units adding a coefficient /100. However, the datapoint (B) are not being plotted according to the secondary axis and remain small.

data<- data.frame(
      Days=(1:10),
      A=c(34,1,22,1,3,0,2,5,0,8),
      B= c(0.2,0.2,0.2,0.2,0.3,0.3,0.2,0.1,0.1,0.3))


coeff2<- 100
ggplot(data) + 
  geom_line(aes(Days, A, color = "A"), fill = "grey") +
  geom_point(aes(Days, A))+
  geom_line(aes(Days, B, color = "B"), size = 0.6) +
  geom_point(aes(Days, B))+
  theme_classic() + 
  scale_y_continuous(name = "A",
    sec.axis = sec_axis(~./coeff2, name="B"))+
  scale_color_manual(name = "", values = c("A" = "darkgrey", "B" = "black"))

enter image description here

Ecg
  • 908
  • 1
  • 10
  • 28

2 Answers2

2

The way I usually do this is by making a pair of maps that go from B to A and A to B. To do this, if you wanted both axes to start at zero, you would first make a dataset with only two observations where the first was the minimum value for each variable and the second was the maximum. If you want both axes to start at zero, you should use zero for the minimum value, otherwise you could use the observed minimum in the data. For example,

tmp <- data.frame(
  A = c(0, max(data$A)), 
  B = c(0, max(data$B))
)

Next, estimate two linear models where we calculate the coefficients to transform from one variable's space into the other. Then we can make functions that will calculate the transformation.

itmod <- lm(A ~ B, data=tmp)
tmod <- lm(B ~ A, data=tmp)
trans <- function(x)coef(tmod)[1] + coef(tmod)[2]*x
invtrans <- function(x)coef(itmod)[1] + coef(itmod)[2]*x

Then, we use those functions in the ggplot:

ggplot(data) + 
  geom_line(aes(Days, A, color = "A")) +
  geom_point(aes(Days, A))+
  geom_line(aes(Days, invtrans(B), color = "B"), size = 0.6) +
  geom_point(aes(Days, invtrans(B)))+
  theme_classic() + 
  scale_y_continuous(name = "A",
                     sec.axis = sec_axis(trans=trans, name="B"))+
  scale_color_manual(name = "", values = c("A" = "darkgrey", "B" = "black"))

enter image description here

Also note, in your original code, the first call to geom_line() had fill="grey", but you could actually remove that because you're defining colours with the scale_colour_manual() function. Also discussed in this answer relating to grouped bar plots and this answer relating to grouped box plots.

DaveArmstrong
  • 18,377
  • 2
  • 13
  • 25
2

ggplot2 doesn't easily work with a second y-axis. sec_axis() basically just glues another scale onto your graph, your geom_line(aes(Days, B, color = "B"), size = 0.6) + geom_point(aes(Days, B)) does not 'interact' with it. DaveArmstrong's solution will probably work the best in all cases where you want to use two graphs that have different scales. In this case you have a coefficient /100 that only applies to your second scale. adding that coefficient to your graph should work in this case because the B graph is still plotted with the primary y-axis:

ggplot(data) + 
  geom_line(aes(Days, A, color = "A"), fill = "grey") +
  geom_point(aes(Days, A))+
  geom_line(aes(Days, B*coeff2, color = "B"), size = 0.6) +
  geom_point(aes(Days, B*coeff2))+
  theme_classic() + 
  scale_y_continuous(name = "A",
    sec.axis = sec_axis(~./coeff2, name="B"))+
  scale_color_manual(name = "", values = c("A" = "darkgrey", "B" = "black"))

But note that with bigger/more complex graphs this solution will not work well or not work at all.

Omniswitcher
  • 368
  • 3
  • 13
  • Thanks for your explanation! I actually was wondering how the plot "knows" which scale to use. Turn out it seems like it doesn't know. Your solution at least works for me now. – Ying Jun 14 '22 at 18:18