For Loop in Shiny Server: How to Not Overwrite Values with Each ActionButton Press? - for-loop

I am trying to create an app in which part of the UI displays a wordcloud generated by words/strings inputted by the user. To do this, I pass the input to a for loop which is supposed to then store every input in an empty vector with ever press of the action button. However, I am encountering a couple problems, though: one in that no word cloud is displaying, with no error indicated, and another in that the for loop will just overwrite the vector each time the button is pressed, such that it always only has one word in it instead of gradually adding more words. I figured the lack of display is because there is only one word, and it seems like wordcloud needs at least two words to print anything: so how can I get the for loop to work as intended with Shiny?
library(shiny)
library(stringr)
library(stringi)
library(wordcloud2)
ui <- fluidPage(
titlePanel("Strings Sim"),
sidebarLayout(
sidebarPanel(
textInput("string.input", "Create a string:", placeholder = "string <-"),
actionButton("go1", "GO!")
),
mainPanel(
textOutput("dummy"),
wordcloud2Output("the.cloud")
)
)
)
server <- function(input, output, session) {
observeEvent(input$go1, {
high.strung <- as.vector(input$string.input)
empty.words <- NULL
for (i in high.strung) {
empty.words <- c(empty.words, i)
}
word.vector <-matrix(empty.words, nrow = length(empty.words),ncol=1)
num.vector <- matrix(sample(1000), nrow=length(empty.words),ncol=1)
prelim <- cbind(word.vector, num.vector)
prelim.data <- as.data.frame(prelim)
prelim.data$V2 <- as.numeric(as.character(prelim.data$V2))
output$the.cloud <- renderWordcloud2(
wordcloud2(prelim.data)
)
print(empty.words)
})
}
shinyApp(ui=ui,server=server)
The operation works as intended when I run it without Shiny code; I basically just use a string in place of the input, run through the for loop a few times to generate the dataframe to be used by word cloud, and get something like the attached picture, which is what I am after:
Functional code without Shiny:
empty.words <- NULL
#Rerun below here to populate vector with more words and regenerate wordcloud
high.strung <- as.vector("gumbo")
for (i in high.strung) {
empty.words <- c(empty.words, i)
return(empty.words)
}
word.vector <-matrix(empty.words, nrow = length(empty.words),ncol=1)
num.vector <- matrix(sample(1000), nrow=length(empty.words),ncol=1)
prelim <- cbind(word.vector, num.vector)
prelim.data <- as.data.frame(prelim)
prelim.data$V2 <- as.numeric(as.character(prelim.data$V2))
str(prelim.data)
wordcloud2(prelim.data)
Any help is much appreciated!
Edit: More pictures of the desired output using the non-Shiny code. (I editted the dataframe output to overlay the wordcloud just to show the cloud and frame in one picture, i.e. don't need them to display in that way). With each press of the button, the inputted word(s) should be added to the dataframe that builds the cloud, gradually making it larger.The random number vector which determines the size doesn't have to stay the same with each press, but each inputted word should be preserved in a vector.

Your app is missing reactivity. You can read about that concept here. You can input strings and as soon as at least two words are in the dataframe the wordcloud is rendered. If you don't want multi-word strings to be split just take out the str_split() function.
library(shiny)
library(stringr)
library(stringi)
library(wordcloud2)
ui <- fluidPage(
titlePanel("Strings Sim"),
sidebarLayout(
sidebarPanel(
textInput("string.input", "Create a string:", placeholder = "string <-"),
actionButton("go1", "GO!")
),
mainPanel(
textOutput("dummy"),
wordcloud2Output("the.cloud")
)
)
)
server <- function(input, output, session) {
rv <- reactiveValues(high.strung = NULL)
observeEvent(input$go1, {
rv$high.strung <- c(rv$high.strung,str_split(c(input$string.input), pattern = " ") %>% unlist)
})
prelim.data <- reactive({
prelim <- data.frame(
word.vector = rv$high.strung,
num.vector = sample(1000, length(rv$high.strung), replace = TRUE)
)
})
output$the.cloud <- renderWordcloud2(
if (length(rv$high.strung) > 0)
wordcloud2(prelim.data())
)
}
shinyApp(ui=ui,server=server)

Related

Performing a calculation on several data frames with a for loop

I have a group dataframes I want to create a for loop for that will perform a calculation on all of them without having to manually enter the name of the dataframe each time.
example:
df1
df2
df3
#first I try to create a list of the dataframe names to iterate through
dflist <- list(c(df1, df2, df3))
Then I attempt to iterate through it including the calculation. Simplified version here:
for (i in 1:length(dflist)) {
x <- dflist[i]$columnone[1] %>%
y <- dflist[i]$columntwo[1] %>%
z <- mean(dflist[i]$columnthree) %>%
paste0("result_",i) <- x-y/z
}
I keep being told that z cannot be found.
What am I doing wrong?
(the paste0 line at the end is meant to store the result for each dataframe as its own new variable but is not the focus of the question)

Change row names in data frame in R

I've got the following code to iterate through directory/subdirectory, pick out certain files, read a value in them, and populate a new data frame with those values. It works, with a few issues...
Here's the code
wd = setwd("/Users/TK/Downloads/DataCSV")
Groups <- list.dirs(path = wd, full.names = TRUE, recursive = FALSE)
Subj <- list.dirs(path = Groups, full.names = TRUE, recursive = FALSE)
section_area_vector <- numeric()
for(i in Subj) {
setwd(i)
section_area <- list.files(path = i, pattern = "section_area",
full.names = FALSE, recursive = TRUE)
read_area <- sapply(section_area, function(x)read.csv(x)[1,2])
total_area_subj <- sum(read_area)
section_area_vector <- rbind(section_area_vector, total_area_subj)
}
section_area_data <- as.data.frame(section_area_vector)
colnames(section_area_data)[colnames(section_area_data) ==
"V1"] <- "Area"
The output looks like this table:
How do I get the row names to appear as subj.1, subj.2, subj.3
Also, I seem to have to run the code twice, with the first time it not working (basically a null result), but the second time it works and yields the table - any ideas why this might be?
Also, is this the best way to write this task, or is there something more elegant? I know "for loops" are frowned upon as they are slow (eventually there will be lots of data to work with)...tried using sapply functions but got lost in the syntax. Would love some suggestions if this code can be improved.

stargazer: line break in F Statistic / df

when creating a table with stargazer, I would like to add a new line befor the degrees of freedom (s. below: before the opening bracket). Could someone help me with the correct call, I couldn't find it in the package documentation. (Apologies for not creating reproducible code, I don't know how to simulate a regression with fake data. I hope someone can still help me!)
As far as I know, there is no built-in functionality to show F-statistics and dfs in distinct lines. You have to hack the output of stargazer() to make a table that you want. A user-defined function in this answer (show_F_in_two_lines()) will produce a table as shown below.
library(stringr)
show_F_in_two_lines <- function(stargazer) {
# `Stringr` works better than base's regex
require(stringr)
# If you remove `capture.output()`, not only the modified LaTeX code
# but also the original code would show up
stargazer <- stargazer |>
capture.output()
# Reuse the index in which F-statistics are displayed
position_F <- str_which(stargazer, "F Statistic")
# Extract only F-statistics
Fs <- stargazer[position_F] |>
str_replace_all("\\(.*?\\)", "")
# Extract only df values and make a new line for them
dfs <- stargazer[position_F] |>
str_extract_all("\\(.*?\\)") |>
unlist() |>
(
\(dfs)
paste0(" & ", dfs, collapse = "")
)() |>
paste0(" \\\\")
# Reuse table elements that are specified
# after the index of F-statistics
after_Fs <- stargazer[-seq_len(position_F)]
c(
stargazer[seq_len(position_F - 1)],
Fs,
dfs,
after_Fs
) |>
cat(sep = "\n")
}
stargazer(
header = FALSE,
lm.out.1,
lm.out.2,
lm.out.3,
lm.out.4,
lm.out.5
) |>
show_F_in_two_lines()

