10

I am plotting Tanglegrams in R using dendextend. I am wondering if it is possible to plot multiple subplots using par(mfrow = c(2,2))?

I can't seem to figure it out.

Thanks

library(dendextend)
dend15 <- c(1:5) %>% dist %>% hclust(method = "average") %>% as.dendrogram
dend15 <- dend15 %>% set("labels_to_char")
dend51 <- dend15 %>% set("labels", as.character(5:1)) %>% match_order_by_labels(dend15)
dends_15_51 <- dendlist(dend15, dend51)

par(mfrow = c(2,2))
tanglegram(dends_15_51)
tanglegram(dends_15_51)
tanglegram(dends_15_51)
tanglegram(dends_15_51)
Tal Galili
  • 24,605
  • 44
  • 129
  • 187
user2861089
  • 1,205
  • 4
  • 22
  • 44

2 Answers2

8

tl;dr: It is not possible to use par(mfrow=...) with the function tanglegram, but it is possible using layout.

Explanation: If you look closer at function tanglegram, you'll see (methods(tanglegram)) that, underneath, there are several methods, among which, dendextend:::tanglegram.dendrogram which is called to draw the tanglegram (as can be seen inside dendextend:::tanglegram.dendlist function).

Inside this function, there is a call to layout:

layout(matrix(1:3, nrow = 1), widths = columns_width) 

This "erases" your previous setting of par(mfrow=c(2, 2)) and changes it to c(1, 3) (just for the "time" of the function though because at the end of the function, the value is reset...).

Indeed, in the help page of layout, it says:

These functions are totally incompatible with the other mechanisms for arranging plots on a device: par(mfrow), par(mfcol) and split.screen.

Conclusion: If you want to plot several tanglegrams in the same "window" you'll need to use the layout call (with 12 subparts: 2 rows and 6 columns) ahead of the calls to tanglegram and suppress the layout call inside tanglegram using the argument just_one=FALSE.

Example of drawing several tanglegrams:

Using the code below, you can then obtain the desired plot (I put the function's default widths for the layout):

layout(matrix(1:12, nrow=2, byrow=TRUE), widths=rep(c(5, 3, 5), 2))
tanglegram.dendlist_mod(dends_15_51, just_one=FALSE)
tanglegram.dendlist_mod(dends_15_51, just_one=FALSE)
tanglegram.dendlist_mod(dends_15_51, just_one=FALSE)
tanglegram.dendlist_mod(dends_15_51, just_one=FALSE)

enter image description here

This was done by updating the dendextend package in which: I modified the 2 functions tanglegram.dendrogram and tanglegram.dendlist to add a just_one parameter, which defaults to TRUE and changed the line of the layout in tanglegram.dendrogram to:

 if (just_one) layout(matrix(1:3, nrow = 1), widths = columns_width)

I also suppressed the reset of par parameters and of course changed the call in tanglegram.dendlist (now called tanglegram.dendlist_mod) so it calls the new modified function, incorporates the just_one parameter and passes it to the modified tanglegram.dendrogram function.

Tal Galili
  • 24,605
  • 44
  • 129
  • 187
Cath
  • 23,906
  • 5
  • 52
  • 86
  • 2
    as a quick alternative you could grab the image, and convert it to a grid object and then combine.. http://stackoverflow.com/questions/27929452/r-return-corrplot-as-object/#27948707 – user20650 Oct 04 '16 at 22:03
  • 1
    @user20650 I thought of using `grid` but wasn't aware that one can grab an image. I've been missing this package, thanks! – Cath Oct 05 '16 at 06:55
  • 1
    @user20650 good idea, but the solution you link to doesn't work with tanglegram, unfortunately. Problem seems to be that `grid.echo` chokes on horizontal dendrograms (e.g. `plot(dend51); grid.echo()` works, `plot(dend51, horiz = TRUE); grid.echo()` throws an error) and this is required to convert the image to a grid object. – Heather Turner Oct 05 '16 at 09:23
  • @HeatherTurner; I really should try things first!! Interesting how it fails on horiz (and then also margin_outer). – user20650 Oct 05 '16 at 09:32
  • I think problem comes from the fact that, at one moment, the min of x-axis is above the max. Modifying the computation of `ticksub` inside `C_axis` (which is called and inside which is th call to `unit` that throws the error) avoids the error. But again, at least one function has to be modified... – Cath Oct 05 '16 at 10:14
  • 1
    Shame grid approach didn't work here - in that case modifying `tangle.dendrogram` is probably simpler. Note as alternative to creating `_mod` functions, you could use `fixInNamespace(tangle.dendrogram, "dendextend")` to make the changes, then you could use `tanglegram` with the new `just_one` argument directly. – Heather Turner Oct 06 '16 at 11:49
  • 1
    HI @Cath do you want to make a pull request for this addition? https://github.com/talgalili/dendextend – Tal Galili Oct 17 '16 at 09:47
4

Rather than creating a combined plot in a single graphical device, you could create multiple plots and arrange them when you put them in a document. The knitr package makes it easy to do this, by using fig.show = "hold" to hold on to multiple plots produced in a single R chunk and specifying a relevant out.width, e.g. 50% to have two plots in a row, for when the plots are placed in the document.

For example, in an R markdown (.Rmd) file you might have

```{r, fig.show = "hold", out.width = "50%", echo = FALSE}
suppressPackageStartupMessages(library(dendextend))
dend15 <- c(1:5) %>% dist %>% hclust(method = "average") %>% as.dendrogram
dend15 <- dend15 %>% set("labels_to_char")
dend51 <- dend15 %>% set("labels", as.character(5:1)) %>% match_order_by_labels(dend15)
dends_15_51 <- dendlist(dend15, dend51)
tanglegram(dends_15_51, margin_outer = 1)
plot.new()
tanglegram(dends_15_51, margin_outer = 1)
plot.new()
tanglegram(dends_15_51, margin_outer = 1)
plot.new()
tanglegram(dends_15_51, margin_outer = 1)
```

which when knitted to HTML, would look like the following:

enter image description here

There a few modifications I made to the code:

  • Suppressed package startup messages from dendextend.
  • Increased default margin_outer to avoid overlapping x axis labels from neighbouring plots.
  • Added plot.new() in between calls to tanglegram, otherwise the next plot would be drawn on top of the previous one (this is a result of tanglegram using layout and is not needed in general when producing multiple plots).

The same approach can be used in .Rnw files. If you are compiling to PDF (via LaTeX) you can add a figure caption and subcaptions, see knitr demo #067 - Graphics Options for more detail.

Heather Turner
  • 3,264
  • 23
  • 30