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

R语言Shiny框架中Plotly分组散点图无法更新及悬停信息缺失的问题求助

问题描述

我希望在R语言的Shiny框架中使用Plotly库创建一个交互式散点图,用于展示分组数据,且鼠标悬停在数据点上时,能够显示该点的X轴、Y轴坐标以及分组变量名称(本示例中为Species)。我对Shiny较为熟悉,但刚接触Plotly,以下是我编写的示例代码:

library(shiny)
library(shinyWidgets)
library(plotly)
library(tidyverse)

ui<-fluidPage(
  titlePanel("Iris"),
  tabsetPanel(
    tabPanel("Iris scatter",
             sidebarPanel(width=5,
                          h5("Select the axis variables"),
                          selectInput("eda_scatter_x", "Select x-axis", 
                                      c("Sepal Length"="Sepal.Length", 
                                        "Sepal Width" ="Sepal.Width", 
                                        "Petal Length"= "Petal.Length", 
                                        "Petal Width"= "Petal.Width")),
                          selectInput("eda_scatter_y", "Select y-axis", 
                                      c("Sepal Length"="Sepal.Length", 
                                        "Sepal Width" ="Sepal.Width", 
                                        "Petal Length"= "Petal.Length", 
                                        "Petal Width"= "Petal.Width")),
                          actionButton(inputId = "eda_run", "Run analysis")),
             mainPanel(
               plotlyOutput("eda_scatter_graph")  
             ))
  )
)

server <- function(input,output,session){
  observeEvent(input$eda_run,{
    output$eda_scatter_graph<- renderPlotly({
      iris%>% 
        group_by(Species)%>% 
        summarise_at(vars(Sepal.Length:Petal.Width),mean)%>% 
        plot_ly(x=input$eda_scatter_x, y=input$eda_scatter_y, size=I(c(100,50)))%>% 
        add_markers()
    })
  })
}

shinyApp(ui,server)

目前遇到两个问题:

  • 通过selectInput选择X轴、Y轴变量后,点击“Run analysis”按钮,图表无法更新;
  • 鼠标悬停在数据点上时,无法显示分组变量名称及对应的坐标信息。

恳请指出代码中的错误,并提供修改建议,谢谢!


解决方案

咱们来一步步拆解并解决这两个问题:

问题1:图表无法更新的原因及修复

核心错误:

plot_ly()中直接传入input$eda_scatter_x这类字符型变量名是无效的——Plotly需要的是数据框中的变量映射,而非字符串常量,这会导致图表始终使用初始的无效值,自然无法响应选择变化。

修复方法:

使用tidyverse的tidyeval语法(sym()和!!运算符),把字符串变量名转换成Plotly能识别的变量映射,或者用get()函数提取变量,这里推荐前者,更贴合tidyverse的使用习惯。

问题2:悬停信息缺失的原因及修复

核心错误:

你没有自定义Plotly的悬停提示内容,默认提示只会显示基础的数值,不会包含分组名称;另外你设置的size=I(c(100,50))只有两个值,但鸢尾花的分组有3个,会导致尺寸赋值异常,也会影响体验。

修复方法:

  • 在add_markers()中用text参数自定义悬停文本,配合hoverinfo="text"显示自定义内容;
  • 调整size参数为适合3个分组的统一值,或者按需求设置对应尺寸。

修改后的完整代码

library(shiny)
library(shinyWidgets)
library(plotly)
library(tidyverse)

ui<-fluidPage(
  titlePanel("Iris"),
  tabsetPanel(
    tabPanel("Iris scatter",
             sidebarPanel(width=5,
                          h5("Select the axis variables"),
                          selectInput("eda_scatter_x", "Select x-axis", 
                                      c("Sepal Length"="Sepal.Length", 
                                        "Sepal Width" ="Sepal.Width", 
                                        "Petal Length"= "Petal.Length", 
                                        "Petal Width"= "Petal.Width")),
                          selectInput("eda_scatter_y", "Select y-axis", 
                                      c("Sepal Length"="Sepal.Length", 
                                        "Sepal Width" ="Sepal.Width", 
                                        "Petal Length"= "Petal.Length", 
                                        "Petal Width"= "Petal.Width")),
                          actionButton(inputId = "eda_run", "Run analysis")),
             mainPanel(
               plotlyOutput("eda_scatter_graph")  
             ))
  )
)

server <- function(input,output,session){
  # 用reactiveVal存储汇总数据,让逻辑更清晰,也方便后续复用
  summarized_data <- reactiveVal(NULL)
  
  observeEvent(input$eda_run,{
    # 计算分组均值,用across替代summarise_at(tidyverse新版本推荐语法)
    data <- iris%>% 
      group_by(Species)%>% 
      summarise(across(Sepal.Length:Petal.Width, mean), .groups = "drop")
    
    summarized_data(data)
  })
  
  output$eda_scatter_graph<- renderPlotly({
    # 确保数据存在才渲染图表,避免初始状态报错
    req(summarized_data())
    
    # 把字符串变量名转换成Plotly可识别的变量映射
    x_var <- sym(input$eda_scatter_x)
    y_var <- sym(input$eda_scatter_y)
    
    summarized_data()%>% 
      plot_ly(x = x_var, y = y_var, size = I(100))%>% 
      add_markers(
        # 自定义悬停文本,包含分组名称和格式化的坐标值
        text = ~paste0("Species: ", Species, "\n",
                       str_replace_all(input$eda_scatter_x, "\\.", " "), ": ", round(!!x_var, 2), "\n",
                       str_replace_all(input$eda_scatter_y, "\\.", " "), ": ", round(!!y_var, 2)),
        hoverinfo = "text"
      )%>%
      # 设置坐标轴为用户选择的友好名称(比如显示"Sepal Length"而非"Sepal.Length")
      layout(
        xaxis = list(title = names(which(c("Sepal Length"="Sepal.Length", 
                                           "Sepal Width" ="Sepal.Width", 
                                           "Petal Length"= "Petal.Length", 
                                           "Petal Width"= "Petal.Width") == input$eda_scatter_x))),
        yaxis = list(title = names(which(c("Sepal Length"="Sepal.Length", 
                                           "Sepal Width" ="Sepal.Width", 
                                           "Petal Length"= "Petal.Length", 
                                           "Petal Width"= "Petal.Width") == input$eda_scatter_y)))
      )
  })
}

shinyApp(ui,server)

额外优化说明

  • 用across()替代了summarise_at(),这是tidyverse 1.0.0版本后的推荐语法,兼容性和可读性更好;
  • 添加req(summarized_data())避免初始状态下数据为空导致的报错;
  • 优化了坐标轴标签,显示用户选择的友好名称,提升体验;
  • 对悬停数值做了四舍五入,让信息更整洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 20:17:44