Quantstrat applystrategy incorrect dimensions trying to work with manual mktdata OHCLV data vs getSymbols

I apologize for not having a working example atm
All I really need is a sample format for how to load multiple symbols from a csv
The function call says
https://www.rdocumentation.org/packages/quantstrat/versions/0.16.7/topics/applyStrategy
mktdata
"an xts object containing market data. depending on indicators, may need to be in OHLCV or BBO formats, default NULL"
The reason I don't wish to use getSymbols is because I do some preprocessing and load the data from csv's because my internet is shoddy. I do download data, but about once a week. My preprocess produces different symbols from a subset of 400 symbols based on the time periods I scan. I'm trying to frontload all my download processing, and no matter what I try, I can't get it to load from either a dataframe or an xts object. Right now I'm converting from csv to dataframe to xts and attempting to load.
I have noticed my xts objects differ from the getSymbols (error about incorrect dimensions). Specifically if I call colnames. Mine will say none, where as getSymbols subelements list 6 columns.
Anyways. What I would like to do, is see a minimal example of loading custom OHCLV data from a csv into an xts that can be supplied as an object to mktdata = in the applyStrategy call. That way I can format my code to match
I have the code to load and create the xts object from a dataframe.
#loads from a dataframe which includes Symbol, Date, Open, High, Low, Close, Volume, Adjusted
tempData <- symbol_data_set[symbol_data_set$Symbol %in% symbolstring & symbol_data_set$Date >= startDate & symbol_data_set$Date<=endDate,]
#creates a list of xts
vectorXTS <- mclapply(symbolstring,function(x)
{
df <- symbol_data_set[symbol_data_set$Symbol==x & symbol_data_set$Date >= startDate & symbol_data_set$Date<=endDate,]
#temp <- as.xts(
temp <- cbind(as.data.frame(df[,2]),as.data.frame(df[,-1:-2]))
rownames(df) <- df$Date
#,order.by=as.POSIXct(df$Date),)
z <- read.zoo(temp, index = 1, col.names=TRUE, header = TRUE)
#sets names to Symbol.Open ...
colnames(z) <- c(paste0(symbolstring[x],".Open"),paste0(symbolstring[x],".High"),paste0(symbolstring[x],".Low"),paste0(symbolstring[x],".Close"),paste0(symbolstring[x],".Volume"),paste0(symbolstring[x],".Adjusted"))
return(as.xts(z, match.to=AAPL))
#colnames(as.xts(z))
})
names(symbolstring) <- symbolstring
names(vectorXTS) <- symbolstring
for(i in symbolstring) assign(symbolstring[i],vectorXTS[i])
colnames(tempData) <- c(paste0(x,".Symbol"),paste0(x,".Date"),paste0(x,".Open"),paste0(x,".High"),paste0(x,".Low"),paste0(x,".Close"),paste0(x,".Volume"),paste0(x,".Adjusted"))
head(tempData)
rownames(tempData) <- tempData$Date
#attempts to use this xts object I created
results <- applyStrategy(strategy= strategyName, portfolios = portfolioName,symbols=symbolstring,mktdata)
error
Error in mktdata[, keep] : incorrect number of dimensions
This is how you store an xts getSymbols object in a file and reload it for use for quantStrat's applyStrategy (two methods shown, the read.xts method is the ideal as you can see how the csv's are stored)
getSymbols("AAPL",from=startDate,to=endDate,adjust=TRUE,src='yahoo',auto.assign = TRUE)
saveRDS(AAPL, file= 'stuff.Rdata')
AAPL <- readRDS(file= 'stuff.Rdata')
write.zoo(AAPL,file="zoo.csv", index.name = "Date", row.names=FALSE)
rm(AAPL)
AAPL <- as.xts(read.zoo(file="zoo.csv",header = TRUE))
If you want to work with multiple symbols, I had this work.
Note initially I had a reference to the 1st element, i.e. vectorXTS[[1]], and it worked
Note: at least setting it up like this got it to run...
vectorXTS <- mclapply(symbolstring,function(x)
{
df <- symbol_data_set[symbol_data_set$Symbol==x & symbol_data_set$Date >= startDate & symbol_data_set$Date<=endDate,]
temp <- cbind(as.data.frame(df[,2]),as.data.frame(df[,-1:-2]))
rownames(df) <- df$Date
z <- read.zoo(temp, index = 1, col.names=TRUE, header = TRUE)
colnames(z) <- c(paste0(x,".Open"),paste0(x,".High"),paste0(x,".Low"),paste0(x,".Close"),paste0(x,".Volume"),paste0(x,".Adjusted"))
write.zoo(z,file=paste0(x,"zoo.csv"), index.name = "Date", row.names=FALSE)
return(as.xts(read.zoo(file=paste0(x,"zoo.csv"),header = TRUE)))
})
names(vectorXTS) <- symbolstring
#this will assign to memory vs vectorXTS if one wishes to avoid using mktdata = vectorXTS[[]]
for(i in symbolstring) assign(i,vectorXTS[[i]])
results <- applyStrategy(strategy= strategyName, portfolios = portfolioName,symbols=symbolstring, mktdata = vectorXTS[[]])
#alternatively
#results <- applyStrategy(strategy= strategyName, portfolios = portfolioName,symbols=symbolstring)

