Adding a matrix to a plot? - r

Is there anyway to add a table to a plot. Suppose that I have the plot below:
curve(dnorm, -3, +4)
Now I like to add a matrix beneath the plot:
testMat <- matrix(1:20, ncol = 5)
My goal? I'm writing a plot function that not only does create a plot, but it also shows a matrix including the information I'm interested in underneath the plot.
Please see the attached picture to see what I mean.
I really appreciate your help.

There are probably better ways to do this, but one option might be to use one of the packages that "plots" matrices and data frames, like the "gplots" package.
Here is a very bare example (you can probably customize this for much finer control over the final layout).
# Some sample data
testMat <- matrix(1:20, ncol = 5)
testMatDF <- as.data.frame(testMat)
names(testMatDF) <- c("Hey there", "Column 2",
"Some * Symbols", "And ^ More",
"Final Column")
rownames(testMatDF) <- paste("Group", 1:4)
# Load the package
library(gplots)
# Set par for plotting a three-row plot
par(mfrow = c(3, 1))
curve(dnorm, -3, +4)
textplot(testMat)
textplot(testMatDF)
The result:
You can also use layout() instead of par(mfrow...) if you want to get a little bit more creative with the placement of your plots. For example:
layout(matrix(c(1, 1, 2, 3, 3, 3),
2, 3, byrow = TRUE))
curve(dnorm, -3, +4)
textplot(testMat)
textplot(testMatDF)

Package plotrix provides function addtable2plot.
Example from the help file:
library(plotrix)
testdf<-data.frame(Before=c(10,7,5),During=c(8,6,2),After=c(5,3,4))
rownames(testdf)<-c("Red","Green","Blue")
barp(testdf,main="Test addtable2plot",ylab="Value",
names.arg=colnames(testdf),col=2:4)
# show most of the options
addtable2plot(2,8,testdf,bty="o",display.rownames=TRUE,hlines=TRUE,
title="The table")
Edit:
Put the table in a new plot to place it underneath your plot.
library(plotrix)
layout(matrix(c(1,2), 2, 1, byrow = TRUE),
widths=c(1,1), heights=c(2,1))
testdf<-data.frame(Before=c(10,7,5),During=c(8,6,2),After=c(5,3,4))
rownames(testdf)<-c("Red","Green","Blue")
barp(testdf,main="Test addtable2plot",ylab="Value",
names.arg=colnames(testdf),col=2:4)
plot.new()
addtable2plot(0,0,testdf,bty="o",display.rownames=TRUE,hlines=TRUE,
title="The table")

Related

leaf and stem diagram incompatible with the layout function

I am trying to join 4 graphs with the layout function. However, I only get 3 represented: all except the stem and leaf diagram.
In brief, this is what it looks like in r:
layout(matrix(c(1,2,3,4), 2, 2, byrow =TRUE))
stem(graph1)
boxplot(graph2)
hist(graph3)
barplot(graph4)
Why doesn't the stem graph plot the same as the others, and is there another function that can do it?
Thank you in advance
As #DaveArmstrong already hinted, stem outputs characters, which are printable but not plotable.
You could redirect the output from stem to a plot like so (shamelessly stolen from this SO answer):
layout(matrix(c(1,2,3,4), 2, 2, byrow =TRUE))
## start stem-plot
plot.new()
tmp <- capture.output(stem(c(10,11,20:23)))
text( 0,1, paste(tmp, collapse='\n'), adj=c(0,1), family='mono' )
## end stem-plot
boxplot(runif(100))
hist(rnorm(100))
barplot(1:3)

R: keeping axis labels and scales when plotting multiple graphs

