Sunday, August 9, 2020

Setting the background color for a plot (including a plotted phylogeny) in R

Just for fun, sometimes when I share R graphics via Twitter or on other social media platforms, I switch to a dramatic BLACK background.

For instance, here's a recent tweet in which I describe how to fix the root state for both traits in Pagel's (1994) binary correlated character evolution model:

Normally, however, in the blog posts themselves I stick with the standard transparent background, which will usually appear white on the web.

Working with R base graphics, though, it's really easy to change the background of your plot - and this applies equally to a scatterplot as to a plotted phylogenetic tree.

This is normally done using the function par - which is used to query or (in our case) set graphical parameters for the active plotting device.

The most useful par arguments we're going to see are bg (background color) and fg (foreground color); however, we also may need to use col.lab, col.axis, or col.main, depending on the type of plot we're trying to create.

Let's see a couple of examples.

For this, we'll use some data from phytools. (Note, that you make have to update phytools from GitHub to get these datasets.)

library(phytools)
data(mammal.data)
mammal.data
##                     bodyMass homeRange
## U._maritimus          265.00   115.600
## U._arctos             251.30    82.800
## U._americanus          93.40    56.800
## N._narica               4.40     1.050
## P._lotor                7.00     1.140
## M._mephitis             2.50     2.500
## M._meles               11.60     0.870
## C._lupus               35.30   202.800
## C._latrans             13.30    45.000
## L._pictus              20.00   160.000
## C._aureus               8.80     9.100
## U._cinereoargenteus     3.70     1.100
## V._fulva                4.80     3.870
## H._hyaena              26.80   152.800
## C._crocuta             52.00    25.000
## A._jubatus             58.80    62.100
## P._pardus              52.40    23.200
## P._tigris             161.00    69.600
## P._leo                155.80   236.000
## T._bairdii            250.00     2.000
## C._simum             2000.00     6.650
## D._bicornis          1200.00    15.600
## E._hemionus           200.00    35.000
## E._caballus           350.00    22.500
## E._burchelli          235.00   165.000
## L._guanicoe            95.00     0.500
## C._dromedarius        550.00   100.000
## G._camelopardalis    1075.00    84.600
## S._caffer            6210.00   138.000
## B._bison              865.00   133.000
## T._oryx               511.00    87.500
## G._granti              62.50    20.000
## G._thomsonii           20.50     5.300
## A._cervicapra          37.50     6.500
## M._kirki                5.00     0.043
## O._americanus         113.50    22.750
## O._canadensis          85.00    14.330
## H._equinus            226.50    80.000
## A._melampus            53.25     3.800
## C._taurinus           216.00    75.000
## D._lunatus            130.00     2.200
## A._buselaphus         136.00     5.000
## A._americana           50.00    10.000
## C._canadensis         300.00    12.930
## D._dama                55.00     1.300
## A._alces              384.00    16.100
## R._tarandus           100.00    30.000
## O._virginianus         57.00     1.960
## O._hemionus            74.00     2.850
par(mar=c(5.1,5.1,3.1,1.1))
options(scipen=100)
plot(mammal.data,log="xy",bty="n",pch=19,
    cex=1.5,xlab="body mass (kg)",
    ylab=expression(paste("range size (km"^"2",
    ")")),cex.axis=0.8)

plot of chunk unnamed-chunk-1

There are some plotting tricks in this chode chunk. For instance, I put an exponent (for km2) in my axis label using expression; and I forced R to not use scientific notation in my axis labels by setting options(scipen=100) (any positive value for scipen would have done the trick, in fact).

OK, now why don't we flip our background & foreground colors? To do this, I'm going to use par(bg), and par(fg), but also par(col.lab) and par(col.main).

par(mar=c(5.1,5.1,3.1,1.1),
    bg="black",
    fg="white",
    col.lab="white",
    col.axis="white")
plot(mammal.data,log="xy",bty="n",pch=19,
    cex=1.5,xlab="body mass (kg)",
    ylab=expression(paste("range size (km"^"2",
    ")")),cex.axis=0.8)

plot of chunk unnamed-chunk-2

Nice.

OK, now let's do the same thing with a plotted tree. This time, I'll use a dark slate background instead of a solid background. For this example, I only need to set par(fg) and par(bg).

data(mammal.tree)
lnHomeRange<-setNames(log(mammal.data$homeRange),
    rownames(mammal.data))
homeRange.fit<-edge.widthMap(mammal.tree,lnHomeRange)
homeRange.fit
## Object of class "edge.widthMap" containing:
## (1) Phylogenetic tree with 49 tips and 48 internal nodes.
## (2) Vector of node values for a mapped quantitative
##     trait.
par(fg="white",bg="#696969")
plot(homeRange.fit,
    border="white",max.width=0.8,lwd=2,
    color=palette()[4],
    legend="log(home range size)")

plot of chunk unnamed-chunk-3

Of course, we mustn't forget that unless we reset them or close our active plotting device (using dev.off or by closing the graphical device in our Rgui) our next plot will also inherit the values of par that we set - whether we wanted that or not!

That's all for now folks.