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

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 updates cs() but then hits the else {return()} at the end, making tweet() return NULL. Your outputs check if tweet() is NULL, so they don't render.
  • The values reactiveValues 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_map with gsub directly, which won't work properly—you need to wrap gsub in content_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)

关键修改说明

  1. 简化状态管理:移除了复杂的values reactiveValues,改用单个cs reactiveVal维护清洗后的语料库,让状态更新逻辑更清晰,确保输出能正确触发重绘。
  2. 移除有缺陷的tweet() reactive:原tweet()的条件判断会在移除/替换操作时返回NULL,导致输出不渲染。现在输出直接依赖cs(),语料库更新时自动触发重绘。
  3. 添加req(cs()):确保所有操作和输出仅在语料库存在时执行,避免空值报错。
  4. 修复替换操作:用content_transformer()包裹gsub,这是tm包处理文本替换的标准方式。
  5. 修正UI语法错误:把checkboxGroupInput中的choices <- c(...)改为choices = c(...),避免在UI中错误赋值。

现在你的应用应该能正常工作:

  • 点击「go」加载数据并显示图表
  • 输入单词点击「do」移除后,图表实时更新
  • 输入替换词点击「act」后,图表实时更新

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:39:19