我想以交互方式在ggplot中标记点,以便鼠标悬停在一个点上显示标签。
我正在尝试调整this question中给出的答案,以便它可以在最新版本的ggplot2中运行。受ggplot google组here的评论影响,我使用最新版本的geom-point-.r作为模板,在各个地方的gp参数中添加了“label”字段。然后我从kohske的答案中复制了剩下的代码。但它不起作用 - 结果svg中没有任何标签,我无法弄清楚原因。
我注意到point_grobs_labels
中的所有内容都为空,当我查看grid.get(point_grob_names[1])$gp
时,没有标签字段...
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()
答案 0 :(得分:12)
试试这个:
library(ggplot2)
library(gridSVG)
library(proto)
library(rjson)
mtcars2 <- data.frame(mtcars, names = rownames(mtcars))
geom_point2 <- function (...) {
GeomPoint2$new(...)
}
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())
name <- paste(.$my_name(), data$PANEL[1], sep = ".")
with(coord_transform(coordinates, data, scales),
ggname(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(mtcars2, aes(mpg, wt, label = names)) + 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_point.([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 = paste("var label = ", jlabel))
grid.script(script = script)
gridToSVG()
没有太大的变化,但我不得不添加
mtcars2 <- data.frame(mtcars, names = rownames(mtcars))
然后
p <- ggplot(mtcars, aes(mpg, wt, label = rownames(mtcars)))
+ geom_point2() + facet_wrap(~ gear)
也改为
p <- ggplot(mtcars2, aes(mpg, wt, label = names))
+ geom_point2() +facet_wrap(~ gear)
因为我们有rownames(mtcars)
rownames(mtcars)
[1] "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive"
[5] "Hornet Sportabout" "Valiant" "Duster 360" "Merc 240D"
[9] "Merc 230" "Merc 280" "Merc 280C" "Merc 450SE"
.....
然后标签(我们设法通过其他修改获得)保持不变,即不由gears
重新排列,仅由它分割:
point_grobs_labels
[[1]]
[1] "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive"
[5] "Hornet Sportabout" "Valiant" "Duster 360" "Merc 240D"
[9] "Merc 230" "Merc 280" "Merc 280C" "Merc 450SE"
[13] "Merc 450SL" "Merc 450SLC" "Cadillac Fleetwood"
[[2]]
....
但将这些标签名称作为列可以解决问题。
point_grobs_labels
[[1]]
[1] "Hornet 4 Drive" "Hornet Sportabout" "Valiant" "Duster 360"
[5] "Merc 450SE" "Merc 450SL" "Merc 450SLC" "Cadillac Fleetwood"
[9] "Lincoln Continental" "Chrysler Imperial" "Toyota Corona" "Dodge Challenger"
[13] "AMC Javelin" "Camaro Z28" "Pontiac Firebird"
[[2]]
....
答案 1 :(得分:1)
感谢Tracy提出了一个很好的问题,感谢Julius提供了非常有用的答案。
要让我在Chrome和Safari中使用Julius的javascript,我必须将this.id
替换为this.correspondingUseElement.id
。这是有道理的,因为单个<circle>
SVG元素没有每个geom_point的id,我们想要的id附加到<use>
元素。
即使这在我的Firefox中也不起作用,所以我将其更改为将事件监听器附加到<use>
元素本身。请注意,如果SVG更复杂,它可能除了geom_points之外还有<use>
,因此我添加了if
仅将事件附加到geom_point.XX <use>
元素。这适用于Chrome,Safari和Firefox:
window.addEventListener("load",function(){
var es = document.getElementsByTagName("use");
for (i=0; i<es.length; ++i) {
if(es[i].id.search(/geom_point.([0-9]+)\.points.*\.([0-9]+)$/) >= 0) es[i].addEventListener("mouseover", f, false);
}
txt = (document.getElementById("text_place").getElementsByTagName("tspan"))[0];
},false);
(所有其他代码与Julius相同)
答案 2 :(得分:0)
我们通过检测生成的.svg中的颜色属性并使用css检测鼠标悬停来解决这个问题。结果显示在本演示的步骤4,5,6中:
Showing svg highlighting using css
这是我的第一个stackoverflow响应 - 希望我得到正确的礼仪
答案 3 :(得分:0)
这是一个一般性的答案。我只是在这里帮助您使剧情互动。您可以尝试-
library(ggplot2)
library(plotly)
# Plot how you would normally code for ggplot2
p <- ggplot(data,... 'add your variables and subsequent plots')
ggplotly(p)
享受!