I am using the following formula to plot 5 graphs together :
my_data <- as.data.frame(datasets::volcano)
layout(matrix(c(1,2,3,4,5,6), 3, 2, byrow = TRUE))
par(mar=c(1,1,1,1))
plot(my_data$V1, my_data$V2)
plot(my_data$V3, my_data$V4)
plot(my_data$V5, my_data$V6)
plot(my_data$V7, my_data$V8)
plot(my_data$V9, my_data$V10)
plot.new()
It works well but I loose the scale of the y-axis of the 1, 3 and 5th plots and the x-axis of the latter. This keeps happening for any future ones I do until I dev.off().
Thanks!
You can use par(mfrow = c(3, 2)) and adjust your margins. You may need to increase the size of your window to accommodate the plot
my_data <- as.data.frame(datasets::volcano)
par(mfrow = c(3, 2))
par(mar = c(2, 2, 2, 2))
plot(my_data$V1, my_data$V2)
plot(my_data$V3, my_data$V4)
plot(my_data$V5, my_data$V6)
plot(my_data$V7, my_data$V8)
plot(my_data$V9, my_data$V10)
In addition to #AllanCameron's solution—I'd keep layout in mind, since it can be very useful! Also you may want to regard the RStudio "Plots" window as a preview tool. Better save your plots with pdf or png as shown below; the plot will be saved in your getwd(). In addition you may avoid the repeated plot call by creating a sub.cols data frame which can be looped by an sapply.
my_data <- as.data.frame(datasets::volcano)
sub.cols <- as.data.frame(matrix(1:10, 2))
png("myPlot01.png", width=400, height=600)
layout(matrix(1:6, 3, 2, byrow=TRUE))
op <- par(mar=c(4.5, 2.5, 1.5, 1.5)) ## set par and store old par
sapply(sub.cols, function(i) plot(my_data[i]))
plot.new()
par(op) ## restore old par
dev.off()
If the soiled console annoys you you can do invisible(sapply(.)) above.

Arrange base plots and grid.tables on the same page

I have 2 plots (created using Base graphics) and 2 data frames that I would like to combine onto one sheet in a PDF. I'm using grid.table to create a tableGrobs from my data frames. I'm having a lot of difficulty formatting the PDF output. In particular, I've been unsuccessful keeping all the objects on the same page. I want the right pannel to contain one graph, and the left panel to contain the other graph, and 2 tables below (landscape format).
Currently my code is something like the following:
library('gridExtra')
pdf("Rplots.pdf", paper = "USr", height = 8.5, width = 11)
layout(matrix(c(1,3, 2,3, 4,3), nrow = 3, ncol = 2, byrow = TRUE))
plot(myPlot1)
grid.table(df1)
plot(myPlot2)
grid.table(df2)
dev.off()
I do not want to use ggplot2.
To combine base plots and grid objects the package gridBase is useful.
A rough worked example base on your layout above
library(grid)
library(gridBase)
library(gridExtra)
layout(matrix(c(1,3, 2,3, 4,3), nrow = 3, ncol = 2, byrow = TRUE))
# First base plot
plot(1:10)
# second base plot
frame()
# Grid regions of current base plot (ie from frame)
vps <- baseViewports()
pushViewport(vps$inner, vps$figure, vps$plot)
# Table grob
grob <- tableGrob(iris[1:2,1:2])
grid.draw(grob)
popViewport(3)
# third base plot
plot(1:10)
# fourth
frame()
vps <- baseViewports()
pushViewport(vps$inner, vps$figure, vps$plot)
grid.draw(grob)
popViewport(3)
Which gives

Combine phylogenetic tree with x,y graph

I'm trying to arrange a phylogenetic tree onto a graph showing physiological data for a set of related organisms. Something like the picture below. This was put together in powerpoint from 2 separate graphs. I guess it gets the job done, but I was hoping to create a single image which I think will be easier to format into a document. I am able to produce the graph I want using ggplot2, and import the tree using ape. I was thinking there should be a way to save the tree as a graphical object and then arrange it with the graph using the gridarrange function in gridExtra. The problem is that ape won't let me save the tree as a graphical object, e.g.,
p2<-plot(tree, dir = "u", show.tip.label = FALSE)
just plots the tree and when you call p2 it just gives a list of arguments. I'm wondering if anyone has any tips.
Thanks!
I'm not sure if that will work with gtable from CRAN
require(ggplot2)
require(gridBase)
require(gtable)
p <- qplot(1,1)
g <- ggplotGrob(p)
g <- gtable_add_rows(g, unit(2,"in"), nrow(g))
g <- gtable_add_grob(g, rectGrob(),
t = 7, l=4, b=7, r=4)
grid.newpage()
grid.draw(g)
#grid.force()
#grid.ls(grobs=F, viewports=T)
seekViewport("layout.7-4-7-4")
par(plt=gridPLT(), new=TRUE)
plot(rtree(10), "c", FALSE, direction = "u")
upViewport()
first I'd like to thanks baptiste for ALL his multiple answers that solved most of my issues with ggplot2.
second, I had a similar question which was to include a tree from ape inside a heatmap obtained with ggplot2. Baptiste made my day, and though my simplified version could help.
I used only what was useful for me (removing the addition of gg_rows).
library(ape)
tr <- read.tree("mytree.tree")
# heat is the heatmap ggplot, using geom_tile
g <- ggplotGrob(heat)
grid.newpage()
grid.draw(g)
# use oma to reduce the tree so it fits
par(new = TRUE, oma = c(5, 4, 5, 38))
plot(tr)
nodelabels(tr$node.label, cex = 1, frame = "none", col = "black", adj = c(-0.3, 0.5))
add.scale.bar()
# use dev.copy2pdf and not ggsave
dev.copy2pdf(file = "heatmap_prob.pdf")
the result is here

