2

I have 20 sets of the following dataset and would like to combine two plots into one with two y-axes that properly reflects the variable values.

hour=c(0:23)
conc=c(20.7, 19.4, 15.6, 11.7, 10.3, 9.1, 9.7, 10.6, 12.7, 12.6, 11, 9.8,
       9.3, 9.3, 10.3, 12.9, 17.1, 22.5, 22, 22.3, 23, 24.8, 24, 26.8)
ws=c(0.75, 0.7, 0.68, 0.64, 0.61, 0.64, 0.57, 0.58, .62, .65, .85, 1.12, 
     1.21, 1.29, 1.2, 1.18, 1.0, 0.84, .87, .75, .69, .69, .77, .74)
wd=c(295, 299, 288, 290, 292, 296, 306, 303, 300, 293, 259, 231, 94, 119, 
     95, 47, 75, 306, 302, 304, 319, 309, 290, 298)
mydf=data.frame(hour, conc, ws, wd)

I can plot them separately as a 1-by-2 graph using the following code:

conchrly <- ggplot(mydf, aes(x=hour,y=conc)) +
  geom_line() + 
  xlab("Hour") +
  ylab("Concentration") +
  theme(legend.position="bottom")     

windhrly <- ggplot(data = mydf, aes(x=hour, y=ws)) + 
  geom_text(aes(angle=-wd+90), label="←") +
  xlab("Hour") +
  ylab("Wind Speed") +
  theme(legend.position="bottom") 

conchrly + windhrly + plot_layout(ncol=1)

which gives this graph:

Two separate plots using plot_layout

I'd like to combine them together as one graph with two y-axes. Most examples I found here are related to the second-axis as a duplicate or function of first y-values. My second y-variable is 'ws' which is not a function on my first y variable (ie. 'conc').

The following is my attempt to graph them together. However the y-value of second plot (geom_text which should represent my ws) are not plotted using the second y-axis.

ggplot(data=mydf, aes(x = hour, y = conc)) + 
  geom_line(color = "black") + 
  geom_text(data=mydf, aes(x=hour, y=ws,angle=-wd+90), label="←", colour = "blue") +
  scale_x_continuous(breaks = seq(0, 24, by=6), limits=c(0,24), name="Hour") + 
  scale_y_continuous( breaks = seq(0,30,10), name= "Concentration", 
     sec.axis = sec_axis(~./20, name = "Wind Speed (m/s)")) + 
              theme(axis.title.y = element_text(color = "black"),
                    axis.title.y.right = element_text(color = "black"))

Combined graph with two y-axes

How do I get those blue arrows which represent my 'ws' to be on the right scale (ie. using the second y-axis)? This is only one set and I have 19 others to do that's why I prefer to combine them into one graph per data set if possible.

Thanks in advance! :)

Z.Lin
  • 28,055
  • 6
  • 54
  • 94
num8ers
  • 63
  • 8
  • This is not easily done, because these sort of dual axes are not really supported by `ggplot1`. This is because it's authors think these plots are misleading. – Axeman Dec 11 '18 at 01:33
  • There are some answers using base R and some other plotting packages [here](https://stackoverflow.com/questions/6142944/how-can-i-plot-with-2-different-y-axes) – bob1 Dec 11 '18 at 02:23

1 Answers1

5

We can achieve what you're after if we scale values of ws such that they use the same range as conc, and then apply the inverse transformation inside sec_axis. The transformation that we are applying takes the form y = a + b * x, where y are the conc and x the ws measurements. The two scaling coefficients a and b are then obtained by solving a system of two linear equations:

# Calculate scaling coefficients a and b
y1 <- min(mydf$conc)
y2 <- max(mydf$conc)
x1 <- min(mydf$ws)
x2 <- max(mydf$ws)
b <- (y2 - y1) / (x2 - x1)
a <- y1 - b * x1

We then calculate ws.scaled and apply the inverse transformation x = (y - a) / b inside sec_axis.

library(tidyverse)
mydf %>%
    mutate(ws.scaled = a + b * ws) %>%
    ggplot(aes(x = hour, y = conc)) +
        geom_line(color = "black") +
        geom_text(aes(x = hour, y = ws.scaled, angle = -wd + 90), label = "←", colour = "blue") +
        scale_x_continuous(breaks = seq(0, 24, by=6), limits=c(0,24), name="Hour") +
        scale_y_continuous(
            breaks = seq(0,30,10),
            name=  "Concentration",
            sec.axis = sec_axis(~ (. - a) / b, name = "Wind Speed (m/s)")) +
            theme(
                axis.title.y = element_text(color = "black"),
                axis.title.y.right = element_text(color = "black"))

enter image description here

PS. Dual y axes are often not a good idea. Personally I prefer showing two plots.

Maurits Evers
  • 49,617
  • 4
  • 47
  • 68
  • This is awesome. Thanks Maurits! – num8ers Dec 12 '18 at 02:15
  • @num8ers PS. If this answers your question please consider closing the question by setting the green check mark next to the answer. That way you help keeping SO tidy and make it easier for others to identify relevant answers. Thanks and great first question btw. – Maurits Evers Dec 13 '18 at 00:39
  • Ok will do. Thanks – num8ers Dec 13 '18 at 06:29