R Shiny- How to apply user inserted text to run a function (R code) and produce final ggplot output

I have a basic R code where, within the code, a user can enter a country name "Argentina". Using that value/name, the code will run an analysis for the "Argentina" subset of the pre-loaded data. Finally, the code will produce a simple ggplot showing results.
I have tried to make this code into a Shiny App, however I cannot get it to work properly. My main issue is that I cannot seem to get the data analysis in the Server section to work, which should subsequently feed into the plotting code. More importantly, I cannot seem to get the user inputted country name to feed into my data analysis.
Without going into the detail of the code, could someone kindly point me in the right direction of how one would do this in Shiny? e.g.
1) Field for user input;
2) Use that user input as an object used in the code;
3) subsequently run the analysis (whatever it might be); and
4) use the final analysis data frame in ggplot for a figure output to be displayed in the shiny app.
Many thanks for your assistance and time.
Please see my shinny code currently used, with reproducible data using MTcars
library(shiny)
# Some Sample data to run app using mtcars
mtcars$Primary<- rownames(mtcars)
mtcars$Area <- "Argentina"
mtcars$Y2016<- mtcars$mpg
mtcars$Element <- "Gross Production Value (constant 2004-2006 million US$)"
# Defining UI ----
ui <- pageWithSidebar(
# App title ----
headerPanel("Subsector Selection Tool"),
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Country name
textInput("country", "Please enter country name", "")#,
),
# Main panel for displaying outputs ----
mainPanel("")
)
# Define server logic to plot various variables against mpg ----
server <- function(input, output) {
#Trying to make user inputed country name into an object to be used in
"reactive" code below, which in turn is be used to make dataset for graphing
country_interest <- reactive({
paste(input$country)
})
#Here I am trying to make the data analysis code run and create desired
dataset for graphing, and subsetting for country selected by user
Value_c_e_PRIM_x <- reactive({
Value_c <- Value[which(Value$Area==country_interest),]
Value_c_e <- Value_c[which(Value_c$Element=="Gross Production Value (constant 2004-2006 million US$)"),]
Value_c_e_PRIM$Primary <- Value_c_e_PRIM[,120]
Value_c_e_PRIM[,120] <- NULL
Value_c_e_PRIM <- Value_c_e_PRIM %>% group_by(Primary,Element) %>% summarise_at(vars(Y2016), sum)
Value_c_e_PRIM$Category <- "Value of Production"
Value_c_e_PRIM$Value <- Value_c_e_PRIM$Y2016
Value_c_e_PRIM <- Value_c_e_PRIM %>% group_by(Category,Primary) %>% summarise_at(vars(Value), mean)
})
#Graphing section, if Ihave the dataset "Value_c_e_PRIM_x" pre-loaded (e.g. not derived in code above), the figure is successfully shown in the output.
output$plot <- renderPlot({
Graph_data <- Value_c_e_PRIM_x
Graph_data$Score_type <- "Competitiveness Score"
Graph_data$`Competitiveness Score` <- round(Graph_data$Value, 2)
title1 <-paste("Competitiveness\nby",paste0(country_interest),"Subsector")
mycol <-c("red", "yellow", "#006600")
ggplot(data = Graph_data, aes(x = Score_type, y = reorder(Primary,Value), fill=Value)) +
geom_tile(aes(fill = Value), colour= "white")+
geom_text(data=Graph_data,aes(y=Primary, x= Score_type, label=Value))+
labs(title =(paste0(title1)),y = "", x = "")+
scale_fill_gradientn(colours = mycol)+
theme(legend.title=element_blank())+
theme(legend.position="bottom")
})
}
shinyApp(ui, server)

Resources