R Shiny散点图保留带空格变量名的技术问题咨询
解决Shiny散点图中带空格变量名的报错问题
你在RStudio开发的Shiny应用中,时间序列图能正常处理Water Temperature和Air Temperature这类带空格的变量名,但散点图出现解析错误:
Warning: Error in parse: <text>:1:7: unexpected symbol 1: Water Temperature ^
或
Warning: Error in parse: <text>:1:5: unexpected symbol 1: Air Temperature ^
问题根源是你使用的aes_string()函数会将传入的字符串当作R代码解析,而带空格的变量名不符合R默认语法规则(R要求变量名无空格,除非用反引号包裹)。要保留变量名空格,只需替换aes_string()为支持动态引用带空格变量的语法即可,以下是两种可行方案:
方案1:使用.data代词(推荐)
这是tidyverse官方推荐的动态变量引用方式,通过.data[[变量名]]可以安全调用带空格的变量:
关键修改点
- 散点图需要宽格式数据,因此将数据源从长格式的
dat_long改为原始宽格式的dat(长格式仅适用于时间序列图的单变量展示) - 用
aes(x = .data[[input$xAxisInput]], y = .data[[input$yAxisInput]])替换aes_string()
修改后的散点图渲染代码:
output$scatterPlot <- renderPlot({ filteredData2 <- dat %>% filter(Site == input$siteInput2) xLabel <- switch(input$xAxisInput[1], `Air Temperature` = expression(Air~Temperature~(degree*C)), `Water Temperature` = expression(Water~Temperature~(degree*C))) yLabel <- switch(input$yAxisInput[1], `Air Temperature` = expression(Air~Temperature~(degree*C)), `Water Temperature` = expression(Water~Temperature~(degree*C))) ggplot(filteredData2, aes(x = .data[[input$xAxisInput]], y = .data[[input$yAxisInput]])) + geom_point() + labs(x = xLabel, y = yLabel, title = paste('Site:', input$siteInput2)) + theme_bw() })
方案2:使用sym()和非标准求值
通过rlang::sym()将字符串转换为R符号,再用!!注入到aes()中:
output$scatterPlot <- renderPlot({ filteredData2 <- dat %>% filter(Site == input$siteInput2) xLabel <- switch(input$xAxisInput[1], `Air Temperature` = expression(Air~Temperature~(degree*C)), `Water Temperature` = expression(Water~Temperature~(degree*C))) yLabel <- switch(input$yAxisInput[1], `Air Temperature` = expression(Air~Temperature~(degree*C)), `Water Temperature` = expression(Water~Temperature~(degree*C))) ggplot(filteredData2, aes(x = !!rlang::sym(input$xAxisInput), y = !!rlang::sym(input$yAxisInput))) + geom_point() + labs(x = xLabel, y = yLabel, title = paste('Site:', input$siteInput2)) + theme_bw() })
完整修改后的应用代码
library(tidyverse) library(shiny) library(shinydashboard) # Create example dataset set.seed(123) dat <- data.frame( Time = rep(seq(1,10,1), times = 2), Site = rep(c('A', 'B'), each = 10), Water_Temperature = round(rnorm(20, mean = 20, sd = 5)), Air_Temperature = round(rnorm(20, mean = 25, sd = 3)) ) dat <- dat %>% rename(`Water Temperature` = Water_Temperature, `Air Temperature` = Air_Temperature) dat_long <- dat %>% pivot_longer(cols = c("Water Temperature","Air Temperature"), names_to = 'Variable', values_to = 'Value') %>% arrange(Site, Time) # Define user interface for time series and scatterplot ui.R <- dashboardPage( dashboardHeader(title = "Example", titleWidth = 350), dashboardSidebar( tags$head( tags$style( HTML(" .sidebar-footer { text-align: center; } .sidebar-logo { display: flex; align-items: center; justify-content: center; } .sidebar-menu a span { font-size: 24px; } ") ) ), sidebarMenu( menuItem("Time Series", tabName = "time_series", icon = icon("chart-line")), menuItem("Scatterplot", tabName = "scatter_plot", icon = icon("chart-line")) ) ), dashboardBody( tabItems( tabItem( tabName = "time_series", fluidRow( box( title = "Time Series", status = "primary", solidHeader = TRUE, width = 2, selectInput("siteInput", "Select Site", choices = unique(dat_long$Site)), selectInput("variableInput", "Select Variable", choices = unique(dat_long$Variable)) ), box( title = "Plot", status = "primary", solidHeader = TRUE, width = 10, plotOutput("timeSeriesPlot", height = "700px") ) ) ), tabItem( tabName = "scatter_plot", fluidRow( box( title = "Scatterplot", status = "primary", solidHeader = TRUE, width = 2, selectInput("siteInput2", "Select Site", choices = unique(dat_long$Site)), selectInput("xAxisInput", "Select X-axis Variable:", choices = unique(dat_long$Variable)), selectInput("yAxisInput", "Select Y-axis Variable:", choices = unique(dat_long$Variable)) ), box( title = "Plot", status = "primary", solidHeader = TRUE, width = 10, plotOutput("scatterPlot", height = "700px") ) ) ), tabItem( tabName = "site_info", fluidPage( fluidRow( selectInput("siteInput3", "Select Site", choices = unique(dat_long$Site)), column(4, dataTableOutput('table')) ) ) ) ) ) ) # Define server server.R <- function(input, output) { output$timeSeriesPlot <- renderPlot({ filteredData <- dat_long %>% filter(Site == input$siteInput, Variable == input$variableInput) variableName <- unique(filteredData$Variable) yLabel <- ifelse(variableName == "Water Temperature", expression(Water~Temperature~(degree*C)), ifelse(variableName == "Air Temperature", expression(Air~Temperature~(degree*C)))) ggplot(filteredData, aes(x = Time, y = Value)) + geom_line() + geom_point() + scale_x_continuous(breaks = seq(1,10,1)) + labs(x = "", y = yLabel, title = paste('Site:', input$siteInput)) + theme_bw() }) output$scatterPlot <- renderPlot({ filteredData2 <- dat %>% filter(Site == input$siteInput2) xLabel <- switch(input$xAxisInput[1], `Air Temperature` = expression(Air~Temperature~(degree*C)), `Water Temperature` = expression(Water~Temperature~(degree*C))) yLabel <- switch(input$yAxisInput[1], `Air Temperature` = expression(Air~Temperature~(degree*C)), `Water Temperature` = expression(Water~Temperature~(degree*C))) ggplot(filteredData2, aes(x = .data[[input$xAxisInput]], y = .data[[input$yAxisInput]])) + geom_point() + labs(x = xLabel, y = yLabel, title = paste('Site:', input$siteInput2)) + theme_bw() }) } # Run the application shinyApp(ui = ui.R, server = server.R)
内容的提问来源于stack exchange,提问作者tassones
相关产品推荐
相关产品推荐

