如何从R plotly图形中获取坐标

Posted

技术标签:

【中文标题】如何从R plotly图形中获取坐标【英文标题】:How to get coordinates from a R plotly figure 【发布时间】:2018-02-19 19:38:57 【问题描述】:

我一直在疯狂地努力解决一个看似基本的问题。 想象一下,你有一个散点图,比如说... 10 个标记。 我想这个图是在 Shiny 环境中使用 plotly 生成的。

使用event_data("plotly_click") 代码可以轻松获取这些标记的坐标。

现在假设您不需要这些标记的坐标,而是通过鼠标单击生成的坐标,但恰好在不存在标记的位置(例如,因为您想在那里设置一个新标记,并且您想重新- 使用来自该鼠标点击的信息)。

我无法使用onclick() 或其他方式获得这种行为。

有什么想法吗?

【问题讨论】:

您是否需要相对的 Plotly 坐标,即您在轴上看到的坐标?还是只是用户单击以创建新的 SVG 元素的位置?您想将您的观点添加到 Plotly 数据中吗? 实际上我想在用户点击的地方添加一个新点,并能够使用坐标来处理新的计算。任何这样做的解决方案都将不胜感激。谢谢 为了更直接,我需要在轴上看到的相对 Plotly 坐标。 这是一个棘手的问题。屏幕坐标比较简单。 【参考方案1】:

您可以在情节中添加 D3 事件侦听器

Plotly.d3.select('.plotly').on('click', function(d, i) )

然后

根据点击位置(d3.event.layerX resp. layerY)检索相对的 x 和 y 值 调整相对图表位置 (document.getElementsByClassName('bg')[0].attributes['x']) 最后根据坐标轴范围计算新值 (myPlot.layout.xaxis.range[0])

然后将新的xy 值推送到现有图表

Plotly.extendTraces(myPlot, 
      x: [[x]],
      y: [[y]]
    , [1]);

完整的 R 代码

library("plotly")
library("htmlwidgets")

p <- plot_ly(x = c( -2, 0, 2 ),y = c( -2, 1, 2), type = 'scatter' ,mode = 'lines+markers') %>% 
  add_trace(x=c(-1,0.4,2),y=c(2, 0, -1),type='scatter',mode='lines+markers') %>% 
  layout(hovermode='closest')
javascript <- "
var myPlot = document.getElementsByClassName('plotly')[0];
Number.prototype.between = function (min, max) 
  return this >= min && this <= max;
;

Plotly.d3.select('.plotly').on('click', function(d, i) 
  var e = Plotly.d3.event;
  var bg = document.getElementsByClassName('bg')[0];
  var x = ((e.layerX - bg.attributes['x'].value + 4) / (bg.attributes['width'].value)) * (myPlot.layout.xaxis.range[1] - myPlot.layout.xaxis.range[0]) + myPlot.layout.xaxis.range[0];
    var y =((e.layerY - bg.attributes['y'].value + 4) / (bg.attributes['height'].value)) * (myPlot.layout.yaxis.range[0] - myPlot.layout.yaxis.range[1]) + myPlot.layout.yaxis.range[1]
  if (x.between(myPlot.layout.xaxis.range[0], myPlot.layout.xaxis.range[1]) && 
y.between(myPlot.layout.yaxis.range[0], myPlot.layout.yaxis.range[1])) 
    Plotly.extendTraces(myPlot, 
      x: [[x]],
      y: [[y]]
    , [1]);
  
);"
p <- htmlwidgets::prependContent(p, onStaticRenderComplete(javascript), data=list(''))
p

交互式 Javascript 示例

var traces = [
  x: [1, 2, 3, 4],
  y: [10, 15, 13, 17],
  mode: 'markers',
  type: 'scatter'
];

traces.push(
  x: [2, 3, 4, 5],
  y: [16, 5, 11, 9],
  mode: 'markers',
  type: 'scatter'
);

traces.push(
  x: [1, 2, 3, 4],
  y: [12, 9, 15, 12],
  mode: 'markers',
  type: 'scatter'
);

traces.push(
  x: [],
  y: [],
  mode: 'lines+markers',
  type: 'scatter'
);

var myPlot = document.getElementById('myPlot')
Plotly.newPlot('myPlot', traces, hovermode: 'closest');

