plotting y and log(y) in one figure

December 15, 2013
By

(This article was first published on Wiekvoet, and kindly contributed to R-bloggers)

Sometimes I have the desire to plot both on the linear and on the log scale. To save space just two figures is not my solution. I want to reuse the x-axis, legend, title. This post examines possibilities to do so with standard plot tools, lattice and ggplot2.

Data

Data is completely artificial.
library(ggplot2)
library(lattice)

datastart <- data.frame(x=rep(1:5,2),
    y=c(1,2,10,50,1, .1,9,8,20,19),
    type=rep(c('a','b'),each=5))
datastart
   x    y type
1  1  1.0    a
2  2  2.0    a
3  3 10.0    a
4  4 50.0    a
5  5  1.0    a
6  1  0.1    b
7  2  9.0    b
8  3  8.0    b
9  4 20.0    b
10 5 19.0    b

standard plot tools

The trick here is to make two plots. The top plot has no x-axis, the bottom one no title. To make the two plot surfaces equal in size the room reserved for x-axis and title is the same. 

par(mfrow=c(2,1),mar=c(0,4.1,4,2))
plot(y~x,
    data=datastart,
    axes=FALSE,
    frame.plot=TRUE,
    xlab='',
    main='bla bla',
    col=c('red','green')[datastart$type])
legend(x='topleft',
    legend=c('a','b'),
    col=c('red','green'),
    pch=1)
axis(side=2,las=1)
par(mar=c(4,4.1,0,2))
plot(y~x,
    data=datastart,
    axes=FALSE,
    frame.plot=TRUE,
    xlab='x',
    log='y',
    ylab='log(y)',
    col=c('red','green')[datastart$type]
)
axis(side=2,las=1)
axis(side=1)

lattice

As far as I understand, lattice does not have the tools to fiddle this extreme with axis. The trick then is to add a copy of the data on logarithmic scale and manually control the labels. Lattice does not understand that the x-axis are same, but some suppression is possible.
data1=datastart
data2=datastart
data1$lab='linear'
data2$lab='log'
data2$y <- log10(data2$y)
dataplot <- rbind(data1,data2)

at2 <- axisTicks(range(data2$y),log=TRUE,nint=4)
at1 <- axisTicks(range(data1$y),log=FALSE,nint=5)
atx <- axisTicks(range(data1$x),log=FALSE,nint=5)
dataplot$lab <- factor(dataplot$lab,levels=c('linear','log'))
xyplot(y  ~ x | lab,groups=type,data=dataplot,layout=c(1,2),
    main='bla bla',
    as.table=TRUE,
    auto.key=TRUE,
    scales=list(relation='free',
        x=list(at=list(NULL,atx)),
        y=list(at=list(at1,log10(at2)),
            labels=list(format(at1),format(at2))
        )
    ))

ggplot2

The trick here is that ggplot2 can have a free y-axis, but you cannot set the labels per axis. Instead it is a common y-axis which has adapted labels. ggplot chooses the range for the y-axis itself, you have to make sure that the labels you feed it match that range. To make that fit in the end I just shifted the whole log part to a different range. Some of the code of lattice is re-used.

dataplot2 <- dataplot
offset <- -10
breaks=c(-11,-10,-9)
dataplot2$y[dataplot2$lab=='log'] <- dataplot2$y[dataplot2$lab=='log'] +offset 
p <- ggplot(dataplot2, aes(x, y,colour=type)) + geom_point()
p + facet_grid(lab ~ .,
        scales='free_y') +
    labs(title = 'bla bla') +
    scale_y_continuous(
        breaks = c(breaks,at1),
        labels=c(format(10^(breaks-offset)),format(at1)))

To leave a comment for the author, please follow the link and comment on his blog: Wiekvoet.

R-bloggers.com offers daily e-mail updates about R news and tutorials on topics such as: visualization (ggplot2, Boxplots, maps, animation), programming (RStudio, Sweave, LaTeX, SQL, Eclipse, git, hadoop, Web Scraping) statistics (regression, PCA, time series, trading) and more...



If you got this far, why not subscribe for updates from the site? Choose your flavor: e-mail, twitter, RSS, or facebook...

Comments are closed.