向闪亮图添加超链接超链接

2023-09-06 07:30:34 作者:哪怕一路没有掌声

我制作了一个 Shiny 应用程序,使用不同的绘图解决方案在 Shiny 上渲染来自 ggplot2 的图形(我最喜欢的是 plotly).我喜欢用户可以与图形交互的事实:使用 plotly 用户可以放大图形或单击点(例如在散点图上)并访问它们的值.

我想将我的散点图上的每个点链接到一个 URL(不显示它)并允许用户单击一个点,这将触发打开一个新网页的超链接的激活.

怎样在图片上设置超链接

如果我可以使用 plotly 来做到这一点,那就太棒了,但我对任何其他类型的技术(ggvisdygraph 等)持开放态度.

解决方案

Shiny 应用使用

ui.R

库(闪亮)图书馆(情节)闪亮的UI(流体页面(主面板(plotlyOutput("趋势图"),标签$head(tags$script(src="clickhandler.js")))))

server.R

库(闪亮)图书馆(情节)x = c(1, 2, 3)y = c(4, 2, 4)链接 = c("https://plot.ly/r/",https://plot.ly/r/shiny-tutorial",https://plot.ly/r/click-events")df = data.frame(x, y, 链接)闪亮服务器(功能(输入,输出){输出$trendPlot <- renderPlotly({# 创建一个ggplotg = ggplot(data=df, aes(x = x, y = y)) + geom_point()# 序列化为 Plotly 的图形通用格式p = plotly_build(g)# 添加一个新的键,链接,JS 将在点击事件时访问p$data[[1]]$links = 链接p# 或者,使用 Plotly 的原生语法.更多信息:https://plot.ly/r# plot_ly(df, x=x,y=y,links=links)})})

www/clickhandler.js

$(document).ready(function(){//样板 postMessage 情节代码(https://github.com/plotly/postMessage-API)var plot = document.getElementById('trendPlot').contentWindow;pinger = setInterval(函数(){plot.postMessage({task: 'ping'}, 'https://plot.ly')}, 100);var clickResponse = 函数(e){plot = document.getElementById('trendPlot').contentWindow;var 消息 = e.data;console.log('来自图表的新消息', message );如果(消息.pong){//告诉嵌入的图你想监听点击事件清除间隔(pinger);plot.postMessage({任务:'听',事件:['点击']},'https://plot.ly');plot.postMessage({任务:'重新布局','更新':{hovermode:'最近的'},},'https://plot.ly');}否则 if(message.type === '点击') {var curveNumber = message['points'][0]['curveNumber'],pointNumber = message['points'][0]['pointNumber'];变种链接;var traces = message.points[0].data;if(traces !== null && typeof traces === 'object') {链接 = traces.links[pointNumber];} 别的 {链接=跟踪[曲线编号].链接[点编号];}控制台.log(链接);var win = window.open(link, '_blank');win.focus();}};window.addEventListener("消息", clickResponse, false);});

这里还有一些可能有用的资源:

使用 R 在 javascript 中添加自定义交互性以绘制图表特别是 在 JavaScript 中绑定点击事件Shiny 和 plotly 入门Plotly postMessage API 用于向托管的 plotly 图表添加自定义交互性

I have made a Shiny app using different plotting solutions to render graphs from ggplot2 on Shiny (my favorite being plotly). I like the fact that the user can interact with the graph: with plotly the user can zoom on the graph or click on points (on a scatterplot for exemple) and access their values.

I would like to link each point on my scatterplot to a URL (without displaying it) and to allow the user to click on a dot, which would trigger the activation of the hyperlink opening a new webpage.

If I could use plotly to do that that would be amazing but I am open to any other kind of technologies (ggvis,dygraph, etc.).

解决方案

Shiny apps use plotly's postMessage API or plotly.js, both of which expose click, hover, and zoom events. These events aren't yet exposed as callbacks to the underlying shiny server, but they are accessible with custom javascript that you can serve yourself in shiny.

Here's an example with click events:

ui.R

library(shiny)
library(plotly)

shinyUI(fluidPage(
  mainPanel(
    plotlyOutput("trendPlot"),
    tags$head(tags$script(src="clickhandler.js"))
  )
))

server.R

library(shiny)
library(plotly)

x = c(1, 2, 3)
y = c(4, 2, 4)
links = c("https://plot.ly/r/", 
          "https://plot.ly/r/shiny-tutorial", 
          "https://plot.ly/r/click-events")

df = data.frame(x, y, links)

shinyServer(function(input, output) {

  output$trendPlot <- renderPlotly({
    # Create a ggplot
    g = ggplot(data=df, aes(x = x, y = y)) + geom_point()
    # Serialize as Plotly's graph universal format
    p = plotly_build(g)
    # Add a new key, links, that JS will access on click events
    p$data[[1]]$links = links
    p

    # Alternatively, use Plotly's native syntax. More here: https://plot.ly/r
    # plot_ly(df, x=x,y=y,links=links)
  })
})

www/clickhandler.js

$(document).ready(function(){
// boiler plate postMessage plotly code (https://github.com/plotly/postMessage-API)
var plot = document.getElementById('trendPlot').contentWindow;

pinger = setInterval(function(){
    plot.postMessage({task: 'ping'}, 'https://plot.ly')
}, 100);

var clickResponse = function(e) {
     plot = document.getElementById('trendPlot').contentWindow;
    var message = e.data;
     console.log( 'New message from chart', message );
    if(message.pong) {
        // tell the embedded plot that you want to listen to click events
        clearInterval(pinger);
        plot.postMessage({
              task: 'listen', events: ['click']}, 'https://plot.ly');
          plot.postMessage({
            task: 'relayout',
            'update': {hovermode: 'closest'},
        },
        'https://plot.ly');
    }
    else if(message.type === 'click') {
        var curveNumber = message['points'][0]['curveNumber'],
            pointNumber = message['points'][0]['pointNumber'];

        var link;
        var traces = message.points[0].data;
        if(traces !== null && typeof traces === 'object') {
            link = traces.links[pointNumber];
        } else {
            link = traces[curveNumber].links[pointNumber];
        }

        console.log(link);

        var win = window.open(link, '_blank');
        win.focus();
    }
};

window.addEventListener("message", clickResponse, false);

});

Here are some more resources that might be helpful:

Adding custom interactivity to plotly charts in javascript with R In particular Binding to click events in JavaScript Getting started with Shiny and plotly Plotly postMessage API for adding custom interactivity to hosted plotly graphs