how to combined plot: facett vs grid arrange

1,041 views
Skip to first unread message

Johannes Radinger

unread,
Nov 11, 2011, 9:05:15 AM11/11/11
to baptist...@gmail.com, h.wi...@gmail.com, ggp...@googlegroups.com
Hello,

I am not sure if it is really possible what I want but
here my "wish":

I'd like to show two point-plots in 1 row/2 columns.
They both share there y axis (which should be a log
scale with own labels). The two plots don't share
their x axis (one x axis is log and with different extent).
For each plot there are two groups of points and
I want to display for both groups the regression line.

What I've done so far are two different approaches:
1) create each plot separately and then combine them with
grid.arrange

2) create a facett_plot with free scales

both of the approaches do have some advantages but also
some disadvantages:

1) facett-approach: I don't know how to use set some of the free axis
to log scales and use different labels

2) grid.arrange-approach: the single plots are fine, except that I'd like
the x-axis titles in a grey bar above the plot (like in the facett plots).
Furthermore I don't want ticks on the left side of the plot (for the plots in the right column. And I don't know how to set the margins between left and right column to a narrower space.

I don't know if here the ggExtra package can help me or how to get to what I want.

Hopefully you can help me in doing this.
To explain my problem/task/approaches, I attached a working sample
script with the two outcomes so far (plot.facett, plot.grid). I'd like
more or less a mixture of both...

Thank you very much

Johannes


--
NEU: FreePhone - 0ct/min Handyspartarif mit Geld-zurück-Garantie!
Jetzt informieren: http://www.gmx.net/de/go/freephone

sample_data.R

Winston Chang

unread,
Nov 11, 2011, 12:40:06 PM11/11/11
to Johannes Radinger, baptist...@gmail.com, h.wi...@gmail.com, ggp...@googlegroups.com
Hi Johannes -
(Oops, I forgot to send this to the list the first time.)
I think there's a bug in your code: in the last set of graphs, I think ggplot should use df3 instead of df2.

Here's one way you can do it, but it's not very elegant. For the titles, it draws a large gray rectangle that goes out of the plotting range, and then puts text on top of it. This requires the development version, I think, because the current release version doesn't allow geoms to go outside of the plotting area. (They just disappear if any part goes outside.)

Also with the devel version, if you specify breaks and labels that go outside of the axis limits, it has a problem with it, so I removed the 0.1 break on the y axis. This might be a bug?

Finally, I don't have ggextra installed so I can't test the final grid.arrange. Apparently ggextra isn't available for R 2.14.0 yet.

Hope this helps,
-Winston

# First part is same - just set up the data 

library(ggplot2)
library(reshape2)

#creating sample data and dataframe
pred.x1 <-runif(5, 5.0, 7.5)
pred.x2 <- runif(5,0.1,0.9)
pred.x3 <- runif(5,0,1000)
resp.y1 <- runif(5,1,10)
resp.y2 <- runif(5,30,50)

df1 <- data.frame(pred.x1,pred.x2,pred.x3,resp.y1,resp.y2)

df2 <- reshape2:::melt.data.frame(reshape2:::melt.data.frame(df1,id=c("resp.y1", "resp.y2"),variable.name="pred.name",value.name="pred.value"),id=c("pred.name","pred.value"),variable.name="resp.name",value.name="resp.value")

df3 <-reshape2:::melt.data.frame(df1,id=c("pred.x1", "pred.x2", "pred.x3"),variable.name="resp.name",value.name="resp.value")

# ======================================================

# Increase y range by a constant (visually) amount
yrange <- c(1,70)

# This function finds the middle point in a log scale
logmiddle <- function(x) { exp(mean(log(range(x)))) }

# the background rectangle
labelrect <- annotate("rect", xmin=.01, xmax=10000, ymin=52, ymax=90, fill="grey80")


#create single plots
plot.grid1 <- ggplot(df3, aes(x=pred.x1,y=resp.value,colour=resp.name))+
geom_point()+
scale_x_log10(limits=range(df3$pred.x1))+
labelrect +
annotate("text", logmiddle(df3$pred.x1), 65, label="pred.x1") +
scale_y_log10("Response", limits=yrange,
      breaks=c(1,5,10,20,50),labels=c(1,5,10,20,50))+
opts(legend.position = "none",
axis.title.y = theme_blank()
#axis.ticks = theme_blank()
)


plot.grid2 <- ggplot(df3, aes(x=pred.x2,y=resp.value,colour=resp.name))+
geom_point()+
scale_x_log10(limits=range(df3$pred.x2))+
labelrect +
annotate("text", logmiddle(df3$pred.x2), 65, label="pred.x2") +
scale_y_log10("Response", limits=yrange,
      breaks=c(1,5,10,20,50),labels=c(1,5,10,20,50))+
opts(legend.position = "none",
axis.title.y = theme_blank(),
axis.text.y = theme_blank()
)

