arrayQualityMetrics Figure

The arrayQualityMetrics package, authored by Audrey Kauffmann and Wolfgang Huber, can produce a report on microarray quality metrics. Within these reports is a scatterplot of principal components. The plot features interactivity by way of increasing the size of a point once it is hovered over. arrayQualityMetrics produces this plot through the use of the SVGAnnotation package.

An attempt has been made by Paul Murrell to replicate this type of plot (including interactivity) using gridSVG.

By hovering over each of the points, we are able to highlight the point by enlarging it. Not only is the point enlarged, but the name of the point is shown on the bottom-left of the plot.

How It Works

library(grid)
library(lattice)
library(gridSVG)

PC1 <- runif(10, -40, 10)
PC2 <- runif(10, -20, 20)
group <- factor(sample(c("Estrogen Receptor Negative",
                         "Estrogen Receptor Positive"),
                       10, replace=TRUE))

The way in which this example works is we first get our data and store it in the variables PC1, PC2 and group.

customPanel <- function(x, y, groups, ...) {
    grps <- levels(groups)
    for (i in 1:length(grps)) {
        index <- which(groups == grps[i])
        xx <- x[index]
        yy <- y[index]
        for (j in 1:length(xx)) {
            grid.circle(xx[j], yy[j], r = unit(1, "mm"),
                        default.unit = "native",
                        name = paste("point", index[j], sep = "."),
                        gp = gpar(col = NA,
                          fill = trellis.par.get("superpose.symbol")$col[i]))
        }
    }
}

We then define a function, customPanel(), which will drawing all of the points in the plot. We will be using a a circleGrob to draw the points because we know that it will be translated to an SVG <circle />. These circles have a naming scheme applied to them so that we can reference them later, which is simply point.[index].

xyplot(PC2 ~ PC1, group = group,
       panel = customPanel,
       key = list(rect = list(col = trellis.par.get("superpose.symbol")$col[1:2]),
                  text = list(label = levels(group))))

The lattice package’s xyplot() function is used to draw the plot. Note that we are using the customPanel function as defined earlier to draw the contents of the main panel.

for (i in 1:10) {
    grid.text(paste("ARRAY", i), x = 0.1, y = 0.01,
              just = c("left", "bottom"),
              name = paste("label", i, sep = "."),
              gp = gpar(fontface = "bold.italic"))
}

We then draw 10 of grid’s textGrobs to show the name of each of the associated points. Each of the text labels are drawn at the bottom-left of the plot. These textGrobs also have a naming scheme applied to them, the names applied are of the form label.[index].1.1 (where index is 1—10). The plot currently appears messy as several text labels are drawn on top of each other, this will be remedied later.

for (i in 1:10) {
    grid.garnish(paste("point", i, sep = "."), 
                 onmouseover = paste('highlight("', i, '.1.1")', sep = ""),
                 onmouseout = paste('dim("', i, '.1.1")', sep = ""))
    grid.garnish(paste("label", i, sep = "."),
                 visibility = "hidden")
}

Given that we know the names of each of the points (point.[index]) and each of the labels (label.[index]) we can use grid.garnish() to modify them. We want to modify the points so that they are enlarged when they are hovered over, while the text should be modified to appear only when a corresponding point is hovered over. We garnish each of the points so that when the mouse hovers over a point a JavaScript function will be called, highlight(), which will enlarge the corresponding point. highlight() takes a single parameter, the name of the element to highlight. Due to gridSVG’s grouping behaviour (see Section 4.1 of my honours report), we know that the name of each of the points is point.[index].1.1, and this is the name that is passed onto highlight(). To return each of the points to the correct size once the mouse has left a given point, we apply another JavaScript function, dim(). dim() is used similarly to highlight() and thus requires no further explanation.

Although the points have been garnished so that the highlight() and dim() functions resize points in response to mouse events, the text labels remain an issue. To resolve this, we garnish each of the labels so that when viewing the SVG file, the labels will be hidden. The highlight() and dim() functions will be used to toggle visibility of the text label.

grid.script(filename = "aqm.js", inline = TRUE)

grid.export("aqm.svg")

We then simply include a text file, in this case aqm.js, that contains JavaScript. By setting the inline argument to TRUE, we are ensuring that the JavaScript code is embedded within the SVG image, making it easier to distribute. The JavaScript file aqm.js defines the highlight() and dim() functions that we are using to perform interactivity. Once this is included, we can save the plot as SVG with grid.export().