skip to Main Content

This is an app that analyzes tweets using Twitter’s API
There is a textInput, and currently each time the input changes the server will pull data, clean it, and update plots.
I only want this to happen after the user has typed the search term, then pressed ‘enter’.

I believe this can be done with isolate(), but I am at a loss.
Any help is appreciated, thank you!

I currently have a tag$script that reads in the last user key press. Upon testing, the initial graph shows when I press enter, however, whenever I update the text field afterwards, the plots update without me needing to press enter. Not sure why, since I have the code in a observe(), but I must be understanding something wrong.The code is below, but you cannot fully run it without your own Twitter API keys

library(shiny)
library(ggplot2)
library(readr)
library(rsconnect) # Deploy Shiny App
library(data.table)
library(plotly)
library(tm) # Text mining
library(dplyr)
library(twitteR) # Pull from Twitter API
library(sentimentr) # Sentiment Analysis
library(tidytext)
library(Unicode)
library(RColorBrewer) # Color palletes
library(base64enc)
library(shinyWidgets) 
library(shinycssloaders) # Loading animatiions
library(wordcloud) # Create wordclouds
library(shinyjs) # Calls shinyjs functions

ui <- fluidPage(

  tags$script(' $(document).on("keydown", function (e) {
                                                 Shiny.onInputChange("lastkeypresscode", e.keyCode);
                                                  });'),
fluidRow( 
    column(12,
           h2("Show me analysis on")),
           textInput("search","", value = "cats")),

    )
  ),
fluidRow(
    column(6, plotOutput("wordcloud") %>% withSpinner()),
    column(6, plotlyOutput("sentiment")  %>% withSpinner()

    )
  )

)