plot.grid3 <- ggplot(df3, aes(x=pred.x3,y=resp.value,colour=resp.name))+
geom_point()+
scale_x_log10(limits=range(df3$pred.x3))+
labelrect +
annotate("text", logmiddle(df3$pred.x3), 65, label="pred.x3") +
scale_y_log10("Response", limits=yrange,
      breaks=c(1,5,10,20,50),labels=c(1,5,10,20,50))+
opts(legend.position = "none",
axis.title.y = theme_blank()
)

plot.grid <- grid.arrange(plot.grid1,
plot.grid2,
plot.grid3,
ncol=2,
nrow=2,
left = "Response")

--
You received this message because you are subscribed to the ggplot2 mailing list.
Please provide a reproducible example: http://gist.github.com/270442

To post: email ggp...@googlegroups.com
To unsubscribe: email ggplot2+u...@googlegroups.com
More options: http://groups.google.com/group/ggplot2

Johannes Radinger

unread,
Nov 14, 2011, 4:45:06 AM11/14/11
to ggp...@googlegroups.com, winsto...@gmail.com
Hi,

first thank you for that codesnippet so that I can have these
grey rectangles. It works fine with the dev-version of ggplot.

The grid.arrange is part of the gridExtra package and not a function
of ggExtra. Anyway I managed to get ggExtra installed on R 2.14.0
with: install.packages("ggExtra", repos="http://R-Forge.R-project.org")

There are still some problems:

1) I can't use grid.arrange in the dev-mode.
When I try to use the call it says: Error: could not find function "ggplotGrob"

I don't know how I should change between dev-mode to create the plots and
non-dev mode to use grid.arrange. I tried to load the libaries as follows:

library(gridExtra)
library(devtools)
dev_mode(TRUE)
library(ggplot2)
library(reshape2)

(I followed the approach to load dev-mode as recommended here:
https://gist.github.com/1150934)

2) How can I remove the ticks only from the x axis?
In the opts there is only available: axis.ticks = theme_blank()
So that is for all ticks (x and y axis)

3) How can I set the space between the plots in grid.arrange or
is there any other package that is better for this purpose??

Thank you very much.

/Johannes

-------- Original-Nachricht --------
> Datum: Fri, 11 Nov 2011 11:37:13 -0600
> Von: Winston Chang <winsto...@gmail.com>
> An: Johannes Radinger <JRad...@gmx.at>
> Betreff: Re: how to combined plot: facett vs grid arrange

> Hi Johannes -

> > --
> > You received this message because you are subscribed to the ggplot2
> > mailing list.
> > Please provide a reproducible example: http://gist.github.com/270442
> >
> > To post: email ggp...@googlegroups.com
> > To unsubscribe: email ggplot2+u...@googlegroups.com
> > More options: http://groups.google.com/group/ggplot2
> >

--

Johannes Radinger

unread,
Nov 14, 2011, 9:28:41 AM11/14/11
to Johannes Radinger, winsto...@gmail.com, ggp...@googlegroups.com
Hi again,

I tried to further improve my code and got a least a little bit further:

I managed now to get the text in the grey boxes working and arrange the
plots with grid.layout and pushviewport.

Here is what I did so far:

#creating sample data and dataframe
pred.x1 <-runif(5, 5.0, 7.5)
pred.x2 <- runif(5,0.1,0.9)
pred.x3 <- runif(5,0,1000)
resp.y1 <- runif(5,1,10)
resp.y2 <- runif(5,30,50)

df1 <- data.frame(pred.x1,pred.x2,pred.x3,resp.y1,resp.y2)

########## grid arrange approach ###############

#reshape dataframe for this approach
df3 <-reshape2:::melt.data.frame(df1,id=c("pred.x1", "pred.x2", "pred.x3"),variable.name="resp.name",value.name="resp.value")

# Increase y range by a constant (visually) amount
yrange <- c(1,70)

# This function finds the middle point in a log scale
logmiddle <- function(x) { exp(mean(log(range(x)))) }

# the background rectangle
labelrect <- annotate("rect", xmin=.01, xmax=10000, ymin=52, ymax=90, fill="grey80")

#create single plots
#create single plots
plot.grid1 <- ggplot(df3, aes(x=pred.x1,y=resp.value,colour=resp.name))+
geom_point()+
scale_x_log10(limits=range(df3$pred.x1))+
labelrect +

annotate("text", logmiddle(df3$pred.x1), 65, label="pred.x1", size=4) +


scale_y_log10("Response", limits=yrange, breaks=c(1,5,10,20,50),labels=c(1,5,10,20,50))+
opts(legend.position = "none",

axis.title.x = theme_blank(),
axis.title.y = theme_blank(),
plot.margin = unit(c(0, 0, 0, 0), "cm")
)


plot.grid2 <- ggplot(df3, aes(x=pred.x2,y=resp.value,colour=resp.name))+
geom_point()+
scale_x_log10(limits=range(df3$pred.x2))+
labelrect +

annotate("text", logmiddle(df3$pred.x2), 65, label="pred.x2", size=4) +


