You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Shiny响应式Plotly中获取可拖拽线段的完整两点坐标

问题:获取Plotly可拖拽线段的完整端点坐标

我在Shiny响应式环境中使用Plotly创建支持任意方向拖拽的线段图形,但通过plotly::event_data("plotly_relayout")只能获取到线段单个端点的更新坐标,无法拿到线段两个端点的完整位置信息。

用到的基础代码

创建可拖拽线段的Plotly图形代码:

library(plotly)
plot_ly(data, x = ~x, y = ~y, type = 'scatter') %>%
    layout(shapes = list(
                    # 示例任意方向线段
                    list(type = "line", x0 = 10, x1 = 50, 
                            y0 = 5, y1 = 25)
                    )) %>%
    config(edits = list(shapePosition = TRUE))

获取编辑事件数据的代码:

newData <- plotly::event_data("plotly_relayout")
print(newData)

当前遇到的问题

执行后仅能得到单个端点的更新值,示例输出:

$`shapes[0].x1`
[1] 80.65517

$`shapes[0].y1`
[1] 2.232316

解决方案

核心思路是在Shiny中维护线段的完整状态,结合plotly_relayout返回的增量更新,拼接出所有端点的完整坐标。

具体实现代码

library(plotly)
library(shiny)
library(stringr)

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

server <- function(input, output) {
  # 初始化线段状态,与plot中shapes的初始配置完全对应
  line_states <- reactiveVal(list(
    list(x0 = 10, x1 = 50, y0 = 5, y1 = 25)  # 可添加多条线段
  ))
  
  output$plot <- renderPlotly({
    plot_ly(data, x = ~x, y = ~y, type = 'scatter') %>%
      layout(shapes = lapply(line_states(), function(line) {
        list(type = "line", x0 = line$x0, x1 = line$x1, y0 = line$y0, y1 = line$y1)
      })) %>%
      config(edits = list(shapePosition = TRUE))
  })
  
  # 监听线段拖拽事件,更新完整状态
  observeEvent(plotly::event_data("plotly_relayout"), {
    relayout_data <- plotly::event_data("plotly_relayout")
    current_lines <- line_states()
    
    # 解析更新的线段索引和属性
    for (key in names(relayout_data)) {
      match_res <- str_match(key, "shapes\\[(\\d+)\\]\\.(x0|x1|y0|y1)")
      if (!is.na(match_res[1])) {
        line_idx <- as.integer(match_res[2]) + 1  # 转换为R的1起始索引
        attr_name <- match_res[3]
        current_lines[[line_idx]][[attr_name]] <- relayout_data[[key]]
      }
    }
    
    # 更新状态,触发图形重绘
    line_states(current_lines)
    
    # 查看完整的线段坐标
    cat("当前所有线段的完整端点坐标:\n")
    print(current_lines)
  })
}

shinyApp(ui, server)

关键说明

  1. 用reactiveVal存储所有线段的完整坐标,初始值必须与layout(shapes)的配置完全一致
  2. 通过stringr解析plotly_relayout返回的键名(如shapes[0].x1),匹配对应的线段索引和端点属性
  3. 每次拖拽后,会自动更新对应线段的属性值,line_states()始终保存所有线段的完整端点信息

内容的提问来源于stack exchange,提问作者PPenton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 18:03:16