Skip to content
Prev 374734 / 398513 Next

[FORGED] Re: draw borders of bars inside of the rectangles in a barplot

Hi

In addition to Richard's suggestion to add borders to the "only filled" 
bars, you could add "mitred" corners, like this ...


par(ljoin="mitre")
barplot(x, beside=T, border=rep(c('black', 'black'),5),
         space=c(0.08,1), col=rep(c('black', 'white'),5))


It may be overkill, but if the "bleeding" below y=0 is still a bother, 
here's one way you could then clip the bar bottoms ...


par(lwd=5, ljoin="mitre")
barplot(x, beside=T, border=rep(c('black', 'black'),5),
         space=c(0.08,1), col=rep(c('black', 'white'),5))
## Convert to 'grid'
library(gridGraphics)
grid.echo()
## Which grob is the bars?
barpath <- grid.grep("rect", grep=TRUE, viewports=TRUE)
## Which viewport are the bars drawn within?
barvp <- attr(barpath, "vp")
## Get copy of the bars
bars <- grid.get(barpath)
## Remove the bars
grid.remove(barpath)
## Go to the bars viewport
downViewport(barvp)
## Set up a clipping rect
grid.clip(y=unit(0, "native"),
           height=unit(11, "native"),
           just="bottom",
           name="clip")
## Draw the bars again (now clipped)
grid.draw(bars)


You could take it even further and clip each individual bar (so the 
border is only visible "inside" the bar) ...


par(lwd=5, ljoin="mitre")
barplot(x, beside=T, border=rep(c('black', 'black'),5),
         space=c(0.08,1), col=rep(c('black', 'white'),5))
library(gridGraphics)
grid.echo()
barpath <- grid.grep("rect", grep=TRUE, viewports=TRUE)
barvp <- attr(barpath, "vp")
bars <- grid.get(barpath)
grid.remove(barpath)
downViewport(barvp)
## Filled bars
for (i in 1:5) {
     odd <- i*2 - 1
     grid.rect(bars$x[odd], bars$y[1], bars$width[odd], bars$height[odd],
               just=c("left", "bottom"), gp=gpar(fill="black"))
}
## Border bars (clipped)
for (i in 1:5) {
     even <- i*2
     grid.clip(bars$x[even], bars$y[1],
               bars$width[even], bars$height[even],
               just=c("left", "bottom"))
     grid.rect(bars$x[even], bars$y[2],
               bars$width[even], bars$height[even],
               just=c("left", "bottom"), gp=gpar(lwd=5))
}


And, since you mentioned Photoshop/Inkscape, another option to draw 
borders only "inside" the bars is a "variable-width line" from the 
'vwline' package ...


par(lwd=5, ljoin="mitre")
barplot(x, beside=T, border=rep(c('black', 'black'),5),
         space=c(0.08,1), col=rep(c('black', 'white'),5))
library(gridGraphics)
grid.echo()
barpath <- grid.grep("rect", grep=TRUE, viewports=TRUE)
barvp <- attr(barpath, "vp")
bars <- grid.get(barpath)
grid.remove(barpath)
downViewport(barvp)
## Filled bars
for (i in 1:5) {
     odd <- i*2 - 1
     grid.rect(bars$x[odd], bars$y[1], bars$width[odd], bars$height[odd],
               just=c("left", "bottom"), gp=gpar(fill="black"))
}
## Draw vwline with width only "inside"
library(vwline)
for (i in 1:5) {
     even <- i*2
     left <- bars$x[even]
     right <- bars$x[even] +
         convertUnit(bars$width[even], "in",
                     "x", "dimension", "x", "location")
     bottom <- bars$y[2]
     top <- bars$y[2] +
         convertUnit(bars$height[even], "in",
                     "y", "dimension", "y", "location")
     grid.vwline(unit.c(left, left, right, right),
                 unit.c(bottom, top, top, bottom),
                 w=widthSpec(list(left=rep(0, 4),
                                  right=unit(rep(1, 4), "mm"))),
                 open=FALSE)
}


Paul
On 22/05/18 04:05, Richard M. Heiberger wrote: