3

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?

Cath
  • 23,906
  • 5
  • 52
  • 86
Suti
  • 33
  • 4
  • Sorry, seems that I made something wrong with the picture and lost the "Hello" at the beginning :) – Suti Nov 07 '16 at 13:22
  • 1
    This [SO post](http://stackoverflow.com/questions/18634431/r-in-barplot-midpoints-are-not-centered-w-r-t-bars) may point you in the right direction. – emilliman5 Nov 07 '16 at 14:01
  • Thank you for that interesting link. I tried to safe the boxplot as an object and use the values for the line/point plot. That seems to work. But how can I keep my date or date/time format x axis? – Suti Nov 07 '16 at 18:55
  • check out this [SO post](http://stackoverflow.com/questions/5182238/r-replace-x-axis-with-own-values) on how to relabel your x axis as needed – emilliman5 Nov 07 '16 at 20:24
  • That's really tricky. I tried it noe with my own data and the following edited code: bg <- barplot(...) [...] points(bg, df$counts, pch = 19, cex = 1.5) Now the points are shifted again. Maybe this does not work for double y axis? – Suti Nov 07 '16 at 21:27

2 Answers2

2

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

Keren Raiter
  • 27
  • 1
  • 6
emilliman5
  • 5,816
  • 3
  • 27
  • 37
0

@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.stack.imgur.com/29qTS.png)

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

Suti
  • 33
  • 4