R Shiny运行ggplot报错:传入函数作为全局data参数求解
问题背景
- 数据来源:NBA 2022赛季球员场均数据统计页面
- 数据预处理流程:从页面「Share & Export」菜单选择「Get table as CSV (for Excel)」选项,全选生成的表格文本复制到Excel中,使用「Text to columns」功能按逗号分隔符拆分数据,之后将文件保存为.csv后缀格式
- 开发目标:搭建Shiny交互应用,配置出场分钟数、出场场次滑块控件,以及球队筛选复选框,实现带悬浮弹窗提示的plotly交互图表
- 运行报错信息:
Warning: Error in ggplot: You're passing a function as global data. Have you misspelled the
dataargument inggplot()
原始代码
library(shiny) library(ggplot2) library(dplyr) library(plotly) library(tidyverse) Player_Stats<-read.csv("2021-2022 Indiv Per Game Stats.csv") colnames(Player_Stats)[11]<-"FG%" colnames(Player_Stats)[14]<-"ThreeP%" colnames(Player_Stats)[17]<-"TwoP%" colnames(Player_Stats)[18]<-"eFG%" colnames(Player_Stats)[21]<-"FT%" ui<-fluidPage( titlePanel("Player Stats"), sidebarLayout( sidebarPanel( sliderInput("input1", "Minutes", min=0, max = 48, value = 0), sliderInput("Input2", "Games Played", min = 0, max = 82, value = 0), checkboxGroupInput(inputId = "tm_input", label = "Team", choices = unique(Player_Stats$Tm), selected = unique(Player_Stats$Tm)) ), mainPanel( plotOutput("plot1"), plotOutput("plot2"), dataTableOutput("Player_StatsTable") ) ) ) server<-function(input, output){ output$plot1<-renderPlotly({ x<-Player_Stats %>% ggplot(aes(x=PTS, y=`ThreeP%`,color=Tm, text=paste("Player:",Player, "PPG:",PTS, "3P%:", `ThreeP%`*100, "Team:",Tm)))+ geom_point()+ xlab("Points per Game")+ ylab("Three Point %")+ ggtitle("PPG and 3P% by Player")+ theme(plot.title = element_text(hjust = 0.5)) ggplotly(x) }) output$plot2<-renderPlotly({ y<-Player_Stats %>% ggplot(aes(x=PTS, y=`TwoP%`,color=Tm, text=paste("Player:",Player, "PPG:",PTS, "2P%:", `TwoP%`*100, "Team:",Tm)))+ geom_point()+ xlab("Points per Game")+ ylab("Two Point %")+ ggtitle("PPG and 2P% by Player")+ theme(plot.title = element_text(hjust = 0.5)) ggplotly(y) }) Player_Stats=reactive({ Player_Stats %>% dplyr::filter(Tm %in% input$Tm_,.preserve = TRUE) %>% dplyr::filter(MP>=input$input1) %>% dplyr::filter(G>=input$input2) }) output$Player_StatsTable<-renderDataTable({ Player_Stats }) } shinyApp(ui=ui,server=server)
问题排查结果
共6处导致报错/功能异常的问题:
- 变量名冲突:全局环境读入的原始数据框命名为
Player_Stats,后续server内又定义了同名的响应式对象,导致ggplot调用数据时拿到的是响应式函数本身而非数据框,直接触发题目中的核心报错 - 输出组件不匹配:UI端使用
plotOutput承接静态ggplot输出,但server端用renderPlotly渲染交互图表,类型不匹配会导致图表无法正常加载 - 输入ID拼写错误:两处ID拼写不匹配:一是球队筛选复选框定义的inputId为
tm_input,响应式数据过滤时错写为input$Tm_;二是出场场次滑块定义的inputId为Input2(首字母大写I),过滤逻辑错写为input$input2(首字母小写i),均无法正确读取用户选择的筛选值 - 响应式数据未生效:两处绘图逻辑完全没有使用过滤后的响应数据,滑块、复选框的筛选操作不会对图表生效
- 响应式对象调用方式错误:Shiny中响应式对象本质是函数,调用时必须加括号,否则读取到的是函数定义而非计算结果
- 表格渲染逻辑错误:
renderDataTable内直接传入了响应式对象本身,未加括号执行,会导致表格无法正常渲染
修复后可运行代码
library(shiny) library(ggplot2) library(dplyr) library(plotly) library(tidyverse) # 重命名原始数据,避免和后续响应式对象重名 raw_player_stats<-read.csv("2021-2022 Indiv Per Game Stats.csv") colnames(raw_player_stats)[11]<-"FG%" colnames(raw_player_stats)[14]<-"ThreeP%" colnames(raw_player_stats)[17]<-"TwoP%" colnames(raw_player_stats)[18]<-"eFG%" colnames(raw_player_stats)[21]<-"FT%" ui<-fluidPage( titlePanel("Player Stats"), sidebarLayout( sidebarPanel( sliderInput("input1", "Minutes", min=0, max = 48, value = 0), sliderInput("Input2", "Games Played", min = 0, max = 82, value = 0), checkboxGroupInput(inputId = "tm_input", label = "Team", choices = unique(raw_player_stats$Tm), selected = unique(raw_player_stats$Tm)) ), mainPanel( # 替换为plotly专属输出组件 plotlyOutput("plot1"), plotlyOutput("plot2"), dataTableOutput("Player_StatsTable") ) ) ) server<-function(input, output){ # 修正响应式数据命名、输入ID拼写 filtered_stats <- reactive({ raw_player_stats %>% dplyr::filter(Tm %in% input$tm_input,.preserve = TRUE) %>% dplyr::filter(MP>=input$input1) %>% dplyr::filter(G>=input$Input2) }) output$plot1<-renderPlotly({ # 调用过滤后的响应数据必须加括号,新增百分比保留1位小数优化展示 x<-filtered_stats() %>% ggplot(aes(x=PTS, y=`ThreeP%`,color=Tm, text=paste("Player:",Player, "PPG:",PTS, "3P%:", round(`ThreeP%`*100,1), "Team:",Tm)))+ geom_point()+ xlab("Points per Game")+ ylab("Three Point %")+ ggtitle("PPG and 3P% by Player")+ theme(plot.title = element_text(hjust = 0.5)) # 明确指定悬浮提示读取text映射内容 ggplotly(x, tooltip = "text") }) output$plot2<-renderPlotly({ y<-filtered_stats() %>% ggplot(aes(x=PTS, y=`TwoP%`,color=Tm, text=paste("Player:",Player, "PPG:",PTS, "2P%:", round(`TwoP%`*100,1), "Team:",Tm)))+ geom_point()+ xlab("Points per Game")+ ylab("Two Point %")+ ggtitle("PPG and 2P% by Player")+ theme(plot.title = element_text(hjust = 0.5)) ggplotly(y, tooltip = "text") }) output$Player_StatsTable<-renderDataTable({ filtered_stats() }) } shinyApp(ui=ui,server=server)
内容的提问来源于stack exchange,提问作者Tamir
相关产品推荐
相关产品推荐

