jon
jon

Reputation: 11366

combining two plots in r

Here are two plots I intend to combine:

First is half matrix of heatmap plot. ..............................

# plot 1 , heatmap plot
set.seed (123)
 myd <- data.frame ( matrix(sample (c(1, 0, -1), 500, replace = "T"), 50))

mmat <-  cor(myd)
diag(mmat) <- NA
mmat[upper.tri (mmat)] <- NA
heatmap (mmat, keep.dendro = F, Rowv = NA, Colv = NA)

enter image description here

I need to suppress the names in x and y columns and put them in diagonal.

The second plot, please note that names / labels in first plot corresponds name in second plot (x1 to X10):

  vard <- data.frame ( position = c(1, 10, 15, 18, 20, 23, 24, 30, 35, 40), 
          Names =paste ("X", 1:10, sep = ""))
    plot(vard$position, vard$position - vard$position,
                type = "n", axes = FALSE, xlab = "", ylab = NULL, yaxt = "n")
    polygon(c(0, max(vard$position + 0.08 * max(vard$position)),
                max(vard$position) + 0.08 * max(vard$position),
                0), 0.2 * c(-0.3, -0.3, 0.3, 0.3), col = "green4")
    segments(vard$position, -0.3, vard$position,                0.3)
    text(vard$position, 0.7, vard$position,
                    srt = 90)
    text(vard$position, -0.7, vard$Names)

enter image description here

I intend rotate the first plot so that X1 to X10 should correspond to the same in the second plot and there is connection between labels in second plot to first plot. The output would look like:

enter image description here How can I do this ?

Edits: based on comments about add = TRUE....I am trying to add polygon to the heatmap plot, the like follows. But I could not find coordinates ..The strategy plot this way and flip the actual figure later...help much appreciated...

enter image description here

Upvotes: 15

Views: 2909

Answers (3)

jwc3119
jwc3119

Reputation: 109

I encountered an error in this line of code:

myd <- data.frame ( matrix(sample (c(1, 0, -1), 500, replace = "T"), 50))

Solved by replacing "T" with TRUE (No quotes)

Upvotes: 0

Josh O&#39;Brien
Josh O&#39;Brien

Reputation: 162311

Here's a fully grid-based solution. The only really involved bit is the function convertToColors(); it takes a numeric matrix (possibly including NAs) and converts it to sRGB color strings (e.g. "#FFFFFF) representing colors on a red-to-white heat.colors() scale. Red corresponds to the minimum value in the matrix, white corresponds to the maximum value, and NAs are transparent.

Other than that, I think the code does a decent job of showing how many grid functions are no more complicated, and considerably more consistent and flexible, than the low-level base graphics functions.

library(grid)

## Data: heatmap
set.seed (123)
myd <- data.frame ( matrix(sample (c(1, 0, -1), 500, replace = "T"), 50))
mmat <-  cor(myd)
diag(mmat) <- NA
mmat[upper.tri (mmat)] <- NA
## Data: Positions
vard <- c(1, 10, 15, 18, 20, 23, 24, 30, 35, 40)

## Construct a function to convert a numeric matrix to a matrix of color names.
## The lowest value in the matrix maps to red, the highest to white,
## and the NAs to "transparent".
convertToColors <- function(mat) {
    # Produce 'normalized' version of matrix, with values ranging from 0 to 1
    rng <- range(mat, na.rm = TRUE)
    m <- (mat - rng[1])/diff(rng)
    # Convert to a matrix of sRGB color strings
    m2 <- m; class(m2) <- "character"
    m2[!is.na(m2)] <- rgb(colorRamp(heat.colors(10))(m[!is.na(m)]), max = 255)
    m2[is.na(m2)] <- "transparent"
    return(m2)
}

## Initialize plot and prepare two viewports
grid.newpage()
heatmapViewport <- viewport(height=1/sqrt(2), width=1/sqrt(2), angle = -135) 
annotationViewport <- viewport(y = 0.7, height = 0.4)