server <- function(input, output,session) {

  # Authentication keys to access TWitter's API
  consumerKey <- 'k1WaBd'
  consumerSecret <- 'XFQMKfh'
  accessToken <- '14554'
  accessSecret <- 'ZHDvhGmdh'
  setup_twitter_oauth(consumerKey, consumerSecret, accessToken, accessSecret)

# Get Tweet Data
  rawTweets <- reactive({rawTweets <- searchTwitter(req(input$search), n = 200) })

  # Clean raw Twitter data, returns just the body of tweets w/o links and emojis
  cleanTweets <- function(rawTweets){
    df<- do.call("rbind",lapply(rawTweets,as.data.frame))
    # Remove emojis
    df$text <- sapply(df$text,function(row) iconv(row, "latin1", "ASCII", sub="")) 
    df[, c('isRetweet','id', 'longitude','latitude', 'replyToUID', 'replyToSID', 'replyToSN')] <- NULL
    df <- df[!duplicated(df$text), ] # Remove duplicate tweets
    df <- df[!duplicated(df$screenName), ] # Remove duplicate users

    df$text[df$text == ""] <- NA 
    df$letterCount <- nchar(gsub(" ","",df$text)) 
    df$text[df$letterCount == '0'] <- NA 
    df <- na.omit(df)  
    return (df$text)
  }

  # Holds list of cleaned tweets
  words <- reactive({words <- cleanTweets(rawTweets())
  })

  createCorpus <-function(words){

    # Create a corpus to store word data, from package tm
    corpus <- Corpus(VectorSource(words))
    corpus <- tm_map(corpus, removePunctuation)
    corpus <- tm_map(corpus, content_transformer(tolower))
    corpus <- tm_map(corpus,function(x)removeWords(x,stopwords()))

    return(corpus)
  }

  corpus <- reactive({corpus <- createCorpus(words() )})


  observe({
    if(!is.null(input$lastkeypresscode)) {
      if(input$lastkeypresscode == 13){


        if (is.null(input$search) || input$search == "")
          return()

        output$wordcloud <- renderPlot({
          wordcloud(corpus(), min.freq = 3, scale = c(7, 2), random.order = F, colors = brewer.pal(8,'Dark2'))
        })

        # Sentiment Scoring
        sentiment <- reactive({sentiment <- sentiment_by(words()) })
        emotion <- reactive({emotion <- emotion_by(words() )})

        output$sentiment <- renderPlotly({
          # Count # of tweets in each category
          neutral <- sum(sentiment()$ave_sentiment == "0")
          positive <- sum(sentiment()$ave_sentiment > "0")
          negative <- sum(sentiment()$ave_sentiment < "0")
          feeling <- c('positive', 'negative', 'neutral')
          count <- c(positive,negative,neutral)
          df <- data.frame(feeling,count, stringsAsFactors=FALSE)

          plot_ly(df,labels = ~feeling, values = ~count, type = 'pie', 
                  marker = list(colors = c('#c2fa87', '#ffb39c', '#d1d1c9'))
        })


      }
    }
  })

}

shinyApp(ui = ui, server = server)

2

Answers


  1. I haven’t tested properly yet but you could try using an observeEvent instead of an observe as below:

    observeEvent(req(input$lastkeypresscode==13), {
    
        if (is.null(input$search) || input$search == "")
          return()
    
        output$wordcloud <- renderPlot({
          wordcloud(corpus(), min.freq = 3, scale = c(7, 2), random.order = F, colors = brewer.pal(8,'Dark2'))
        })
    
        # Sentiment Scoring
        sentiment <- reactive({sentiment <- sentiment_by(words()) })
        emotion <- reactive({emotion <- emotion_by(words() )})
    
        output$sentiment <- renderPlotly({
          # Count # of tweets in each category
          neutral <- sum(sentiment()$ave_sentiment == "0")
          positive <- sum(sentiment()$ave_sentiment > "0")
          negative <- sum(sentiment()$ave_sentiment < "0")
          feeling <- c('positive', 'negative', 'neutral')
          count <- c(positive,negative,neutral)
          df <- data.frame(feeling,count, stringsAsFactors=FALSE)
    
          plot_ly(df,labels = ~feeling, values = ~count, type = 'pie', 
                  marker = list(colors = c('#c2fa87', '#ffb39c', '#d1d1c9'))
        })
    })
    
    Login or Signup to reply.
  2. I tried using a search action button,

    ui <- fluidPage(
      fluidRow(column(6,
                      h2("Show me analysis on")),
               textInput("keySearch", NULL)),
      column(
        width = 1,
        actionButton("search", "Search"),
        tags$style(
          "#search { color: #fff; background-color: #00557F; margin-top:24px; font-family: 'Candara'; }"
        )
      ),
      fluidRow(
        column(6, plotOutput("wordcloud") %>% withSpinner()),
        column(6, plotlyOutput("sentiment")  %>% withSpinner())
      )
    )
    
    server <- function(input, output, session) {
      # Authentication keys to access TWitter's API
      consumerKey <- 'your key'
      consumerSecret <- 'your secret'
      accessToken <- 'your token'
      accessSecret <- 'your secret'
      setup_twitter_oauth(consumerKey, consumerSecret, accessToken, accessSecret)
    
      # Get Tweet Data
      rawTweets <-
        eventReactive(input$search, {
          searchTwitter(req(input$keySearch), n = 200)
        })
    
      # Clean raw Twitter data, returns just the body of tweets w/o links and emojis
      cleanTweets <- function(rawTweet) {
        df <- do.call("rbind", lapply(rawTweet, as.data.frame))
        # Remove emojis
        df$text <-
          sapply(df$text, function(row)
            iconv(row, "latin1", "ASCII", sub = ""))
        df[, c(
          'isRetweet',
          'id',
          'longitude',
          'latitude',
          'replyToUID',
          'replyToSID',
          'replyToSN'
        )] <- NULL
        df <- df[!duplicated(df$text),] # Remove duplicate tweets
        df <- df[!duplicated(df$screenName),] # Remove duplicate users
    
        df$text[df$text == ""] <- NA
        df$letterCount <- nchar(gsub(" ", "", df$text))
        df$text[df$letterCount == '0'] <- NA
        df <- na.omit(df)
        return (df$text)
      }
    
      # Holds list of cleaned tweets
      words <- reactive({
        words <- cleanTweets(rawTweets())
      })
    
      createCorpus <- function(words) {
        # Create a corpus to store word data, from package tm
        corpus <- Corpus(VectorSource(words))
        corpus <- tm_map(corpus, removePunctuation)
        corpus <- tm_map(corpus, content_transformer(tolower))
        corpus <- tm_map(corpus, function(x)
          removeWords(x, stopwords()))
    
        return(corpus)
      }
    
      corpus <- reactive({
        corpus <- createCorpus(words())
      })
    
    
      observeEvent(input$search, {
        output$wordcloud <- renderPlot({
          wordcloud(
            corpus(),
            min.freq = 3,
            scale = c(7, 2),
            random.order = F,
            colors = brewer.pal(8, 'Dark2')
          )
        })
    
        # Sentiment Scoring
        sentiment <- reactive({
          sentiment <- sentiment_by(words())
        })
        emotion <- reactive({
          emotion <- emotion_by(words())
        })
    
        output$sentiment <- renderPlotly({
          # Count # of tweets in each category
          neutral <- sum(sentiment()$ave_sentiment == "0")
          positive <- sum(sentiment()$ave_sentiment > "0")
          negative <- sum(sentiment()$ave_sentiment < "0")
          feeling <- c('positive', 'negative', 'neutral')
          count <- c(positive, negative, neutral)
          df <- data.frame(feeling, count, stringsAsFactors = FALSE)
    
          plot_ly(
            df,
            labels = ~ feeling,
            values = ~ count,
            type = 'pie',
            marker = list(colors = c('#c2fa87', '#ffb39c', '#d1d1c9'))
          )
        })
      })
    
    }
    
    shinyApp(ui = ui, server = server)
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search