Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you relate ggplot2 grobs back to the data?

Tags:

r

ggplot2

r-grid

Given a ggplot of, for example, points, how would you find out the row of data that a given point corresponded to?

A sample plot:

library(ggplot2)
(p <- ggplot(mtcars, aes(mpg, wt)) +
    geom_point() +
    facet_wrap(~ gear)
)

We can get the grobs that contain points with grid.ls + grid.get.

grob_names <- grid.ls(print = FALSE)$name
point_grob_names <- grob_names[grepl("point", grob_names)]
point_grobs <- lapply(point_grob_names, grid.get)

This last variable contains details of the x-y coordinates, and pointsize, etc. (try unclass(point_grobs[[1]])), but it isn't obvious how I get the row of data in mtcars that each point corresponds to.


To answer kohske's question about why am I doing this, I'm using gridSVG to create an interactive scatterplot. When you roll the mouse over a point, I want to display contextual information. In the mtcars example, I could show a tooltip with the name of the car or other values from that row of the data frame.

My hacky idea so far is to include an id column as an invisible text label:

mtcars$id <- seq_len(nrow(mtcars))
p + geom_text(aes(label = id), colour = NA)

Then traverse the tree of grobs from the point grob to the text grob, and display the row of the dataset indexed by the label.

This is fiddly and not very generalisable. If there's a way to store the id value within the point grob, it would be much cleaner.

like image 370
Richie Cotton Avatar asked Jan 23 '12 13:01

Richie Cotton


People also ask

What are grobs ggplot?

First off a grob is just short for “grid graphical object” from the low-level graphics package grid; Think of it as a set of instructions for create a graphical object (i.e. a plot). The graphics library underneath all of ggplot2's graphical elements are really composed of grob's because ggplot2 uses grid underneath.

What is grobs?

coarse, rough. uncouth, rude, crude.


1 Answers

This script generate a SVG file wherein you can interactively annotate the points.

library(ggplot2)
library(gridSVG)

geom_point2 <- function (...) GeomPoint2$new(...)
GeomPoint2 <- proto(GeomPoint, {
  objname <- "point2"
  draw <- function(., data, scales, coordinates, na.rm = FALSE, ...) {
   data <- remove_missing(data, na.rm, c("x", "y", "size", "shape"), 
        name = "geom_point")
    if (empty(data)) 
        return(zeroGrob())
    name <- paste(.$my_name(), data$PANEL[1], sep = ".")
    with(coordinates$transform(data, scales), ggname(name,
        pointsGrob(x, y, size = unit(size, "mm"), pch = shape, 
            gp = gpar(col = alpha(colour, alpha), fill = fill, label = label,
                fontsize = size * .pt))))
  }}
  )

p <- ggplot(mtcars, aes(mpg, wt, label = rownames(mtcars))) + geom_point2() + facet_wrap(~ gear)
print(p)

grob_names <- grid.ls(print = FALSE)$name
point_grob_names <- sort(grob_names[grepl("point", grob_names)])
point_grobs_labels <- lapply(point_grob_names, function(x) grid.get(x)$gp$label)

library(rjson)
jlabel <- toJSON(point_grobs_labels)

grid.text("value", 0.05, 0.05, just = c(0, 0), name = "text_place", gp = gpar(col = "red"))

script <- '
var txt = null;
function f() {
    var id = this.id.match(/geom_point2.([0-9]+)\\.points.*\\.([0-9]+)$/);
    txt.textContent = label[id[1]-1][id[2]-1];
}

window.addEventListener("load",function(){
    var es = document.getElementsByTagName("circle");
    for (i=0; i<es.length; ++i) es[i].addEventListener("mouseover", f, false);

    txt = (document.getElementById("text_place").getElementsByTagName("tspan"))[0];

},false);
'

grid.script(script = script)
grid.script(script = paste("var label = ", jlabel))

gridToSVG()

Do you know some places I can upload SVG file?

like image 171
kohske Avatar answered Nov 15 '22 19:11

kohske