As @joran noted, the grid graphical system offers more flexible control over the location of multiple graphs on a single device.
Here I first use grconvertY() to query the location of a height of 50 along the y axis in units of "normalized device coordinates". (i.e., as a percentage of the total height of the plotter, with 0 = bottom and 1 = top). Then I use the grid functions to: (1) click the viewport that populates the device; and (2) draw a line at the height returned by grconvertY() .
#

EDIT : @joran asked how to build a line that extends from the Y axis of the 1st section to the edge of the last strip in the 3rd section. Here are a few alternatives:
library(grid) library(gridBase) par(mfrow=c(1,3)) # barplot #1 barplot(VADeaths, border = "dark blue") X1 <- grconvertX(0, "user", "ndc") # barplot #2 barplot(VADeaths, border = "yellow") # barplot #3 m <- barplot(VADeaths, border = "green") X2 <- grconvertX(tail(m, 1) + 0.5, "user", "ndc") # default width of bars = 1 Y <- grconvertY(50, "user", "ndc") ## Horizontal line pushViewport(viewport()) grid.lines(x = c(X1, X2), y = Y, gp = gpar(col = "red")) popViewport()

Finally, here is an almost equivalent and more accessible approach. It uses the functions grid.move.to() and grid.line.to() demo'd by Paul Murrell in an article related to @mdsumner's answer:
library(grid) library(gridBase) par(mfrow=c(1,3)) barplot(VADeaths); vps1 <- do.call(vpStack, baseViewports()) barplot(VADeaths) barplot(VADeaths); vps3 <- do.call(vpStack, baseViewports()) pushViewport(vps1) Y <- convertY(unit(50,"native"), "npc") popViewport(3) grid.move.to(x = unit(0, "npc"), y = Y, vp = vps1) grid.line.to(x = unit(1, "npc"), y = Y, vp = vps3, gp = gpar(col = "red"))