scale_y_log10("Response", limits=yrange, breaks=c(1,5,10,20,50),labels=c(1,5,10,20,50))+
opts(legend.position = "none",

axis.title.x = theme_blank(),
axis.title.y = theme_blank(),
axis.text.y = theme_blank(),
plot.margin = unit(c(0, 0, 0, 0), "cm")
)

plot.grid3 <- ggplot(df3, aes(x=pred.x3,y=resp.value,colour=resp.name))+
geom_point()+
scale_x_log10(limits=range(df3$pred.x3))+
labelrect +

annotate("text", logmiddle(df3$pred.x3), 65, label="pred.x3", size=4) +


scale_y_log10("Response", limits=yrange, breaks=c(1,5,10,20,50),labels=c(1,5,10,20,50))+
opts(legend.position = "none",

axis.title.x = theme_blank(),
axis.title.y = theme_blank(),
plot.margin = unit(c(0, 0, 0, 0), "cm")
)

grid.newpage()
pushViewport(viewport(layout = grid.layout(nrow=2, ncol=2,
widths = unit(c(7.5,7), "cm"),
heights = unit(rep(5, 2), "cm"))))
print(plot.grid1, vp = viewport(layout.pos.row = 1, layout.pos.col = 1))
print(plot.grid2, vp = viewport(layout.pos.row = 1, layout.pos.col = 2))
print(plot.grid3, vp = viewport(layout.pos.row = 2, layout.pos.col = 1))


Just some comments and questions to that:

1) I removed the y-axis text on the right side column plots with opts
2) I set the plot margins to 0 for each plot
3) I had to set the grid.layout column widths manually as on one side
the axis text is removed. I didn't find any other way so that the box
of the left and the right side are exactly the same size.
4) I still don't know how to remove the y axis ticks for plot.grid2
5) I set the text size in the annotation manually to size=4. What is the size of the axis text? Is there any way to use a relative text size?
6) How can I sent the grid.layout - output to a eps/pdf?


And of course I am still interested in the other questions I asked before:

1) How to use log scale for basis e instead of log10?
2) How can I use "scale_shape_manual(value=c(21,16))" in
ggplot dev-mode

Thank you
Johannes

--
Ihr GMX Postfach immer dabei: die kostenlose GMX Mail App für Android.
Komfortabel, sicher und schnell: www.gmx.de/android

Winston Chang

unread,
Nov 14, 2011, 8:21:02 PM11/14/11
to Johannes Radinger, ggp...@googlegroups.com
2) How can I remove the ticks only from the x axis?
In the opts there is only available: axis.ticks = theme_blank()
So that is for all ticks (x and y axis)


I think that for gridlines and tick marks, it's not possible to control the appearance x and y independently. Kohske posted some code to disable just vertical (or horizontal) gridlines in this thread:

But it's kind of a hack, and it influences ggplot globally. After you run the code, no graph will have have vertical grid lines until you run some similar code to bring them back. I would guess that something similar is possible with the tick marks, if you're willing to dig around in the code.



It might be simpler to hide all the tick marks, then manually add your own tick marks with geom_segment. Here's some code to do that, though it's not the most elegant. It also sets the tick labels to e^0, e^1, etc, because the devel version doesn't seem to do that automatically.

# Random data - exponential distribution on y axis
set.seed(342)
df <- data.frame(x=rnorm(50), y=exp(rnorm(50)))

# Manually specify x start and endpoints for segments
tickxmax <- -2.3
tickxmin <- tickxmax-1

# Everything below here should work automatically without manual tweaking

# Get the range of powers of e that span the data
# The rounding might need tweaking to get a range to match
# ggplot's range for all data. But it works for this data.
powrange <- ceil(min(log(y))):floor(max(log(y)))

# Set the breaks and labels
ybreaks <- exp(powrange)
ylabels <- parse(text=paste("e^", powrange,sep=""))
ylabels
# expression(e^-2, e^-1, e^0, e^1, e^2)



# Make the ticks
yticks <- data.frame(y=exp(powrange), xmin=tickxmin, xmax=tickxmax)


ggplot(df, aes(x=x, y=y)) + geom_point() +
    geom_segment(data=yticks, aes(y=y, yend=y, x=xmin, xend=xmax),
                 size=.5) +
    scale_y_continuous(trans="log",
                       breaks=ybreaks,
                       labels=ylabels) +
    scale_x_continuous(limits=range(df$x)) +
    theme_bw() +
    opts(axis.ticks = theme_blank())



A couple notes:
- This requires the development version. I believe the current release version won't show the ticks at all since they go out of the plotting area.
- You need to set the x range manually because it otherwise will expand the plotting area to include the entire segment.
- If any of the breaks and labels are outside the plotting area, it will complain. (IIRC this wasn't a problem with release version, but is a problem with the devel version.)
- I used theme_bw because the black ticks look a little weird with the white gridlines of theme_grey.


-Winston
exp_ticks_internal.png
Reply all
Reply to author
Forward
0 new messages