The "trick" (and often nightmares of inverting algebraic equations in high school) is knowing how to change the trans
forms for sec_axis
, and knowing that you need to change the raw data itself.
I'm going to assume your data is in a "wide" format, looking somewhat like this:
set.seed(42)
dat <- data.frame(precip = runif(50, 0, 1.5)) |>
transform(
time = 1:50,
precip = ifelse(runif(50) < 0.8, 0, precip),
sensor = sample(c("inside", "outside"), 50, replace = TRUE)
) |>
transform(depth = 3.6 + cumsum(precip) - time/10)
head(dat)
# precip time sensor depth
# 1 0 1 outside 3.5
# 2 0 2 outside 3.4
# 3 0 3 inside 3.3
# 4 0 4 outside 3.2
# 5 0 5 inside 3.1
# 6 0 6 outside 3.0
From here, we need to know how to algebraically convert depth
to the correct location and scale of the precip
data.
The conversion is a "simple" scaling, meaning we need to adjust it to be completely within [0,1]
and then adjust to the new scale. Using some prep objects,
rngdepth <- range(dat$depth)
diffdepth <- diff(rngdepth)
maxprecip <- max(dat$precip)
diffprecip <- diff(range(dat$precip))
We now have a simple relationship and the inversion. The two formulas we're interested in are the first and last:
y = maxprecip - diffprecip * (depth - rngdepth[1]) / diffdepth
maxprecip - y = diffprecip * (depth - rngdepth[1]) / diffdepth
diffdepth * (maxprecip - y) = diffprecip * (depth - rngdepth[1])
diffdepth * (maxprecip - y) / diffprecip = depth - rngdepth[1]
diffdepth * (maxprecip - y) / diffprecip + rngdepth[1] = depth
I prefer to use ~
-function transforms in the data, so that the original frame is not encumbered (confusingly, sometimes) with the variables. Here's the plotting code:
ggplot(dat, aes(x = time)) +
geom_col(aes(y = precip)) +
geom_line(
aes(x = time, y = depth2, color = sensor, group = sensor),
data = ~ transform(., depth2 = maxprecip - diffprecip * (depth - rngdepth[1]) / diffdepth)
) +
scale_y_reverse(
name = "Precipitation",
sec.axis = sec_axis(
~ diffdepth * (maxprecip - .) / diffprecip + rngdepth[1],
name = "Depth"
)
)
