Shiny应用中点击操作更新图表与数据的问题排查
解决Shiny应用中仅特定操作后图表才显示的问题
Hey there! Let's break down why your Shiny app is only showing charts after clicking "go" then "act", and fix it step by step.
问题根源分析
Looking at your code, the main issues are around how you're managing the state of your cleaned text corpus (cleanset) and how reactive outputs trigger updates:
- The
tweet()reactive has a flawed conditional structure: when you click "do" (remove) or "act" (replace), the code updatescs()but then hits theelse {return()}at the end, makingtweet()return NULL. Your outputs check iftweet()is NULL, so they don't render. - The
valuesreactiveValues are overcomplicating state management, leading to conflicts where the app doesn't recognize when the corpus has actually been updated. - The replace operation uses
tm_mapwithgsubdirectly, which won't work properly—you need to wrapgsubincontent_transformer()for tm to process it correctly.
修正后的完整代码
Here's the fixed version of your app, with key improvements to logic and readability:
library(shiny) library(plyr) library(sp) library(stringr) library(tidyr) library(tidyverse) library(tm) library(ggplot2) library("stringi") library(dplyr) library(wordcloud2) # Move to top to load once ui <- fluidPage( fluidRow( column(4, titlePanel("Twitter Analytics")), column(3), column(4, textInput("searchstring", label = "", value = "")), column(1, br(), actionButton("action", "go")) ), fluidRow( column(12, tabsetPanel( tabPanel("one", fluidRow( column(3, textInput("removeString", label = "remove", value = ""), actionButton("remove", "do"), textInput("find", label = "find", value = ""), textInput("rep", label = "replace", value = ""), actionButton("replace", "act"), checkboxGroupInput("checkGroup", "select plots", choices = c("Histogram", "Wordcloud", "network")), # Fixed typo: choices <- -> choices = sliderInput("topTerms", label = "top (n) terms", min = 0, max = 25, value = 0) ), column(9, fluidRow(column(12, plotOutput("ttext"))), fluidRow(column(12, wordcloud2Output("wc2")))) ) ), tabPanel("two"), tabPanel("three") ) ) ) ) server <- function(input, output) { # Initialize reactive value to hold our cleaned corpus cs <- reactiveVal(NULL) # Load and initialize data when "go" is clicked observeEvent(input$action, { num <- c(1,2,3,4,50) text <- c("this is love love something", "this is not hate hate hate something", "@something islove rethched this not", " Shiny is love confusing me", "this is hate also somthing difficult") letter<- c("a", "b", "c", "D", "e") tweetdf <- data.frame(num, text, letter) # Clean the text tweetdf$text <- tolower(tweetdf$text) tweetdf$text <- gsub("@\\w+", "", tweetdf$text) tweetdf$text <- gsub("[[:punct:]]", "", tweetdf$text) tweetdf$text <- gsub("http\\w+", "", tweetdf$text) tweetdf$text <- gsub("[ |\t]{2,}", "", tweetdf$text) tweetdf$text <- gsub("^ ", "", tweetdf$text) # Create corpus and clean with tm corpus <- iconv(tweetdf$text, to = "ASCII") corpus <- Corpus(VectorSource(corpus)) corpus <- tm_map(corpus, removePunctuation) corpus <- tm_map(corpus, removeNumbers) cleanset <- tm_map(corpus, removeWords, stopwords('english')) # Update our reactive corpus cs(cleanset) }) # Remove words when "do" is clicked observeEvent(input$remove, { req(cs()) # Only run if corpus exists current_corpus <- cs() updated_corpus <- tm_map(current_corpus, removeWords, input$removeString) cs(updated_corpus) }) # Replace words when "act" is clicked observeEvent(input$replace, { req(cs()) # Only run if corpus exists current_corpus <- cs() # Use content_transformer to make gsub work with tm_map updated_corpus <- tm_map(current_corpus, content_transformer(gsub), pattern = input$find, replacement = input$rep) cs(updated_corpus) }) # Render histogram output$ttext <- renderPlot({ req(cs()) # Only run if corpus exists cleanset <- cs() tdm <- TermDocumentMatrix(cleanset) tdm <- as.matrix(tdm) w <- rowSums(tdm) barplot(w, col = brewer.pal(8, "Dark2")) # Added color for better visibility }) # Render wordcloud output$wc2 <- renderWordcloud2({ req(cs()) # Only run if corpus exists cleanset <- cs() tdm <- TermDocumentMatrix(cleanset) tdm <- as.matrix(tdm) w <- rowSums(tdm) w_df <- data.frame(word = names(w), freq = w) wordcloud2(w_df, color = 'random-dark', size = 0.7, shape = 'circle', rotateRatio = 0.5, minSize = 1) }) } shinyApp(ui, server)
关键修改说明
- 简化状态管理:移除了复杂的
valuesreactiveValues,改用单个csreactiveVal维护清洗后的语料库,让状态更新逻辑更清晰,确保输出能正确触发重绘。 - 移除有缺陷的
tweet()reactive:原tweet()的条件判断会在移除/替换操作时返回NULL,导致输出不渲染。现在输出直接依赖cs(),语料库更新时自动触发重绘。 - 添加
req(cs()):确保所有操作和输出仅在语料库存在时执行,避免空值报错。 - 修复替换操作:用
content_transformer()包裹gsub,这是tm包处理文本替换的标准方式。 - 修正UI语法错误:把checkboxGroupInput中的
choices <- c(...)改为choices = c(...),避免在UI中错误赋值。
现在你的应用应该能正常工作:
- 点击「go」加载数据并显示图表
- 输入单词点击「do」移除后,图表实时更新
- 输入替换词点击「act」后,图表实时更新
内容的提问来源于stack exchange,提问作者Pythonuser
相关产品推荐
相关产品推荐

