在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)
关键说明
- 用
reactiveVal存储所有线段的完整坐标,初始值必须与layout(shapes)的配置完全一致 - 通过
stringr解析plotly_relayout返回的键名(如shapes[0].x1),匹配对应的线段索引和端点属性 - 每次拖拽后,会自动更新对应线段的属性值,
line_states()始终保存所有线段的完整端点信息
内容的提问来源于stack exchange,提问作者PPenton
相关产品推荐
相关产品推荐

