Suti
Suti

Reputation: 45

R - Plot with two y axis, bars and points not aligned

For a customer I'm trying to do a combined barplot and lineplot (with points) with two y axis. Problem: My bars and points are not aligned.

Background: We have several machines and are measuring their number of on/of switches and the amount of time that each machine is running. We want both information together in one plot to save space, because we have several machines.

The data is aggregated by day or hour. Here's some sample data:

date <- seq(as.Date("2016-10-01"), as.Date("2016-10-10"), "day")
counts <- c(390, 377, 444, NA, NA, NA, NA, 162, 166, 145)
runtime <- c(56.8, 59.4, 51.0, NA, NA, NA, NA, 38.5, 40.9, 43.4)
df <- data.frame(date = date, counts = counts, runtime = runtime)

Here's what I tried so far:

par(mar = c(3,4,4,4) + 0.3)    
barplot(df$runtime, col = "palegreen2", border = "NA", ylab = "runtime in [%]", 
    ylim = c(0,100), font.lab = 2)
par(new = TRUE)
ymax <- max(df$counts, na.rm = TRUE) * 1.05
plot(df$date, df$counts, type = "n", xlab = "", ylab = "", yaxt = "n", 
    main = "Machine 1", ylim = c(0, ymax))
abline(v = date, col = "red", lwd = 2.5)
lines(df$date, df$counts, col = "blue", lwd = 2)
points(df$date, df$counts, pch = 19, cex = 1.5)
axis(4)
mtext("Number of switching operations", side = 4, line = 3, font = 2)

enter image description here

I found some inspiration for two axis here: http://robjhyndman.com/hyndsight/r-graph-with-two-y-axes/

What can I do to get bars with their middle aligned with the points of the lineplot?

Upvotes: 3

Views: 2364

Answers (2)

emilliman5
emilliman5

Reputation: 5956

The problem you are running into is the call to the second plot function after the barplot. This is shifting/resizing the plotting canvas which is causing the shift in the subsequent points.

Here is a quick work-around that just rescales the points and lines onto the barplot. It saves the barplot as an object, which stores x-axis locations for the mid-points of the bars. Then, when you plot the abline, lines and points using 'bp' as the x-axis variable, they will be correctly aligned.

ymax <- max(df$counts, na.rm = TRUE) * 1.05

par(mar=c(4.1,5.1,2.1,5.1))
bp <- barplot(df$runtime, col = "palegreen2", border = "NA", ylab = "runtime in [%]", 
              ylim = c(0,100), font.lab = 2, xlim=c(0.2,12), )

barplot(df$runtime, col = "palegreen2", ylab = "runtime in [%]", border="NA",
    ylim = c(0,100), font.lab = 2)

abline(v = bp, col = "red", lwd = 2.5)
lines(bp, df$counts/ymax*100, col = "blue", lwd = 2)
points(bp, df$counts/ymax*100, pch = 19, cex = 1.5)
axis(4,at=c(0,20,40,60,80,100), labels=c("0","100","200","300","400","500"))
mtext("Number of switching operations", side = 4, line = 3, font = 2)
axis(1, at=bp, labels=df$date)

enter image description here

Upvotes: 2

Suti
Suti

Reputation: 45

@emilliman: Thank you for your patience and input! Your plot is not completely correct, because the scaling of the second y-axis does not fit the points' values, but your idea helped me to find a solution!

Here's my new code:

library(plyr)
ymax <- max(df$counts, na.rm = TRUE)
ymax_up <- round_any(ymax, 100, f = ceiling)
ylab <- ymax_up/5 * c(0:5)

par(mar = c(3,4,4,4) + 0.3)
bp <- barplot(df$runtime, col = "palegreen2", border = "NA", ylab = "runtime in [%]", 
    ylim = c(0,100), font.lab = 2, main = "Machine 1")
abline(v = bp, col = "red", lwd = 2.5)
lines(bp, 100/ymax_up * df$counts, col = "blue", lwd = 2)
points(bp, 100/ymax_up * df$counts, pch = 19, cex = 1.5)

axis(4,at=c(0,20,40,60,80,100), labels= as.character(ylab))
mtext("Number of switching operations", side = 4, line = 3, font = 2)
xlab <- as.character(df$date, format = "%b %d")
axis(1, at=bp, labels = xlab)
abline(h = c(0,100))

(https://i.sstatic.net/29qTS.png)

Maybe this is helpful for others who run into this problem.

Upvotes: 0

Related Questions