rplotgraphbar-chartpar

Adjust size/width of barplot plots when using mfrow


I want to produce two figures using base R, both showing barplots. The first figure should contain two bar plots and the second figure should contain four bar plots.

I used par(mfrow = c(...)) to arrange multiple bar plots in one figure. I don't have trouble to produce the figures themselves, but when I save the figures bar widths and tick labels are different in size.

To my understanding, when I produce the second figure with four bar plots and chose double the width of the first figure when exporting, bars and labels should be displayed with the same size in the file. However, the labels are much smaller and the bars have a different width in the second figure. Can anyone tell me why?

Here a simple example:

png(filename="plot1.png", width=200, height=300, bg="white")
par(mfrow = c(1, 2), mar = c(1, 2, 1, 1), oma = c(0, 0, 0, 0))

barplot(height = c(2,3), width = 1, xlim = c(0,2))
barplot(height = c(2,3), width = 1, xlim = c(0,2))
dev.off()

png(filename="plot2.png", width=400, height=300, bg="white")
par(mfrow = c(1, 4), mar = c(1, 2, 1, 1), oma = c(0, 0, 0, 0))

barplot(height = c(2,3), width = 1, xlim = c(0,2))
barplot(height = c(2,3), width = 1, xlim = c(0,2))
barplot(height = c(2,3), width = 1, xlim = c(0,2))
barplot(height = c(2,3), width = 1, xlim = c(0,2))
dev.off()

Plot 1:

Figure 1

Plot 2:

Figure 2


Solution

  • Probably par and pdf(width, height) should be equal.

    png(filename="plot1.png", width=400, height=300, bg="white")
    par(mfrow=c(1, 4), mar=c(1, 2, 1, 1), oma=c(0, 0, 0, 0))
    replicate(2, barplot(height=c(2,3), width=1, xlim=c(0,2)))
    dev.off()
    
    png(filename="plot2.png", width=400, height=300, bg="white")
    par(mfrow=c(1, 4), mar=c(1, 2, 1, 1), oma=c(0, 0, 0, 0))
    replicate(4, barplot(height=c(2,3), width=1, xlim=c(0,2)))
    dev.off()
    

    Another solution is to use layout.

    def.par <- par(no.readonly=TRUE) # save par default, for resetting...
    
    # 1 x 2 plot
    layout(matrix(c(1:2, 0, 0), nrow=1, ncol=4, byrow=TRUE))
    layout.show(n=2)  # to inspect layout                        # MARK
    replicate(2, barplot(height=c(2,3), width=1, xlim=c(0,2)))
    
    # 1 x 4 plot
    layout(matrix(c(1:4), nrow=1, ncol=4, byrow=TRUE))
    layout.show(n=4)  # to inspect layout
    replicate(4, barplot(height=c(2,3), width=1, xlim=c(0,2)))
    
    # 2 x 4 plot
    layout(matrix(c(1:2, 0, 0, 3:6), nrow=2, ncol=4, byrow=TRUE))
    layout.show(n=6)  # to inspect layout
    replicate(2, barplot(height=c(2,3), width=1, xlim=c(0,2)))
    replicate(4, barplot(height=c(2,3), width=1, xlim=c(0,2)))
    
    par(def.par)  # reset to default
    

    However, both solutions bring a half empty plot 1, the reason can be seen in code above at # MARK.

    We could use the magick package to "chop" the first plot to the desired content. First we create the *.pngs with the second method.

    clr <- "#ED7C22"  # color
    
    png(filename="plot1.png", width=400, height=300, bg="white")
    layout(matrix(c(1:2, 0, 0), nrow=1, ncol=4, byrow=TRUE))
    replicate(2, barplot(height=c(2,3), width=1, xlim=c(0,2), col=clr, border=0))
    dev.off()
    
    png(filename="plot2.png", width=400, height=300, bg="white")
    layout(matrix(c(1:4), nrow=1, ncol=4, byrow=TRUE))
    replicate(4, barplot(height=c(2,3), width=1, xlim=c(0,2), col=clr, border=0))
    dev.off()
    

    Now, using image_chop we trim plot1.png to it's left half.

    library(magick)
    (i <- image_read("plot1.png"))
    i.chopped <- image_chop(i, "200x+200")  # says: trim by 200px at pos. 200
    

    Finally, we export the chopped image.

    image_write(i.chopped, path="plot1.ch.png", format="png")
    

    Plot 1 ("chopped")

    enter image description here

    Plot 2

    enter image description here