Hi folks,

I developed this simple function (modified from this link) that inserts a png picture to a plot in R while keeping the proportion of the original figure. The novelty here (compared to the original) is that it does the job regardless of plot dimensions (i.e. squared or stretched). Thought I’d share this because often people move away from R when they need to insert a bunch of pictures inside plots.

I’ve also just added a new function that changes the colour of RGBa objects (which is the case of both logos used in the example). So, even though the fox and rabbit logos are originally black, they can changed to any colour.

I suspect I may have reinvented the wheel here, so please let me know if you already know of a package that does the same thing.

Cheers,

D

```
library(RCurl) # only necessary if extracting a png from the web
library(png) # actual package needed to 'read' a png picture into R
# modified from https://gist.github.com/scrogster/7fc5b7597b63585a00b6
# png silhouettes of red fox and rabbit from phylopic.org
foxurl <- 'http://phylopic.org/assets/images/submissions/51b1b6e4-129d-41a6-bbbd-c3fab459c25f.1024.png'
raburl <- 'http://phylopic.org/assets/images/submissions/1e15411c-5394-4a9d-a209-76c8ac0c331d.1024.png'
foxLogo <- readPNG(getURLContent(foxurl))
rabLogo <- readPNG(getURLContent(raburl))
# utility function for embedding png images at specified fractional sizes in R plots
# places the logo centred on a specified fraction of the the usr space,
# and sizes appropriately (respects aspect ratio)
# works for any plot size, including logged axes
# logo: a png object obtained with readPNG
# px: is a vector with 2 values (start and end) specifying the relative x positions (i.e. between 0 and 1)
# py: is the initial (i.e. bottom) relative y position (i.e. between 0 and 1)
# log: should the x and/or y axes be logged? Default to FALSE; Alternative values are 'x', 'y' or 'xy'
proportionalPng <- function(logo, px, py, log = FALSE, ...) {
if(!is.numeric(px) | !is.numeric(py) | length(px) != 2) {
stop('wrong position coordinates [0,1]')
}
usr <- par('usr')
pin <- par('pin')
# first get proportions of coordinates right
pxRg <- px[2] - px[1]
xProp <- usr[1] + px * (usr[2] - usr[1]) # x range from relative px
yProp <- usr[3] + py * (usr[4] - usr[3]) # minimum y from relative py
# now get aspect ratio to calculate maximum y
pinRatio <- pin[2] / pin[1] # aspect ratio of actual plot region, depends on device and plot size
dims <- dim(logo)[1:2] # number of x-y pixels for the logo (aspect ratio)
AR <- dims[1] / dims[2]
yProp <- c(yProp, usr[3] + (py + pxRg * AR / pinRatio) * (usr[4] - usr[3])) # maximum y from relative py correcting for x and plot ratios
if (log == 'x') xProp <- 10^(xProp)
if (log == 'y') yProp <- 10^(yProp)
if (log == 'xy') {xProp <- 10^(xProp); yProp <- 10^(yProp)}
rasterImage(logo, xProp[1], yProp[1], xProp[2], yProp[2], interpolate=TRUE, ...)
}
# change colour
# currently works for RGBa only
changePngColour <- function(pngObject, col, ...) {
rgbVals <- col2rgb(col, ...) / 255
for(i in 1:3)
pngObject[,,i] <- rgbVals[i]
pngObject
}
# Example 1: a time-series plot of fake fox and rabbit abundance data with phylopic logos overlaid: squared plot
dev.new(width=7, height=7)
par(mfrow=c(1,2))
set.seed(1)
years <- 1981:2010
abundanceFox <- 50*cumprod(exp(rnorm(30, 0.02, 0.1)))
abundanceRab <- 50*cumprod(exp(rnorm(30, -0.05, 0.2)))
plot(abundanceFox ~ years, xlab='Time', pch=16, ylab='Fox abundance', las=1, col='tomato', lwd=2, type='o', ylim=c(0, 150), main='Index of fox abundance, 1981-2010', cex.main=0.8)
proportionalPng(changePngColour(foxLogo, 'tomato'), c(0.1,0.5), c(0.2)) # sets fox to occupy 40% of the x axis [i.e. 0.5 - 0.1 = 0.4], starting at 20% of the y axis
plot(abundanceRab ~ years, xlab='Time', pch=16, ylab='Rabbit abundance', las=1, col='darkorange', lwd=2, type='o', ylim=c(0, 150), main='Index of rabbit abundance, 1981-2010', cex.main=0.8)
proportionalPng(changePngColour(rabLogo, 'dodgerblue2'), c(0.1,0.3), c(0.5)) # sets fox to occupy 20% of the x axis [i.e. 0.3 - 0.1 = 0.2], starting at 50% of the y axis
# Example 2: a time-series plot of fake fox abundance data with phylopic logos overlaid: stretched plot
dev.new(width=7, height=3)
plot(abundanceFox ~ years, xlab='Time', pch=16, ylab='Fox abundance', las=1, col='tomato', lwd=2, type='o', ylim=c(0, 150), main='Index of fox abundance, 1981-2010', cex.main=0.8)
proportionalPng(foxLogo, c(0.7,0.9), c(0.1)) # sets fox to occupy 20% of the x axis [i.e. 0.9 - 0.7 = 0.2], starting at 10% of the y axis
# Example 3: a time-series plot of fake fox abundance data with phylopic logos overlaid: log plot
dev.new(width=7, height=3)
plot(abundanceFox ~ years, xlab='Time', pch=16, ylab='Fox abundance', las=1, col='dodgerblue2', lwd=2, type='o', ylim=c(50, 150), main='Index of fox abundance, 1981-2010', cex.main=0.8, log='y')
proportionalPng(foxLogo, c(0.75,0.95), c(0.05), log='y') # sets fox to occupy 20% of the x axis [i.e. 0.95 - 0.75 = 0.2], starting at 5% of the y axis
```