在 plotly 弹出窗口中放置图表
问题描述
我正在为 R 使用 plotly,尽管我也愿意使用 Python 版本.当我将鼠标悬停在数据点上时,有没有办法让弹出窗口包含另一个图表?理想情况下,图表将根据数据创建,尽管我可以使用静态图像作为后备.
I'm using plotly for R, although I'm open to using the Python version, as well. When I hover over a datapoint, is there a way to make the popup contain another chart? Ideally the chart would be created from the data, although I can use a static image as a fallback.
我不确定从哪里开始,并为没有 MWE 提前道歉.
I'm unsure where to start on this, and apologize in advance for not having an MWE.
解决方案
解决方案一:坚持R
感谢@MLavoie.以下示例使用纯 R
创建两个图,主图"和悬停",它对第一个的悬停事件做出反应.
Solution 1: Stick to R
Thanks to @MLavoie. The following example use pure R
to create two plot, the "mainplot" and the "hover" which reacts to the hover event of the first one.
library(shiny)
library(plotly)
ui <- fluidPage(
plotlyOutput("mainplot"),
plotlyOutput("hover")
)
server <- function(input, output) {
output$mainplot <- renderPlotly({
# https://plot.ly/r/
d <- diamonds[sample(nrow(diamonds), 1000), ]
plot_ly(d, x = carat, y = price, text = paste("Clarity: ", clarity), mode = "markers", color = carat, size = carat, source="main")
})
output$hover <- renderPlotly({
eventdat <- event_data('plotly_hover', source="main") # get event data from source main
if(is.null(eventdat) == T) return(NULL) # If NULL dont do anything
point <- as.numeric(eventdat[['pointNumber']]) # Index of the data point being charted
# draw plot according to the point number on hover
plot_ly( x = c(1,2,3), y = c(point, point*2, point*3), mode = "scatter")
})
}
shinyApp(ui, server)
本示例使用 shiny binds for plotly代码>.对于每个悬停事件,都会向服务器发送一个
POST
请求,然后服务器将更新弹出图表.它的效率非常低,因此在慢速连接时可能无法正常工作.
This example use the shiny binds for plotly
. For every hover event, a POST
request is sent to the server, then the server will update the popup-chart. It's very inefficient thus may not work well on slow connections.
以上代码仅用于演示,尚未测试.here 查看一个更复杂的工作示例(使用 来源).
The above code is just for demo, and not yet tested. See a working and much more complicated example here (with source).
是的,您可以使用 plotly Javascript API 来实现.
Yes, you can do it using the plotly Javascript API.
- 使用
R
或Python
或任何其他支持的语言创建图表. - 将图表插入新的 HTML 页面并添加回调函数,如下例所示.如果你对 DOM 有很好的了解,也可以将 JS 添加到原始 HTML而不是创建一个新的.
- 在回调函数内绘制弹出图,该函数接受包含悬停数据点数据的参数.
- Create your graph using
R
orPython
or any other supported language. - Insert the graph into a new HTML page and add a callback function as shown in the example below. If you have good knowledge about DOM, you can also add the JS to the original HTML instead of creating a new one.
- Draw the popup graph inside the callback function which accepts parameters containing the data of the datapoint on-hover.
详情
正如@MLavoie 提到的,一个很好的例子显示在 plotly.hover-events
让我们深入研究代码.在JS文件中,有一个简单的回调函数附在Plot
上:
Let's dig into the code. In the JS file, there is a simple callback function attached to Plot
:
Plot.onHover = function(message) {
var artist = message.points[0].x.toLowerCase().replace(/ /g, '-');
var imgSrc = blankImg;
if(artistToUrl[artist] !== undefined) imgSrc = artistToUrl[artist];
Plot.hoverImg.src = imgSrc;
};
上面,artistToUrl
是一个巨大的对象,里面填充了 base64 字符串,我不会粘贴到这里来溢出帖子.但是您可以在示例页面的 JS 选项卡下看到它.它有这样的结构:
Above, artistToUrl
is a huge object filled with base64 string which I will not paste here to overflow the post. But you can see it under the JS tab of the example page. It has such structure:
var artistToUrl = { 'bob-dylan': 'data:image/jpeg;base64,/...',...}
工作示例:
为了演示,我准备了一个简单的例子这里(点击试试):
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>
<iframe id="plot" style="width: 900px; height: 600px;" src="https://plot.ly/~jackp/10816.embed" seamless></iframe>
<div id="myDiv"></div>
<script>
(function main() {
var Plot = { id: 'plot', domain: 'https://plot.ly' };
Plot.onHover = function(message) {
var y = message.points[0].y; /*** y value of the data point(bar) under hover ***/
var line1 = {
x: [0.25,0.5,1], /*** dummy x array in popup-chart ***/
y: [1/y, 2, y], /*** dummy y array in popup-chart ***/
mode: 'lines+markers'
};
var layout = {
title:'Popup graph on hover',
height: 400,
width: 480
};
Plotly.newPlot('myDiv', [ line1 ], layout); // this finally draws your popup-chart
};
Plot.init = function init() {
var pinger = setInterval(function() {
Plot.post({task: 'ping'});
}, 500);
function messageListener(e) {
var message = e.data;
if(message.pong) {
console.log('Initial pong, frame is ready to receive');
clearInterval(pinger);
Plot.post({
'task': 'listen',
'events': ['hover']
});
}
else if(message.type === 'hover') {
Plot.onHover(message);
}
}
window.removeEventListener('message', messageListener);
window.addEventListener('message', messageListener);
};
Plot.post = function post(o) {
document.getElementById(Plot.id).contentWindow.postMessage(o, Plot.domain);
};
Plot.init();
})();
</script>
</body>
</html>
这是从 Python 的 poltly.hover-events 示例修改而来的.我没有弹出图像,而是更改了 onhover
回调以根据每个条形的 y
值绘制曲线.
This is modified from the poltly.hover-events example for python. Instead of poping up an image, I change the onhover
callback to plot a curve based on the y
value of the each bar.
主图表由python生成并作为iframe
插入此处.你可以用任何语言制作你自己的,包括R
.在这个页面中,我们添加一个 <div id="myDiv"></div>
并使用 plotly.js 在其中绘制弹出图表.
The main chart is generated by python and inserted here as iframe
. You can make your own by any language including R
. In this page we add a <div id="myDiv"></div>
and use the plotly.js to draw the popup-chart whithin it.
Shiny 使用 jsonlite 进行转换R
对象到 json
并将它们发送到客户端.我们可以使用相同的机制来打包和发送我们的数据帧,以便 JS 回调可以使用数据来渲染弹出图表.
Shiny uses jsonlite to convert R
objects to json
and send them to the client. We can use the same mechanism to pack and send our data frame so that the JS callback can use the data to render the popup chart.
服务器.r
output$json <- reactive({
paste('<script>data =', RJSONIO::toJSON(your_data_frame, byrow=T, colNames=T),'</script>')
ui.r
fluidPage(..., htmlOutput("json"), ...)
在 JS 回调函数中,您可以像使用任何其他 JS 对象一样使用 data
.
In the JS callback function, you can use data
as any other JS objects.
更多详细信息请参见此处和这里.
More detail goes here and here.
相关文章