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
I haven’t tested properly yet but you could try using an observeEvent instead of an observe as below:
I tried using a search action button,