New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Combining multiple panels with or without panel size adjustment #326
Comments
latticeExtra defines a c() method for trellis objects; from what I understand however it would not be very suitable for ggplot2. Am I correct in thinking that any such combination of plots should only alter (at most) the plot dimensions, but not deal with removing axes, combining legends, axis labels, titles, etc.? One feature that's been requested quite often is a multipage option. I don't know how hard that would be to implement for facetting in general. The grid.arrange() way is quite trivial and will be present in the next version of gridExtra (the basic idea is currently on SO http://stackoverflow.com/a/6687147/471093) |
Here are some features that I think would be useful.
It would be nice to be able to specify the sizes as integers, like (3,1), as well as nonintegers, like (1,.33). |
I like this idea - lets put it in 0.9.1 (when hopefully gtable will be Hadley On Sun, Dec 25, 2011 at 7:26 PM, kohske takahashi
Assistant Professor / Dobelman Family Junior Chair |
Thanks. I want to make sure what we need to consider. The Please find the visual tests in: https://github.com/kohske/ggplot2/blob/7bf05ba7c25d58d584430e4c7b2f62c6e889f48b/inst/tests/visual-plot-layout.r
User can specify dimension (i.e., nrow, ncol, or both). Or, user can specify the layout itself. In addition to layout dimension, users can specify widths/heights of each row/column. I wonder which is the best interface to set layout.
This is a wrapper for Do you have any good idea? Anyway, the importance of I will discuss about |
First, interface to specify the table layout. This is same issue with In addition to the interface, there are two big issue:
In But sometimes the nrow/ncol are inconsistent. a) drop guides (legends) and keep other materials. b) Induce an error, and enforce users to appropriate dimension. I also like this way as an initial implementation. or any other possibility?
|
Here's an idea for how to specify the arrangement for table and layout, in a single unified way. I don't know what the "normal" way is to do this is -- this is just what comes to mind. Suppose you could give it a matrix, like this:
This means: use a 3x3 grid, put the first object And to specify the relative size of rows and columns, you could add row and column names:
The NA just means that that cell is empty. The row and column names determine the relative size of the cells. So the upper-left cell is 80% of the width and 80% of the height; the upper-right cell is 20% width, 80% height; and so on. Hopefully you could also use non-integer values. This method is also a little syntactically awkward (because using |
another general question is whether one wants to draw directly on the page, or return a grob as an alternative. It could be nice if grid.arrange supports most of these features, only multi-cell spanning isn't implemented as I couldn't find an elegant way of defining the layout. |
Thanks. Perhaps,
should be
The advantage is of course visual representation and also that some users are familier with this system. |
I pushed a testbed for combining multiple panel. @baptiste ggarrange now does not support grob-extraction, but will support in future. |
@baptiste I implemented grob-extraction here: https://github.com/kohske/ggplot2/tree/feature/plot-layout |
@kohske I just took a quick look at the code. There is a |
@baptiste oops, fixed. thanks. |
@wch Sorry, I had a mistake about your name. Thanks anyway. I'm happy if you will review the branch. |
@kohske I run the examples; it's great. One thought, have you considered something like a global title, on top of the page (and perhaps one for each side as well, just in case)? ggarrange, from what I can see, could easily work with arbitrary grobs, in which case it would have reproduced the full functionality of grid.arrange (minus the latest addition of multiple pages and ggsave support). That's why I'm not sure what you mean by "combine with gridExtra", can you clarify please? |
I have a question, also: as those functions (presumably) become more and more self-contained and independent (moving towards gtable), perhaps it could be good to systemize the naming convention (single "g" for "grid"? or double "gg" for "grammar of graphics"). Grid/gridExtra have already defined grid.layout and grid.arrange (I'd be willing to remove the latter when ready), leaving the possibility: garrange, glayout, whilst ggtable, however, would remain with ggplot2 (but the name is probably confusing, with the gtable package). |
oh, and another side-remark: I noticed you have an example with inset plot; annotation_custom is probably more flexible for this particular purpose [https://github.com/baptiste/ggplot2/blob/customgrob/R/annotation-custom.r#L29] |
@kohske I tried it out, and I like it! It works very well. A couple of comments: I like the idea of having insets but the interface seems somewhat awkward. Am I right that it requires using a character matrix like this? It seems kind of inelegant, not that I have a better idea.
If I wanted to inset a graph and have it set away from the edge, it seems I would have to do something like this:
This seems kind of complicated to me (but again I don't have a better idea right now). Finally, I would suggest having some code to detect when the numbers aren't laid out in rectangles. In the example below, I think it should give a warning/error, but right now it doesn't:
|
@baptiste @wch thanks you for the comments. Here is point-to-point comments.
gg <- ggarrange(qplot(1:3, 1:3), qplot(1:3))
grid.arrange(gg, xyplot(1:10~1:10)) # does not work
grid.arrange(gtable_gTree(gg), xyplot(1:10~1:10)) # does work
As for the naming, I named
Yes, the inset plot is unplanned feature. After implementation, I found that the inset plot is possible. So probably not well designed.
No. At the moment,
m <- matrix(
c(1, 1, 1,
2, 2, 3,
4, 5, 5,
6, 5, 5), 4, byrow = T)
lay <- gglayout(m)
lay <- gglayout(row = list(1, 2, 2, 3, 3:4, 4), col = list(1:3, 1:2, 3, 1, 2:3, 1))
The inset plot is possible only by 2) the list of row/col span.
Agreed. I'm looking for the good algorithms for detecting such incorrect layout. Now I'm using Thanks!! |
On 9 January 2012 15:20, kohske takahashi
I guess my question is whether ggarrange could also work with other Making the current arrangeGrob compatible with ggarrange does not help Cheers, b.
|
I think this should do the trick. It could probably be cleaned up a little, though. # Returns TRUE if all the x's in mat are arranged in a rectangle,
# FALSE otherwise
is_rect <- function(x, mat, ...) {
numcol <- ncol(mat)
numrow <- nrow(mat)
# The column and row numbers for each location in the matrix
colnums <- matrix( rep(1:numcol, numrow), ncol = numcol, byrow=TRUE)
rownums <- matrix( rep(1:numrow, numcol), nrow = numrow, byrow=FALSE)
# Find matrix locations that contain x
xloc <- mat == x
# Find min and max value of cols and rows with x.
# This specifies a rectangle.
rowmin <- min(rownums[xloc])
rowmax <- max(rownums[xloc])
colmin <- min(colnums[xloc])
colmax <- max(colnums[xloc])
# All values of xloc inside the rectangle should be TRUE.
# All values of xloc outside the rectangle should be FALSE.
# Check this by inverting the rectangle and checking that all == FALSE
xloc[rowmin:rowmax, colmin:colmax] <- !xloc[rowmin:rowmax, colmin:colmax]
if (any(xloc)) return(FALSE)
else return(TRUE)
}
# Returns TRUE if all values in mat are in rectangles, FALSE otherwise
is_all_rects <- function(mat) {
# Get all the unique values in mat
nums <- unique(as.vector(mat))
# (Not totally sure this uses vapply correctly...)
goodrects <- vapply(nums, is_rect, TRUE, mat)
if (all(goodrects)) {
return(TRUE)
} else {
stop(paste("These numbers are not in rectangles: ",
paste(nums[!goodrects], collapse=", ")))
return(FALSE)
}
}
These function names are probably not the best for the ggplot2 namespace. Also, it won't work for all character matrices -- it could fail for cases where there's weird stuff like Some test cases: mat <- matrix(c(
1, 1, 2,
1, 1, 2,
3, 3, 2
), 3, byrow=TRUE)
is_all_rects(mat)
# [1] TRUE
mat2 <- matrix(c(
1, 1, 2,
1, 1, 2,
3, 3, 1
), 3, byrow=TRUE)
is_all_rects(mat2)
# Error in is_all_rects(mat2) : These numbers are not in rectangles: 1
mat3 <- matrix(c(
1, 1, 2,
1, 1, 2,
1, 3, 3
), 3, byrow=TRUE)
is_all_rects(mat3)
# Error in is_all_rects(mat3) : These numbers are not in rectangles: 1
mat4 <- matrix(c(
1, 1, 2,
1, 1, 3,
3, 1, 3
), 3, byrow=TRUE)
is_all_rects(mat4)
# Error in is_all_rects(mat4) : These numbers are not in rectangles: 1, 3 |
I'm not sure how general ggarrange(
qplot(iris[,1], iris[,2]),
tableGrob(iris[1:6, 1:2], gp=gpar(fontsize=8))) and output here: https://skitch.com/e-kohske/gadjt/2012-01-09-13.50.38 But in my view How do you see it, @hadley? |
@wch Thanks. is_rect <- function(i, mat) {
m0 <- array(FALSE, dim(mat))
is <- which(mat == i, arr.ind=T)
m0[seq(min(is[, 1]), max(is[, 1])), seq(min(is[, 2]), max(is[, 2]))] <- TRUE
is <- which(m0)
all(mat[is] == i) && all(mat[-is] != i)
}
There is no interface to set the character matrices. |
How about testing for the number of elements against the number of elements for the maximum block? is_rect <- function(i, mat) { |
@baptiste why |
@kohske yes, |
... unless you want to use this case to specify "inset" plots, that is to say enforce connected blocks (no gap), but not necessarily simply connected (can have holes). |
Moving to 0.9.2 since I'm now reserving 0.9.1 for bug fixes and v. small features. |
I now wonder if this shouldn't be in it's own package. |
Yes, I may write after the port to gtable package. |
Here is an initial implementation. https://github.com/kohske/ggplot2/tree/feature/plot-layout
Two way of combining:
Currently, using S3 of cbind and rbind.
Any idea and suggestions are welcome.
The text was updated successfully, but these errors were encountered: