#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
# http://shiny.rstudio.com/
#
################# INSTALL PACKAGES IF REQUIRED #################
# v_required_packages <- c("rtweet", "ggplot2", "ggthemes",
# "maps", "devtools", "cli", "gh", "knitr")
#
# for (v_package in v_required_packages) {
# if(v_package %in% rownames(installed.packages()) == FALSE)
# {
# install.packages(v_package, dependencies=TRUE)
# }
# }
#
# devtools::install_github("mkearney/rtweet", build_vignettes = TRUE, force = TRUE)
################# LOAD THE REQUIRED PACKAGES #################
suppressPackageStartupMessages(library(shiny))
suppressPackageStartupMessages(library(shinyjs))
suppressPackageStartupMessages(library(shinythemes))
suppressPackageStartupMessages(library(rtweet))
suppressPackageStartupMessages(library(ggplot2))
suppressPackageStartupMessages(library(ggthemes))
suppressPackageStartupMessages(library(maps))
suppressPackageStartupMessages(library(cli))
suppressPackageStartupMessages(library(gh))
suppressPackageStartupMessages(library(knitr))
suppressPackageStartupMessages(library(dplyr))
suppressPackageStartupMessages(library(DT))
suppressPackageStartupMessages(library(leaflet))
suppressPackageStartupMessages(library(wordcloud))
suppressPackageStartupMessages(library(rJava))
suppressPackageStartupMessages(library(DBI))
suppressPackageStartupMessages(library(RJDBC))
suppressPackageStartupMessages(library(tm))
suppressPackageStartupMessages(library(SnowballC))
suppressPackageStartupMessages(library(tidyr))
suppressPackageStartupMessages(library(reshape2))
httr::set_config(httr::config(http_version = 0))
################# REQUIRED FUNCTIONS #################
## DISPLAY A MESSAGE BOX
displayMessage <- function(p_title, p_message) {
showModal(modalDialog(
title = p_title,
p_message,
easyClose = TRUE,
footer = NULL # modalButton("Dismiss")
))
}
## DISPLAY A ERROR MESSAGE BOX
displayError <- function(p_error_message) {
displayMessage("ERROR", p_error_message)
}
## FETCH THE EXISTING SUBJECTS FOR WHICH TWEETS EXIST IN THE DATABASE
fetchExistingSubjects <- function() {
tryCatch(
{
v_query <- "SELECT DISTINCT searchString, dateOfEnquiry FROM TB_TWEETS ORDER BY dateOfEnquiry DESC";
conn = dbConnect(jcc, jdbc_path, user=dsn_uid, password=dsn_pwd)
v_rs <- dbSendQuery(conn, v_query);
v_existing_subjects <- fetch(v_rs, -1) %>%
filter(!is.na(SEARCHSTRING)) %>%
filter(!is.na(DATEOFENQUIRY))
if( nrow(v_existing_subjects) == 0 ) {
dbDisconnect(conn)
displayError("Error in Application Setup. No set up data exists. Quitting")
stop(safeError(NULL))
}
dbDisconnect(conn)
},
error = function(e) {
# return a safeError if a parsing error occurs
dbDisconnect(conn)
displayError(paste("Error in Fetching Set Up Data. Quitting", e))
stop(safeError(e))
}
)
return(v_existing_subjects)
}
## FETCH THE SUBJECTS FOR WHICH TWEETS WERE SEARCHED IN THE PAST
fetchExistingSearches <- function() {
tryCatch(
{
v_query <- "SELECT Search_String FROM TB_STATISTICS";
conn = dbConnect(jcc, jdbc_path, user=dsn_uid, password=dsn_pwd)
v_rs <- dbSendQuery(conn, v_query);
v_existing_searches <- fetch(v_rs, -1) %>%
filter(!is.na(SEARCH_STRING))
if( nrow(v_existing_searches) == 0 ) {
dbDisconnect(conn)
displayError("Error in Application Setup. No set up data (Existing Searches) exists. Quitting")
stop(safeError(NULL))
}
dbDisconnect(conn)
},
error = function(e) {
# return a safeError if a parsing error occurs
dbDisconnect(conn)
displayError(paste("Error in Fetching Set Up Data. Existing Searches do not exist. Quitting", e))
stop(safeError(e))
}
)
return(v_existing_searches)
}
## READ TWEETS FROM THE DATABASE FOR A PARTICULAR SEARCH CRITERIA
readTweets <- function(p_search_string, p_search_date) {
if( p_search_date == '' || is.null(p_search_date) ) {
return(NULL)
}
if( p_search_string == '' || is.null(p_search_string) ) {
return(NULL)
}
v_query = paste("SELECT * FROM TB_TWEETS ",
"WHERE searchString = '", p_search_string, "' ",
"AND dateOfEnquiry = '", p_search_date, "'",
sep = ""
)
tryCatch(
{
conn = dbConnect(jcc, jdbc_path, user=dsn_uid, password=dsn_pwd)
v_rs = dbSendQuery(conn, v_query);
v_temp = fetch(v_rs, -1);
if( nrow(v_temp) == 0 ) {
dbDisconnect(conn)
displayError("Error in Data Fetch from Database. ZERO ROWS Returned. Quitting")
stop(safeError(NULL))
}
v_temp <- lat_lng(v_temp) %>%
mutate(tweet_text = TEXT) %>%
mutate(tweet_language = LANG) %>%
mutate(tweet_source = SOURCE) %>%
mutate(tweet_user = NAME) %>%
mutate(tweet_country = COUNTRY_CODE) %>%
mutate(tweet_place = PLACE_FULL_NAME) %>%
mutate(tweet_hashtag = HASHTAGS) %>%
mutate(tweet_followers_count = FOLLOWERS_COUNT) %>%
mutate(tweet_friends_count = FRIENDS_COUNT) %>%
mutate(tweet_urls_expanded_url = STATUS_URL) %>%
mutate(tweet_place_url = PLACE_URL) %>%
mutate(tweet_created_at = CREATED_AT) %>%
mutate(latitude = LAT) %>%
mutate(longitude = LNG)
dbDisconnect(conn)
},
error = function(e) {
# return a safeError if a parsing error occurs
dbDisconnect(conn)
displayError(paste("Error in Data Fetch from Database. Quitting", e))
stop(safeError(e))
}
)
return(v_temp)
}
# ## SAVE THE CURRENT SET OF TWEETS TO THE DATABASE
# saveTweetsToDatabase <- function(p_data_frame) {
# tryCatch(
# {
# p_data_frame$tweet_text <- NULL
# p_data_frame$latitude <- NULL
# p_data_frame$longitude <- NULL
# p_data_frame$tweet_language <- NULL
# p_data_frame$tweet_source <- NULL
# p_data_frame$tweet_user <- NULL
# p_data_frame$tweet_country <- NULL
# p_data_frame$tweet_place <- NULL
# p_data_frame$tweet_hashtag <- NULL
# p_data_frame$tweet_followers_count <- NULL
# p_data_frame$tweet_friends_count <- NULL
# p_data_frame$tweet_urls_expanded_url <- NULL
# p_data_frame$tweet_place_url <- NULL
# p_data_frame$tweet_created_at <- NULL
#
# conn = dbConnect(jcc, jdbc_path, user=dsn_uid, password=dsn_pwd)
# dbWriteTable(conn, "TB_TWEETS", p_data_frame,
# overwrite = FALSE,
# append =TRUE
# )
#
# dbDisconnect(conn)
# },
# error = function(e) {
# # return a safeError if a parsing error occurs
# dbDisconnect(conn)
# displayError(paste("Error Writing to Database. Quitting", e))
# stop(safeError(e))
# }
# )
# }
## EXTRAXT WORDS FROM THE READ TWEETS
extractWordsFromTweets <- function(p_tweet_data_frame) {
tryCatch(
{
# Remove the Emoticons
p_tweet_data_frame <- gsub("[^\x01-\x7F]", "", p_tweet_data_frame)
# Form the Corpus
v_corpus <- VCorpus(VectorSource(p_tweet_data_frame))
# Remove URLs
removeURL <- content_transformer(function(x) gsub("(f|ht)tp(s?)://\\S+", "", x, perl=T))
toSpace <- content_transformer(function (x , pattern) gsub(pattern, " ", x))
v_corpus <- tm_map(v_corpus, removeURL)
v_corpus <- tm_map(v_corpus, toSpace, "/")
v_corpus <- tm_map(v_corpus, toSpace, "@")
v_corpus <- tm_map(v_corpus, toSpace, "\\|")
v_corpus <- tm_map(v_corpus, toSpace, '"')
v_corpus <- tm_map(v_corpus, toSpace, "'")
# Create the Term Document Matrix after cleaning the Corpus
v_tdm <- TermDocumentMatrix(v_corpus,
control =
list(removePunctuation = TRUE,
stopwords = TRUE,
tolower = TRUE,
stemming = TRUE,
removeNumbers = TRUE,
bounds = list(global = c(1, Inf))
)
)
# Find the Frequent Words
v_ft <- findFreqTerms(v_tdm, lowfreq = 1, highfreq = Inf)
# Convert to a Matrix
v_matrix <- as.matrix(v_tdm[v_ft,])
# Sort the Words in DESCENDING Order and create Data Frame
v_data <- stack(sort(apply(v_matrix, 1, sum), decreasing = TRUE))
v_data <- subset(v_data, !(ind == "" || is.null(ind) || is.na(ind)))
},
error = function(e) {
# return a safeError if a parsing error occurs
displayError(paste("Error in Extracting Words from Tweets. This could be becuase the search does not produce any words in English Language. Please Try Again.", e, sep = " "))
# stop(safeError(e))
}
)
return(v_data)
}
## EVALUATE EMOTIONS
determineEmotionCount <- function(p_tidy_data) {
v_combined <- sort(union(levels(p_tidy_data$word), levels(v_nrc$word)))
v_text_sentiment2 <- inner_join(mutate(p_tidy_data, word=factor(word, levels=v_combined)),
mutate(v_nrc, word=factor(word, levels=v_combined))
)
v_text_sentiment1 <- v_text_sentiment2 %>%
count(word, index = row_number() %/% 80, sentiment) %>%
mutate(v_original_n = n) %>%
mutate(v_positive_negative = ifelse(sentiment %in% v_positive_emotions,
'positive', 'negative')) %>%
mutate(v_original_sentiment = sentiment) %>%
spread(sentiment, n, fill = 0)
v_text_sentiment <- v_text_sentiment1 %>%
mutate(positive = ifelse("positive" %in% colnames(v_text_sentiment1), positive, 0)) %>%
mutate(joy = ifelse("joy" %in% colnames(v_text_sentiment1), joy, 0)) %>%
mutate(surprise = ifelse("surprise" %in% colnames(v_text_sentiment1), surprise, 0)) %>%
mutate(trust = ifelse("trust" %in% colnames(v_text_sentiment1), trust, 0)) %>%
mutate(anticipation = ifelse("anticipation" %in% colnames(v_text_sentiment1), anticipation, 0)) %>%
mutate(negative = ifelse("negative" %in% colnames(v_text_sentiment1), negative, 0)) %>%
mutate(anger = ifelse("anger" %in% colnames(v_text_sentiment1), anger, 0)) %>%
mutate(disgust = ifelse("disgust" %in% colnames(v_text_sentiment1), disgust, 0)) %>%
mutate(sadness = ifelse("sadness" %in% colnames(v_text_sentiment1), sadness, 0)) %>%
mutate(fear = ifelse("fear" %in% colnames(v_text_sentiment1), fear, 0)) %>%
mutate(sentiment = (positive+joy+surprise+trust+anticipation) - (negative+anger+disgust+sadness+fear)) %>%
ungroup()
return(v_text_sentiment)
}
## SAVE STATISTICS TO DATABASE
saveStatisics <- function() {
tryCatch(
{
v_statement <- paste("INSERT INTO TB_STATISTICS (",
"Date_of_Search,",
"Search_String,",
"No_requested,",
"No_of_tweets_fetched,",
"No_of_tweets_analysed,",
"No_of_hashtag_found,",
"No_of_countries,",
"No_of_places,",
"No_of_languages,",
"No_of_devices,",
"No_of_users,",
"Total_words,",
"Unique_words,",
"Prevalent_emotion)",
"VALUES (",
paste("'", v_selected_date, "',", sep = ""),
paste("'", v_selected_subject, "',", sep = ""),
paste(v_number_requested, ",", sep = ""),
paste(v_number_fetched, ",", sep = ""),
paste(v_number_analysed, ",", sep = ""),
paste(v_number_hastag_found, ",", sep = ""),
paste(v_number_countries, ",", sep = ""),
paste(v_number_places, ",", sep = ""),
paste(v_number_languages, ",", sep = ""),
paste(v_number_devices, ",", sep = ""),
paste(v_number_users, ",", sep = ""),
paste(v_number_words, ",", sep = ""),
paste(v_number_unique_words, ",", sep = ""),
paste("'", v_prevalent_emotion, "'", sep = ""),
")", sep = " "
)
conn = dbConnect(jcc, jdbc_path, user=dsn_uid, password=dsn_pwd)
if( !dbSendUpdate(conn, v_statement) ) {
displayError("Error Writing to Database.")
} else {
dbCommit(conn)
}
dbDisconnect(conn)
},
error = function(e) {
# return a safeError if a parsing error occurs
dbDisconnect(conn)
# displayError(paste("Error Writing to Statistics.", e, sep = " "))
# stop(safeError(e))
}
)
}
################# READ THE SYSTEM PARAMETERS #################
v_system_parameters <- read.csv(file = "SystemParameters.csv", header = TRUE)
attach(v_system_parameters)
################# SET UP THE TWITTER ACCOUNT #################
api_key <- as.character(v_system_parameters[(which(Parameter == "api_key")),]$Value)
api_secret_key <- as.character(v_system_parameters[(which(Parameter == "api_secret_key")),]$Value)
access_token <- as.character(v_system_parameters[(which(Parameter == "access_token")),]$Value)
access_token_secret <- as.character(v_system_parameters[(which(Parameter == "access_token_secret")),]$Value)
## Authenticate via Web Browser
token <- create_token(
app = "ParthaEmotions",
consumer_key = api_key,
consumer_secret = api_secret_key,
access_token = access_token,
access_secret = access_token_secret)
################# SET UP THE DATABASE #################
## Values for database connection
dsn_driver = as.character(v_system_parameters[(which(Parameter == "dsn_driver")),]$Value)
dsn_database = as.character(v_system_parameters[(which(Parameter == "dsn_database")),]$Value)
dsn_hostname = as.character(v_system_parameters[(which(Parameter == "dsn_hostname")),]$Value)
dsn_port = as.character(v_system_parameters[(which(Parameter == "dsn_port")),]$Value)
dsn_protocol = as.character(v_system_parameters[(which(Parameter == "dsn_protocol")),]$Value)
dsn_uid = as.character(v_system_parameters[(which(Parameter == "DBUserID")),]$Value)
dsn_pwd = as.character(v_system_parameters[(which(Parameter == "DBPassword")),]$Value)
## Connect to the Database
jcc = JDBC(dsn_driver, "Drivers/db2jcc4.jar", identifier.quote="`");
jdbc_path = paste("jdbc:db2://", dsn_hostname, ":", dsn_port, "/", dsn_database, sep="");
################# SET UP THE GOOGLE MAPS #################
google_maps_api_key = as.character(v_system_parameters[(which(Parameter == "google_maps_api_key")),]$Value)
################# READ THE LEXICON #################
v_nrc <- readRDS("./nrc")
v_positive_emotions <- c("positive","joy","anticipation","surprise", "trust")
v_negative_emotions <- c("negative","anger","disgust","fear", "sadness")
v_positive_sentiment <- v_nrc %>%
filter(sentiment %in% v_positive_emotions)
################# SET UP INITIAL DATA TO DISPLAY #################
# Fetch existing searches
v_existing_searches <- fetchExistingSearches()
# Fetch the Initial Set of Tweets deom Database to Display
v_existing_subjects <- fetchExistingSubjects()
v_selected_subject <- v_existing_subjects[1,]$SEARCHSTRING
v_selected_date <- v_existing_subjects[1,]$DATEOFENQUIRY
v_tweets_to_display <- readTweets(v_selected_subject, v_selected_date)
v_number_requested <- as.integer(0)
v_number_fetched <- as.integer(0)
v_number_analysed <- as.integer(0)
v_number_hastag_found <- as.integer(0)
v_number_countries <- as.integer(0)
v_number_places <- as.integer(0)
v_number_languages <- as.integer(0)
v_number_devices <- as.integer(0)
v_number_users <- as.integer(0)
v_number_words <- as.integer(0)
v_number_unique_words <- as.integer(0)
v_prevalent_emotion <- ""
# Set up initial Emotion Analysis
tryCatch(
{
v_words_in_tweets <- extractWordsFromTweets(
(v_tweets_to_display %>%
filter(tweet_language == 'en'))$tweet_text
) %>%
rename(word = ind) %>%
rename(n = values)
},
error = function(e) {
# return a safeError if a parsing error occurs
displayError(paste("Error Setting up Chidiya. Quitting", e, sep = " "))
stop(safeError(e))
}
)
v_combined <- sort(union(levels(v_words_in_tweets$word), levels(v_positive_sentiment$word)))
v_positive_sentiment_words <- semi_join(mutate(v_words_in_tweets, word=factor(word, levels=v_combined)),
mutate(v_positive_sentiment, word=factor(word, levels=v_combined))) %>%
count(word, sort = TRUE)
## Joining, by = "word"
################# SET UP UI FOR THE APPLICATION #################
ui <- fluidPage(theme = shinytheme("united"),
tags$head(
tags$style(
HTML(".shiny-notification {
position:fixed;
top: calc(50%);
left: calc(50%);
font-family:Verdana;
fontSize:xx-large;
}
"
)
)
),
# Application title
fluidRow(
column(width = 3,
img(src="ParthaInPetra.jpg", width=200, height=112)
),
column(width = 6,
h1("Chidiya", style="color:blue; text-align: center;"),
h3("Tweet Analyser", style="color:darkred; text-align: center;")
),
column(width = 3,
h4("...", style="color:blue; text-align: right;"),
h4("Developed by: Partha Majumdar", style="color:blue; text-align: right;"),
h5("Riyadh (Saudi Arabia), 29-February-2020", style="color:black; text-align: right;")
)
),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
tabsetPanel(id = "search_option_panel", type = "tabs",
tabPanel("Search String",
h4("Enter Search String"),
h5("Enter several subjects by separating with comma"),
h5("To search for hashtag, enter Search String starting with #. For example: #Climate"),
textInput(inputId = "v_search_string",
label = "",
value = "",
placeholder = "Enter Subject(s) to Search"
),
sliderInput(inputId = "v_number_of_tweets",
label = h4("Number of Tweets to Fetch:"),
value = 750,
min = 500,
max = 5000
),
actionButton(inputId = "v_fetch", label = "Fetch")
),
tabPanel("Location",
h4("Enter Location"),
h5("Enter only ONE Location name"),
textInput(inputId = "v_search_location",
label = "",
value = "",
placeholder = "Enter Location to Search"
),
sliderInput(inputId = "v_number_of_tweets_location",
label = h4("Number of Tweets to Fetch:"),
value = 750,
min = 500,
max = 5000
),
actionButton(inputId = "v_fetch_location", label = "Fetch")
)
),
br(),
br(),
wellPanel(
h5("It can take time to fetch new Tweets. In case, Chidiya throws an error while fetching new tweets, wait for about 15 minutes before trying to fetch tweets once again. There is a restriction on how many tweets can be fetched in a given interval.",
style="color:red; text-align: left;")
),
wellPanel(
h4("Past Searches", style="color:black; text-align: center;"),
plotOutput(outputId = "existingSearchesWordCloud")
)
),
# Show a plot of the generated distribution
mainPanel(
tabsetPanel(id = "main_panel", type = "tabs",
tabPanel("Raw Data",
dataTableOutput(outputId = "tweets"),
wellPanel(
plotOutput(outputId = "tweetTimeSeries")
)
),
tabPanel("Analysis",
tabsetPanel(id = "analysis_panel", type = "tabs",
tabPanel("World Map",
fluidRow(
column(width = 12,
h3("Where are the people tweeting from",
style="color:blue; text-align: center;"),
# leafletOutput(outputId = "WorldMap", width = "100%", height = "500px")
plotOutput(outputId = "WorldMap")
)
)
),
# tabPanel("Country Maps",
# fluidRow(
# column(width = 6,
# h3("India"),
# plotOutput(outputId = "IndiaMap")
# ),
# column(width = 6,
# h3("USA"),
# plotOutput(outputId = "USAMap")
# )
# )
# ),
tabPanel("Statistics",
fluidRow(
column(width = 3,
fluidRow(
column(width = 12,
wellPanel(
h5("Number of Tweets Analysed", style="color:black; text-align: center;"),
h3(textOutput(outputId = "numberOfTweets"), style="color:blue; text-align: center;"),
h6("Only Tweets with complete innformation are considered for analysis.", style="color:red; text-align: center;"),
)
),
column(width = 12,
wellPanel(
h5("Tweets from", style="color:black; text-align: center;"),
h3(textOutput(outputId = "countryCount"), style="color:blue; text-align: center;"),
h4("Country(ies)", style="color:blue; text-align: center;"),
h6("See Map for details", style="color:red; text-align: center;"),
dataTableOutput(outputId = "placeCount")
)
)
)
),
column(width = 5,
fluidRow(
column(width = 12,
wellPanel(
plotOutput(outputId = "languageCount")
)
),
column(width = 12,
wellPanel(
plotOutput(outputId = "sourceCount")
)
) #,
)
),
column(width = 4,
fluidRow(
column(width = 12,
wellPanel(
h5("Tweets from", style="color:black; text-align: center;"),
h3(textOutput(outputId = "userCount"), style="color:blue; text-align: center;"),
h4("User(s)", style="color:blue; text-align: center;"),
dataTableOutput(outputId = "mostTweeter")
)
),
column(width = 12,
# wellPanel(
h5("Hashtags Used", style="color:black; text-align: center;"),
plotOutput(outputId = "hashTagWordCloud")
# )
)
)
)
)
),
tabPanel("Emotion Analysis",
h3("Only Tweets in English Language considered for analysis", style="color:blue; text-align: center;"),
tabsetPanel(id = "emotion_analysis_panel", type = "tabs",
tabPanel("Summary",
fluidRow(
column(width = 2,
fluidRow(
column(width = 12,
wellPanel(
h5("Total Word Analysed", style="color:black; text-align: center;"),
h3(textOutput(outputId = "totalWordCount"), style="color:blue; text-align: center;")
)
),
column(width = 12,
wellPanel(
h5("Unique Words Found", style="color:black; text-align: center;"),
h3(textOutput(outputId = "uniqueWordCount"), style="color:blue; text-align: center;")
)
),
column(width = 12,
wellPanel(
h5("Words with Positive Emotions Found", style="color:black; text-align: center;"),
h3(textOutput(outputId = "positiveSentimentWordCount"), style="color:blue; text-align: center;")
)
)
)
),
column(width = 3,
wellPanel(
h5("Unique Words in Tweets", style="color:black; text-align: center;"),
dataTableOutput(outputId = "uniqueWords")
)
),
column(width = 7,
fluidRow(
column(width = 12,
wellPanel(
h5("Most Prevalent Emotion in Tweets", style="color:black; text-align: center;"),
h2(textOutput(outputId = "mostPrevalentEmotion"), style="color:red; text-align: center;")
)
)
),
fluidRow(
column(width = 4,
plotOutput(outputId = "boxPlot")
),
column(width = 8,
h5("Words Used", style="color:black; text-align: center;"),
plotOutput(outputId = "wordWordCloud")
)
)
)
)
),
tabPanel(
title = "Sentiment Analysis",
fluidRow(
column(width = 6,
h3("This graph indicates the prevalent emotions in the text."),
plotOutput(outputId = "sentiments")
),
column(width = 6,
h3("This graph indicates the volume of positive and negative sentiments used through different words used in the Tweets. The sentiments are displayed from the First to the Last Tweet analysed."),
h4("Higher volume of GREEN colour in the graph indicates positivity in the text.", style="color:darkgreen; text-align: left;"),
h4("Higher volume of RED indicates negativity in the text.", style="color:red; text-align: left;"),
plotOutput(outputId = "positiveNegativeSentiments")
)
)
),
tabPanel("Word Analysis",
fluidRow(
column(width = 6,
sliderInput(inputId = "v_top_n_word_contribution",
h4("Set Top N Words to Include"),
min = 4, max = 200,
value = 10, step = 2, ticks = TRUE),
h4("This section highlights the words which have contributed to the various emotions extracted in the text."),
h4("The emotions extracted is as per the lexicon used. The lexicon assigns a emotion to the words as per generic computation preset in the knowledge base."),
h4("While evaluating this graph, specific context needs to be kept in mind before drawing conclusions."),
plotOutput(outputId = "wordContributionToSentiments")
),
column(width = 6,
sliderInput(inputId = "v_top_n_sentiment_score",
h4("Set Top N Words to Include"),
min = 4, max = 200,
value = 10, step = 2, ticks = TRUE),
h4("This graph display the different words that have contributed to the different emotions evaluated in the text."),
h3("The same word can contribute to different emotions based on the context it is used in."),
plotOutput(outputId = "sentimentScore")
)
)
)
)
)
)
),
tabPanel("Known Errors",
h3("1. When the 'Fetch Tweets' Operations fetched no Tweets, then the Display in the Analysis is all incorrect. 'Chidiya' does not become inoperational. An Error Message is displayed. And 'Chidiya' allows for the next fetch operation to be conducted.", style="color:red; text-align: left;"),
h3("2. If the 'Fetch Tweets' Operations is used to too frequently for large numberof Tweets, 'Chidiya' can misbehave. This is because of limitation of number of Tweets that can be pulled from Twitter. The solution is to invoke 'Chidiya' after a gap of 15-30 minutes and normal service is restored.", style="color:blue; text-align: left;"),
h3("3. Progress Bar not synchronised with actual progress of task.", style="color:red; text-align: left;"),
h3("4. If there is a problem with the Internet connection, 'Chidiya' cannot connect to the Twitter API. 'Chidiya' detects this. However, 'Chidiya' cannot presently recover from this error. To recover from this error, Internet Connection has to be restored and 'Chidiya' has to be revoked once again.", style="color:blue; text-align: left;")
)
)
)
)
)
################# SET UP SERVER FOR THE APPLICATION #################
server <- function(input, output, session) {
observeEvent(input$v_fetch_location,
{
if( !(input$v_search_location == "" || is.null(input$v_search_location)) ) {
tryCatch(
{
withProgress(message = 'Fetching Tweets for Location',
detail = 'This may take a while...', value = 100, {
v_tweets_to_display <<- v_tweets_for_location(input$v_search_location, input$v_number_of_tweets_location)
extractWords()
})
refreshDisplay()
# Save Statistics
saveStatisics()
},
error = function(e) {
# return a safeError if a parsing error occurs
displayError(paste("Error Fetching Tweets. This could be becuase the search does not fetch any Tweet OR the fetched Tweets does not contain any Words in English Language OR the search was for too few number of Tweets. The Graphs and other Outputs will not be updated due to this. Try fetching larger number of Tweets OR using Search Terms in English Language.", e, sep = " "))
# stop(safeError(e))
}
)
# Reset Display to default TAB
updateTabsetPanel(session, "main_panel",
selected = "Raw Data"
)
}
}
)
observeEvent(input$v_fetch,
{
if( !(input$v_search_string == "" || is.null(input$v_search_string)) ) {
tryCatch(
{
withProgress(message = 'Fetching Tweets for Search String',
detail = 'This may take a while...', value = 100, {
v_tweets_to_display <<- v_tweets(input$v_search_string, input$v_number_of_tweets)
extractWords()
})
refreshDisplay()
# Save Statistics
saveStatisics()
},
error = function(e) {
# return a safeError if a parsing error occurs
displayError(paste("Error Fetching Tweets. This could be becuase the search does not fetch any Tweet OR the fetched Tweets does not contain any Words in English Language OR the search was for too few number of Tweets. The Graphs and other Outputs will not be updated due to this. Try fetching larger number of Tweets OR using Search Terms in English Language.", e, sep = " "))
# stop(safeError(e))
}
)
# Reset Display to default TAB
updateTabsetPanel(session, "main_panel",
selected = "Raw Data"
)
}
}
)
extractWords <- function() {
tryCatch(
{
v_words_in_tweets <<- extractWordsFromTweets(
(v_tweets_to_display %>%
filter(tweet_language == 'en'))$tweet_text
) %>%
rename(word = ind) %>%
rename(n = values)
},
error = function(e) {
# return a safeError if a parsing error occurs
displayError(paste("Error Extracting Words from Tweets. This could be becuase the search does not fetch any Words in English Language OR the search for too few number of Tweets. The Graphs and other Outputs will not be updated due to this. Try fetching larger number of Tweets OR using Search Terms in English Language.", e, sep = " "))
# stop(safeError(e))
}
)
v_combined <<- sort(union(levels(v_words_in_tweets$word), levels(v_positive_sentiment$word)))
v_positive_sentiment_words <<- semi_join(mutate(v_words_in_tweets, word=factor(word, levels=v_combined)),
mutate(v_positive_sentiment, word=factor(word, levels=v_combined))) %>%
count(word, sort = TRUE)
}
refreshDisplay <- function() {
# Dummy
determineLanguageCount(FALSE)
determineSourceCount(FALSE)
determineUserCount()
determineCountryCount()
determinePlaceCount(FALSE)
showUniqueWords(FALSE)
showMostPrevalentEmotion()
# Render on Fetch
output$tweets <- renderDataTable({showTweets()})
output$tweetTimeSeries <- renderPlot({showTweetTimeSeries()})
output$WorldMap <- renderPlot({showWorldMap()})
# output$WorldMap <- renderLeaflet({showWorldMap()})
# output$IndiaMap <- renderPlot({showIndiaMap()})
# output$USAMap <- renderPlot({showUSAMap()})
output$numberOfTweets <- renderText({nrow(v_tweets_to_display)})
output$languageCount <- renderPlot({determineLanguageCount()})
output$sourceCount <- renderPlot({determineSourceCount()})
output$userCount <- renderText({determineUserCount()})
output$countryCount <- renderText({determineCountryCount()})
output$placeCount <- renderDataTable({determinePlaceCount()})
output$mostTweeter <- renderDataTable({determineMostTweeter()})
output$hashTagWordCloud <- renderPlot({showHashTagWordCloud()})
output$totalWordCount <- renderText({return(sum(v_words_in_tweets$n))})
output$uniqueWordCount <- renderText({return(nrow(v_words_in_tweets))})
output$positiveSentimentWordCount <- renderText({return(nrow(v_positive_sentiment_words))})
output$uniqueWords <- renderDataTable({showUniqueWords()})
output$boxPlot <- renderPlot({showBoxPlot()})
output$wordWordCloud <- renderPlot({showWordWordCloud()})
output$wordContributionToSentiments <- renderPlot({showWordContributionToSentiments()})
output$sentiments <- renderPlot({showSentiments()})
output$positiveNegativeSentiments <- renderPlot({showPositiveNegativeSentiments()})
output$mostPrevalentEmotion <- renderText({showMostPrevalentEmotion()})
output$sentimentScore <- renderPlot({determineSentimentScore()})
}
v_tweets <- function(p_search_string, p_number_of_tweets) {
tryCatch(
{
v_temp <- search_tweets(
p_search_string,
`-filter` = "replies",
n = p_number_of_tweets,
include_rts = FALSE,
retryonratelimit = FALSE #,
)
v_temp <- gatherTweetData(v_temp, p_search_string, p_number_of_tweets)
},
error = function(e) {
# return a safeError if a parsing error occurs
displayError(paste("Error Fetching Tweets.", e))
# stop(safeError(e))
}
)
return(v_temp)
}
v_tweets_for_location <- function(p_search_location, p_number_of_tweets) {
tryCatch(
{
v_temp <- search_tweets(
geocode = lookup_coords(p_search_location, apikey = google_maps_api_key),
`-filter` = "replies",
n = p_number_of_tweets,
include_rts = FALSE,
retryonratelimit = FALSE #,
)
v_temp <- gatherTweetData(v_temp, p_search_location, p_number_of_tweets)
},
error = function(e) {
# return a safeError if a parsing error occurs
displayError(paste("Error Fetching Tweets.", e))
# stop(safeError(e))
}
)
return(v_temp)
}
gatherTweetData <- function(p_tweets, p_search_string, p_number_of_tweets) {
v_number_fetched <<- nrow(p_tweets)
v_temp <- lat_lng(p_tweets) %>%
filter(lat != "NA") %>%
filter(lng != "NA") %>%
mutate(tweet_text = text) %>%
mutate(tweet_language = lang) %>%
mutate(tweet_source = source) %>%
mutate(tweet_user = name) %>%
mutate(tweet_country = country_code) %>%
mutate(tweet_place = place_full_name) %>%
mutate(tweet_hashtag = hashtags) %>%
mutate(tweet_followers_count = followers_count) %>%
mutate(tweet_friends_count = friends_count) %>%
mutate(tweet_urls_expanded_url = status_url) %>%
mutate(tweet_place_url = place_url) %>%
mutate(tweet_created_at = created_at) %>%
mutate(latitude = lat) %>%
mutate(longitude = lng)
v_number_analysed <<- nrow(v_temp)
v_dataframe_to_write <- v_temp
v_dataframe_to_write$SEARCHSTRING <- p_search_string
v_dataframe_to_write$DATEOFENQUIRY <- format(Sys.Date(), "%Y-%m-%d")
# saveTweetsToDatabase(v_dataframe_to_write)
v_selected_subject <<- p_search_string
v_number_requested <<- p_number_of_tweets
v_selected_date <<- format(Sys.Date(), "%Y-%m-%d")
write_as_csv(
v_dataframe_to_write,
file_name = "last_fetched.csv",
prepend_ids = TRUE,
na = "",
fileEncoding = "UTF-8"
)
return(v_temp)
}
output$totalWordCount <- renderText({
return(sum(v_words_in_tweets$n))
})
output$uniqueWordCount <- renderText({
return(nrow(v_words_in_tweets))
})
output$positiveSentimentWordCount <- renderText({
return(nrow(v_positive_sentiment_words))
})
output$uniqueWords <- renderDataTable({
showUniqueWords()
})
output$boxPlot <- renderPlot({
showBoxPlot()
})
output$tweets <- renderDataTable({
showTweets()
})
output$WorldMap <- renderPlot({
showWorldMap()
})
# output$WorldMap <- renderLeaflet({
# showWorldMap()
# })
#
# output$IndiaMap <- renderPlot({
# showIndiaMap()
# })
#
# output$USAMap <- renderPlot({
# showUSAMap()
# })
output$numberOfTweets <- renderText({
nrow(v_tweets_to_display)
})
output$languageCount <- renderPlot({
determineLanguageCount()
})
output$sourceCount <- renderPlot({
determineSourceCount()
})
output$userCount <- renderText({
determineUserCount()
})
output$mostTweeter <- renderDataTable({
determineMostTweeter()
})
output$countryCount <- renderText({
determineCountryCount()
})
output$placeCount <- renderDataTable({
determinePlaceCount()
})
output$hashTagWordCloud <- renderPlot({
showHashTagWordCloud()
})
output$wordWordCloud <- renderPlot({
showWordWordCloud()
})
showBoxPlot <- function() {
boxplot(v_words_in_tweets$n,
main = "Word Distribution",
xlab = NULL,
ylab = "Frequency",
col = "orange",
border = "brown",
horizontal = FALSE,
notch = FALSE
)
}
determineLanguageCount <- function(flag = TRUE) {
v_temp <- v_tweets_to_display %>%
ungroup() %>%
mutate(fac_language = as.factor(tweet_language)) %>%
group_by(fac_language) %>%
count(fac_language, sort = TRUE) %>%
mutate(Language = reorder(fac_language, n))
v_data <- v_temp$n
v_labels <- paste(paste(v_temp$Language, "\n",
round(v_data/sum(v_data)*100, 2), sep=" "),
"%", sep = "")
v_number_languages <<- nrow(v_temp)
if(flag) {
pie(v_data, labels = v_labels, main = "Tweet Languages")
}
}
determineSourceCount <- function(flag = TRUE) {
v_temp <- v_tweets_to_display %>%
ungroup() %>%
mutate(fac_source = as.factor(tweet_source)) %>%
group_by(fac_source) %>%
count(fac_source, sort = TRUE) %>%
mutate(Source = reorder(fac_source, n))
v_data <- v_temp$n
v_labels <- paste(paste(v_temp$Source, "\n",
round(v_data/sum(v_data)*100, 2), sep=" "),
"%", sep = "")
v_number_devices <<- nrow(v_temp)
if(flag) {
pie(v_data, labels = v_labels, main = "Tweet Source")
}
}
determineUserCount <- function() {
v_temp <- v_tweets_to_display %>%
ungroup() %>%
mutate(fac_user = as.factor(tweet_user)) %>%
group_by(fac_user) %>%
count(fac_user, sort = TRUE)
v_number_users <<- nrow(v_temp)
return(nrow(v_temp))
}
determineCountryCount <- function() {
v_temp <- v_tweets_to_display %>%
ungroup() %>%
mutate(fac_country = as.factor(tweet_country)) %>%
group_by(fac_country) %>%
count(fac_country, sort = TRUE)
v_number_countries <<- nrow(v_temp)
return(nrow(v_temp))
}
determinePlaceCount <- function(flag = TRUE) {
v_temp <- v_tweets_to_display %>%
ungroup() %>%
mutate(fac_place = as.factor(tweet_place)) %>%
group_by(fac_place) %>%
count(fac_place, sort = TRUE) %>%
mutate(Place = reorder(fac_place, n))
# Determine Place URL
v_temp$PlaceURL <- ""
for (i in 1:nrow(v_temp)) {
v_temp[i,]$PlaceURL <- head(subset(v_tweets_to_display, tweet_place == v_temp[i,]$fac_place)$tweet_place_url, 1)
}
v_temp <- v_temp %>%
mutate(place_with_link = paste("<a href='",
PlaceURL,
"', target='_blank'>",
Place,
"</a>",
sep = "")
)
v_number_places <<- nrow(v_temp)
if(flag) {
DT::datatable(
{ v_temp[,c("place_with_link", "n")] },
colnames = c("Place", "#"),
escape = FALSE,
rownames = FALSE,
options = list(
fixedColumns = TRUE,
autoWidth = FALSE,
ordering = TRUE,
pageLength = 6,
dom = 'tip'
))
}
}
determineMostTweeter <- function() {
v_temp <- v_tweets_to_display %>%
ungroup() %>%
mutate(fac_user = as.factor(tweet_user)) %>%
group_by(fac_user) %>%
count(fac_user, sort = TRUE) %>%
mutate(Tweeter = reorder(fac_user, n))
# Determine number of Followers and Friends
v_temp$Followers <- as.integer(0)
v_temp$Friends <- as.integer(0)
for (i in 1:nrow(v_temp)) {
v_temp[i,]$Followers <- as.integer(max(subset(v_tweets_to_display, tweet_user == v_temp[i,]$fac_user)$tweet_followers_count))
v_temp[i,]$Friends <- as.integer(max(subset(v_tweets_to_display, tweet_user == v_temp[i,]$fac_user)$tweet_friends_count))
}
DT::datatable(
{ v_temp[,c("Tweeter", "n", "Followers", "Friends")] },
colnames = c("Tweeter", "#", "Followers", "Friends"),
escape = TRUE,
rownames = FALSE,
options = list(
fixedColumns = TRUE,
autoWidth = FALSE,
ordering = TRUE,
pageLength = 3,
dom = 'tip'
))
}
showHashTagWordCloud <- function() {
tryCatch(
{
v_corpus <- Corpus(VectorSource(v_tweets_to_display$tweet_hashtag))
# Create the Term Document Matrix after cleaning the Corpus
v_tdm <- TermDocumentMatrix(v_corpus,
control =
list(removePunctuation = TRUE,
stopwords = TRUE,
tolower = TRUE,
stemming = TRUE,
removeNumbers = TRUE,
bounds = list(global = c(1, Inf))
)
)
# Find the Frequent Words
v_ft <- findFreqTerms(v_tdm, lowfreq = 1, highfreq = Inf)
# Convert to a Matrix
v_matrix <- as.matrix(v_tdm[v_ft,])
# Sort the Words in DESCENDING Order and create Data Frame
v_data <- stack(sort(apply(v_matrix, 1, sum), decreasing = TRUE))
v_number_hastag_found <<- nrow(v_data)
withProgress(message = 'Generating Word Cloud',
detail = 'This may take a while...', value = 0, {
wordcloud(words = v_data$ind, freq = v_data$values,
min.freq = 1,
max.words = 100,
random.order=FALSE,
colors=brewer.pal(8, "Dark2")
)
})
},
error = function(e) {
# return a safeError if a parsing error occurs
displayError(paste("Error creating HashTag Word Cloud", e))
# stop(safeError(e))
}
)
}
output$existingSearchesWordCloud <- renderPlot({
tryCatch(
{
v_corpus <- Corpus(VectorSource(v_existing_searches$SEARCH_STRING))
# Create the Term Document Matrix after cleaning the Corpus
v_tdm <- TermDocumentMatrix(v_corpus,
control =
list(removePunctuation = TRUE,
stopwords = TRUE,
tolower = TRUE,
stemming = TRUE,
removeNumbers = TRUE,
bounds = list(global = c(1, Inf))
)
)
# Find the Frequent Words
v_ft <- findFreqTerms(v_tdm, lowfreq = 1, highfreq = Inf)
# Convert to a Matrix
v_matrix <- as.matrix(v_tdm[v_ft,])
# Sort the Words in DESCENDING Order and create Data Frame
v_data <- stack(sort(apply(v_matrix, 1, sum), decreasing = TRUE))
v_number_hastag_found <<- nrow(v_data)
withProgress(message = 'Generating Word Cloud',
detail = 'This may take a while...', value = 0, {
wordcloud(words = v_data$ind, freq = v_data$values,
min.freq = 1,
max.words = 100,
random.order=FALSE,
colors=brewer.pal(8, "Dark2")
)
})
},
error = function(e) {
# return a safeError if a parsing error occurs
displayError(paste("Error creating Existing Searches Word Cloud", e))
# stop(safeError(e))
}
)
})
showWordWordCloud <- function() {
withProgress(message = 'Generating Word Cloud',
detail = 'This may take a while...', value = 0, {
wordcloud(words = v_words_in_tweets$word, freq = v_words_in_tweets$n,
min.freq = 1,
max.words = 100,
random.order=FALSE,
colors=brewer.pal(8, "Dark2")
)
})
}
showTweets <- function() {
withProgress(message = 'Tabulating Tweets',
detail = 'This may take a while...', value = 100, {
v_temp <- v_tweets_to_display %>%
mutate(tweet_with_link = paste("<a href='",
tweet_urls_expanded_url,
"', target='_blank'>",
tweet_text,
"</a>",
sep = "")
)
DT::datatable(
{ select(v_temp, tweet_with_link) },
colnames = c('Tweet Text (Click on the Tweet to see the Original Tweet)'),
caption = htmltools::tags$caption(
style = 'caption-side: bottom; text-align: center;',
'Table 1: ',
htmltools::em('Fetched Tweets')
),
extensions = 'Buttons',
escape = FALSE,
options = list(
fixedColumns = TRUE,
autoWidth = FALSE,
ordering = TRUE,
pageLength = 10,
dom = 'Bftsp',
buttons = c('copy', 'csv', 'excel')
))
})
}
output$tweetTimeSeries <- renderPlot({
showTweetTimeSeries()
})
showTweetTimeSeries <- function() {
# Save current locale
loc <- Sys.getlocale("LC_TIME")
# Set Locale
Sys.setlocale("LC_TIME", "C")
# Convert to POSIXct
v_tweets_to_display$tweet_created_at <- as.POSIXct(v_tweets_to_display$tweet_created_at, '%Y-%m-%d %H:%M:%S', tz = Sys.timezone())
# Then set back to the old locale
Sys.setlocale("LC_TIME", loc)
## Plot time series of tweets frequency
ts_plot(v_tweets_to_display[, c("tweet_created_at")], "mins") +
ggplot2::theme_minimal() +
ggplot2::theme(plot.title = ggplot2::element_text(face = "bold")) +
ggplot2::labs(
x = NULL, y = NULL,
title = paste("Frequency of", v_selected_subject, "Twitter statuses", sep = " "),
subtitle = "Twitter status (tweet) counts aggregated using one-minute intervals",
caption = "\nSource: Data collected from Twitter's REST API via rtweet"
)
}
showUniqueWords <- function(flag = TRUE) {
v_number_words <<- sum(v_words_in_tweets$n)
v_number_unique_words <<- nrow(v_words_in_tweets)
if(flag) {
withProgress(message = 'Tabulating Unique Words',
detail = 'This may take a while...', value = 100, {
DT::datatable(
{ v_words_in_tweets[, c("word", "n")] },
colnames = c('Word', '#'),
caption = htmltools::tags$caption(
style = 'caption-side: bottom; text-align: center;',
'Table 4: ',
htmltools::em('Unique Words')
),
extensions = 'Buttons',
escape = TRUE,
rownames = FALSE,
options = list(
fixedColumns = TRUE,
autoWidth = FALSE,
ordering = TRUE,
pageLength = 5,
dom = 'Bftsp',
buttons = c('copy', 'csv', 'excel')
))
})
}
}
showWorldMap <- function() {
withProgress(message = 'Generating Map',
detail = 'This may take a while...', value = 100, {
par(mar = c(0, 0, 0, 0))
map( 'world', fill = FALSE, col = 1:10, wrap=c(-180,180) )
## plot lat and lng points onto state map
with(v_tweets_to_display, points(lng, lat, pch = 21, cex = .75, col = rgb(1, 0, 0, 1)))
# leaflet(v_tweets_to_display) %>%
# addCircles(lng = ~longitude, lat = ~latitude) %>%
# addTiles() %>%
# addCircleMarkers(data = v_tweets_to_display, lat = ~latitude, lng = ~longitude,
# radius = 3,
# popup = ~as.character(tweet_text),
# # color = ~pal(Category),
# stroke = FALSE, fillOpacity = 0.8) #%>%
# # addLegend(pal=pal, values=bb_data$Category,opacity=1, na.label = "Not Available")%>%
# # addEasyButton(easyButton(
# # icon="fa-crosshairs", title="ME",
# # onClick=JS("function(btn, map){ map.locate({setView: true}); }")))
})
}
# showIndiaMap <- function() {
# withProgress(message = 'Generating Map',
# detail = 'This may take a while...', value = 100, {
# par(mar = c(0, 0, 0, 0))
# maps::map("world", "India", lwd = .25)
#
# ## plot lat and lng points onto state map
# with(v_tweets_to_display, points(lng, lat, pch = 20, cex = .75, col = rgb(0, .3, .7, .75)))
# })
# }
#
# showUSAMap <- function() {
# withProgress(message = 'Generating Map',
# detail = 'This may take a while...', value = 100, {
# ## plot state boundaries
# par(mar = c(0, 0, 0, 0))
# maps::map("usa", lwd = .25)
#
# ## plot lat and lng points onto state map
# with(v_tweets_to_display, points(lng, lat, pch = 20, cex = .75, col = rgb(0, .3, .7, .75)))
# })
# }
# output$wordContributionToSentiments <- shinyRenderWidget(quoted = TRUE, {
# showWordContributionToSentiments()
# })
output$wordContributionToSentiments <- renderPlot({
showWordContributionToSentiments()
})
showWordContributionToSentiments <- function() {
v_data <- determineEmotionCount(v_words_in_tweets) %>%
filter(row_number() < input$v_top_n_word_contribution) %>%
group_by(v_original_sentiment) %>%
ungroup() %>%
mutate(word = reorder(word, v_original_n))
v_data$word <- as.character(v_data$word)
v_data <- data.frame(apply(v_data, 2, unclass))
ggplot(aes(x = word, y = v_original_n, fill = v_original_sentiment), data = v_data, scale_x_continuous(breaks = NULL)) +
geom_col(show.legend = FALSE) +
facet_wrap(~v_original_sentiment, scales = "free_y") +
labs(y = "Words Contribution to Individual Sentiments", x = NULL) +
coord_flip()
}
output$sentiments <- renderPlot({
showSentiments()
})
showSentiments <- function() {
v_emotions <- determineEmotionCount(v_words_in_tweets) %>%
select(index, anger, anticipation, disgust, fear, joy,
sadness, surprise, trust) %>%
melt(id = "index") %>%
rename(linenumber = index, sentiment_name = variable, value = value)
v_emotions_group <- group_by(v_emotions, sentiment_name)
v_by_emotions <- summarise(v_emotions_group, values=sum(value))
ggplot(aes(reorder(x=sentiment_name, values), y=values, fill=sentiment_name), data = v_by_emotions) +
geom_bar(stat = 'identity') +
ggtitle('Sentiment in Tweets') +
coord_flip() +
theme(legend.position="none")
}
output$positiveNegativeSentiments <- renderPlot({
showPositiveNegativeSentiments()
})
showPositiveNegativeSentiments <- function() {
v_data <- determineEmotionCount(v_words_in_tweets) %>%
mutate(v_original_n = ifelse(v_positive_negative == "negative",
-v_original_n, v_original_n))
ggplot(data = v_data, aes(x = index, y = v_original_n, fill = v_positive_negative)) +
geom_bar(stat = 'identity', position = position_dodge()) +
theme_minimal() +
ylab("Sentiment") +
ggtitle("Positive and Negative Sentiment in Tweets") +
scale_color_manual(values = c("red", "dark green")) +
scale_fill_manual(values = c("red", "dark green"))
}
output$mostPrevalentEmotion <- renderText({
showMostPrevalentEmotion()
})
showMostPrevalentEmotion <- function() {
v_emotions <- determineEmotionCount(v_words_in_tweets) %>%
select(index, anger, anticipation, disgust, fear, joy,
sadness, surprise, trust) %>%
melt(id = "index") %>%
rename(linenumber = index, sentiment_name = variable, value = value)
v_emotions_group <- group_by(v_emotions, sentiment_name)
v_by_emotions <- summarise(v_emotions_group, values = sum(value))
v_temp <- v_by_emotions %>%
mutate_if(is.factor, as.character)
v_prevalent_emotion <<- ifelse(nrow(subset(v_temp, values == max(values))) == 1,
unname(unlist(subset(v_temp, values == max(values)))),
"No Prevalent Emotion")
return(v_prevalent_emotion)
}
output$sentimentScore <- renderPlot({
determineSentimentScore()
})
determineSentimentScore <- function() {
v_combined <- sort(union(levels(v_words_in_tweets$word), levels(v_nrc$word)))
v_word_count <- inner_join(mutate(v_words_in_tweets, word=factor(word, levels=v_combined)),
mutate(v_nrc, word=factor(word, levels=v_combined))
) %>%
count(word, sentiment, sort = TRUE)
v_data <- v_word_count %>%
filter(row_number() < input$v_top_n_sentiment_score) %>%
mutate(n = ifelse(sentiment %in% v_negative_emotions, -n, n)) %>%
mutate(word = reorder(word, n))
ggplot(aes(word, n, fill = sentiment), data = v_data) +
geom_col() +
coord_flip() +
labs(y = "Sentiment Score")
}
}
# Run the application
shinyApp(ui = ui, server = server)
##
## Listening on http://127.0.0.1:6360