## Plot heat map
pushViewport(heatmapViewport)
    grid.raster(t(convertToColors(mmat)), interpolate = FALSE)
upViewport()

## Precompute x-locations of text and segment elements
n <- nrow(mmat)
v_x <- vard/max(vard)
X_x <- seq(0, 1, len=n)

## Plot the annotated green bar and line segments
pushViewport(annotationViewport)
    ## Green rectangle
    grid.polygon(x = c(0,0,1,1,0), y = c(.45,.55,.55,.45,.45),
                 gp = gpar(fill = "green4"))
    pushViewport(viewport(width = (n-1)/n))
        ## Segments and text marking vard values
        grid.segments(x0 = v_x, x1 = v_x, y0 = 0.3, y1 = 0.7)
        grid.text(label = vard, x = v_x, y = 0.75, rot = 90)
        ## Text marking heatmap column names (X1-X10)
        grid.text(paste0("X", seq_along(X_x)), x = X_x, y=0.05,
                  gp = gpar(fontface="bold"))
        ## Angled lines
        grid.segments(x0 = v_x, x1 = X_x, y0 = 0.29, y1 = 0.09)
    upViewport()
upViewport()

enter image description here

Upvotes: 13

Josh O&#39;Brien
Josh O&#39;Brien

Reputation: 162311

This isn't really a full answer, but there are some ideas in it that might help you construct one...

Compared to the base graphical system, the grid system (on which both ggplot2 and lattice are based) has much better support for arranging multiple graphical elements in a compound plot. It uses 'viewports' to specify locations in a plot; viewports of any height, width and degree of rotation can be 'pushed' to any location within an existing plot. Then, once pushed, they can be plotted into and, finally, stepped up from so that another plot can be placed elsewhere in the main plotting area.

If this were my project, I'd probably work towards a fully grid-based solution (making liberal use of higher-level lattice or ggplot2 plots). The gridBase package, however, does provide some support for combining base and grid graphics, and I've used that in the example below.

(For more details on what I've done in the following, see the grid.pdf, viewports.pdf, and rotated.pdf vignettes located in file.path(.Library, "grid", "doc"), as well as the vignette that is opened by typing vignette("gridBase", package="gridBase")).

## Load required packages
library(lattice); library(grid); library(gridBase)

## Construct example dataset
set.seed (123)
myd <- data.frame ( matrix(sample (c(1, 0, -1), 500, replace = "T"), 50))
mmat <-  cor(myd)
diag(mmat) <- NA
mmat[upper.tri (mmat)] <- NA

## Reformat data for input to `lattice::levelplot()`
grid <- data.frame(expand.grid(x = rownames(mmat), y = colnames(mmat)), 
                   z = as.vector(mmat))

## Open a plotting device    
plot.new()     

## Push viewport that will contain the levelplot; plot it; up viewport.
pushViewport(viewport(y = 0.6, height = 0.8, width = 0.8, angle=135))
    lp <- levelplot(z~y*x, grid, colorkey=FALSE, 
                    col.regions=heat.colors(100), aspect=1,
                    scales = list(draw=FALSE), xlab="", ylab="", 
                    par.settings=list(axis.line=list(col="white")))
    plot(lp, newpage=FALSE)
upViewport()

## Push viewport that will contain the green bar; plot it; up viewport.
pushViewport(viewport(y = 0.7, height=0.2))
    # Use the gridBase::gridOMI to determine the location within the plot.
    # occupied by the current viewport, then set that location via par() call
    par(omi = gridOMI(), new=TRUE, mar = c(0,0,0,0))
    plot(0:1, 0:1,type = "n", axes = FALSE, xlab = "", ylab = "", yaxt = "n")
    polygon(x=c(0,0,1,1,0), y = c(.4,.6,.6,.4,.4), col = "green4")
upViewport()

enter image description here

Upvotes: 11

Related Questions