to display two heatmaps in same pdf side by side in R

i am trying to display two or more heatmaps side by side in the same png or pdf . The layout or mfcol is not working in the case. Can someone please help me out with this.
Here's one option using the recently introduced gridGraphics package,
library(gridGraphics)
library(grid)
heatmap(as.matrix(mtcars))
library(gridGraphics)
grab_grob <- function(){
grid.echo()
grid.grab()
}
g <- grab_grob()
grid.newpage()
# library(gridExtra)
# grid.arrange(g,g, ncol=2, clip=TRUE)
lay <- grid.layout(nrow = 1, ncol=2)
pushViewport(viewport(layout = lay))
grid.draw(editGrob(g, vp=viewport(layout.pos.row = 1,
layout.pos.col = 1, clip=TRUE)))
grid.draw(editGrob(g, vp=viewport(layout.pos.row = 1,
layout.pos.col = 2, clip=TRUE)))
upViewport(1)
As stated in the help document for heatmap.2,
'heatmap.2()' uses 'layout' and draws the 'image' in the lower
right corner of a 2x2 layout. Consequentially, it can not be
used in a multi column/row layout, i.e., when 'par(mfrow= *)' or
'(mfcol= *)' has been called.
The same is true for heatmap.
Here's a way of doing that. It is very hacky but I think that when a function doesn't do what you want to do the best solution is to make it do it anyway.
Function heatmap.2 contains the following three lines at mid-way through its code:
...
op <- par(no.readonly = TRUE)
on.exit(par(op))
layout(lmat, widths = lwid, heights = lhei, respect = FALSE)
...
It is because of them that you can't use layout and par(mar=...) since it overrides it.
Copy the code of heatmap.2 into a new function (say heatmap.3) and remove those three lines:
heatmap.3 <- function(... #etc etc with the exact same code minus those 3 lines
Then your code to produce your two heatmaps side by side will be, for instance:
layout(rbind(c(4,3,8,7),c(2,1,6,5)),
widths = c(1,2,1,2), heights = c(1,2), respect = FALSE)
heatmap.3(x)
heatmap.3(y)
When preparing your layout remember that the heatmap code plot first the heatmap itself, then the "row" dendrogram, then the "col" dendrogram and finally the histogram, hence the order from top to bottom, left to right is 4, 3, 2, 1 meaning when both heatmap are side by side it becomes 4, 3, 8, 7, 2, 1, 6, 5.
After having exactly the same problem, I came up with the following solution:
1) Use ggplot2 to make your heatmap with dendrogram like here: Reproducing lattice dendrogram graph with ggplot2 and then arrange it with multiplot() function (http://www.cookbook-r.com/Graphs/Multiple_graphs_on_one_page_%28ggplot2%29/)
2) However, this is a lot of work and I wanted to stick with the base heatmap() function. The following is easy (though not plain R) and works on Linux if you have imagemagick installed:
m <- matrix(runif(10^2), ncol=10)
for (i1 in 1:4) {
ifile <- paste0(i1,'_heatmap.pdf')
pdf(ifile)
heatmap(m)
d <- dev.off()
}
system('montage -geometry 100% -tile 2x2 ./*_heatmap.pdf outfile.pdf')

Resources