I’d like to label points in a ggplot interactively, so that mousing over a point shows a label.
I’m trying to adapt the answer given in this question so that it works in the latest version of ggplot2. Influenced by comments on the ggplot google group, here, I used the latest version of geom-point-.r as a template, adding a “label” field to the gp argument in various places. Then I copied the remaining code from kohske’s answer. But it doesn’t work — there aren’t any labels in the resulting svg, and I can’t figure out why.
I did notice that everything in point_grobs_labels is null, and when I look at grid.get(point_grob_names[1])$gp, there is no label field…
library(ggplot2)
library(gridSVG)
library(proto)
library(rjson)
geom_point2 <- function (mapping = NULL, data = NULL, stat = "identity",
position = "identity",
na.rm = FALSE, ...) {
ggplot2:::GeomPoint$new(mapping = mapping, data = data, stat = stat,
position = position,
na.rm = na.rm, ...)
}
GeomPoint2 <- proto(ggplot2:::Geom, {
objname <- "point"
draw_groups <- function(., ...) .$draw(...)
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())
with(coord_transform(coordinates, data, scales),
ggname(.$my_name(), pointsGrob(x, y, size=unit(size, "mm"), pch=shape,
gp=gpar(
col=alpha(colour, alpha),
fill = alpha(fill, alpha),
label = label,
fontsize = size * .pt)))
)
}
draw_legend <- function(., data, ...) {
data <- aesdefaults(data, .$default_aes(), list(...))
with(data,
pointsGrob(0.5, 0.5, size=unit(size, "mm"), pch=shape,
gp=gpar(
col = alpha(colour, alpha),
fill = alpha(fill, alpha),
label = label,
fontsize = size * .pt)
)
)
}
default_stat <- function(.) StatIdentity
required_aes <- c("x", "y")
default_aes <- function(.) aes(shape=16, colour="black", size=2,
fill = NA, alpha = NA, label = NA)
})
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)
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()
Try this:
there were no big changes, but I had to add
and then
also changes to
because we have
rownames(mtcars)and then labels (which we manage to get with other modifications) remain the same, i.e. not rearranged by
gears, only split by it:but having these label names as a column fixes the problem.