Number.prototype.between = function(min, max) 
  return this >= min && this <= max;
;

Plotly.d3.select(".plotly").on('click', function(d, i) 
  var e = Plotly.d3.event;
  var bg = document.getElementsByClassName('bg')[0];
  var x = ((e.layerX - bg.attributes['x'].value + 4) / (bg.attributes['width'].value)) * (myPlot.layout.xaxis.range[1] - myPlot.layout.xaxis.range[0]) + myPlot.layout.xaxis.range[0];
  var y = ((e.layerY - bg.attributes['y'].value + 4) / (bg.attributes['height'].value)) * (myPlot.layout.yaxis.range[0] - myPlot.layout.yaxis.range[1]) + myPlot.layout.yaxis.range[1]
  if (x.between(myPlot.layout.xaxis.range[0], myPlot.layout.xaxis.range[1]) &&
    y.between(myPlot.layout.yaxis.range[0], myPlot.layout.yaxis.range[1])) 
    Plotly.extendTraces(myPlot, 
      x: [
        [x]
      ],
      y: [
        [y]
      ]
    , [3]);
  
);
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<div id="myPlot" style="width:100%;height:100%"></div>

闪亮的例子

library(shiny)
library("plotly")
library("htmlwidgets")

ui <- fluidPage(
  plotlyOutput("plot")
)

server <- function(input, output) 
   javascript <- "
function(el, x)
  Number.prototype.between = function (min, max) 
   return this >= min && this <= max;
  ;

  Plotly.d3.select('.plotly').on('click', function(d, i) 
  var e = Plotly.d3.event;
  var bg = document.getElementsByClassName('bg')[0];
  var x = ((e.layerX - bg.attributes['x'].value + 4) / (bg.attributes['width'].value)) * (el.layout.xaxis.range[1] - el.layout.xaxis.range[0]) + el.layout.xaxis.range[0];
  var y =((e.layerY - bg.attributes['y'].value + 4) / (bg.attributes['height'].value)) * (el.layout.yaxis.range[0] - el.layout.yaxis.range[1]) + el.layout.yaxis.range[1]
  if (x.between(el.layout.xaxis.range[0], el.layout.xaxis.range[1]) && y.between(el.layout.yaxis.range[0], el.layout.yaxis.range[1])) 
    Plotly.extendTraces(el, 
     x: [[x]],
     y: [[y]]
    , [1]);
  
);
"
  output$plot <- renderPlotly(
    plot_ly(x = c( -2, 0, 2 ),y = c( -2, 1, 2), type = 'scatter' ,mode = 'lines+markers') %>% 
    add_trace(x=c(-1,0.4,2),y=c(2, 0, -1),type='scatter',mode='lines+markers') %>% 
    layout(hovermode='closest') %>% onRender(javascript)
  )


shinyApp(ui = ui, server = server)

【讨论】:

谢谢马克西米利安,它工作得很好......但不是在闪亮的环境中。我相信这是因为在 Shiny 小部件呈现内容中不支持 prependContent()。 对于闪亮的你需要用function(el, x) ... 包装JS 代码并在调用你的plotly 函数的地方使用%&gt;% onRender(javascript)。 -- 查看更新的答案 完美运行。马克西米利安:这一切只需要一个词=> 精彩。非常感谢您的帮助。【参考方案2】:

Maximilian 的解决方案不适用于 1.42.0 之后的 Plotly.js 版本。正在尝试获取

var bg = document.getElementsByClassName('bg')[0];

返回未定义。该解决方案适用于 1.41.3 版本。

这个答案很可能更适合作为评论,但我的声誉不符合 50 的最低要求。

【讨论】:

感谢您的信息!刚刚检查了 R 中的最新 Plotly 版本,代码仍然有效,与 *** 之外的 Plotly.js 相同。似乎是代码如何嵌入 *** 的问题。

以上是关于如何从R plotly图形中获取坐标的主要内容,如果未能解决你的问题,请参考以下文章

如何从图形 Canvas 类中获取坐标? [复制]

r中怎么删除图形坐标值

如何从graphviz的布局中获取坐标?

如何用python按顺序获取一个线条组成的图形的点坐标

Plotly:将多个图形绘制为子图

如何获取图形工具中特定布局算法绘制的图形的坐标?