Why does this Shiny App not display dataframe using RStudio? - r

I have a list of data frames, ls_df, comprising two dataframes from the datasets package.
I am trying to load these two dataframes into a Shiny app using the code below. However, it does not work, with the error message no item called "ls_df" on the search list being returned. Does anyone know how to fix?
ls_df <- list(datasets::airmiles,
datasets::AirPassengers)
ui <- fluidPage(
selectInput("ls_df", label = "Dataset", choices = ls("ls_df")),
verbatimTextOutput("summary"),
tableOutput("table")
)
server <- function(input, output, session) {
output$summary <- renderPrint({
dataset <- get(input$ls_df, "ls_df")
summary(dataset)
})
output$table <- renderTable({
dataset <- get(input$ls_df, "ls_df")
dataset
})
}
shinyApp(ui, server)

The list needs the names:
library(shiny)
ls_df <- list(airmiles=datasets::airmiles,AirPassengers=datasets::AirPassengers)
ui <- fluidPage(
selectInput("ls_df", label = "Dataset", choices = names(ls_df)),
verbatimTextOutput("summary"),
tableOutput("table")
)
server <- function(input, output, session) {
output$summary <- renderPrint({
dataset <- ls_df[[input$ls_df]]
summary(dataset)
})
output$table <- renderTable({
dataset <- ls_df[[input$ls_df]]
dataset
})
}
shinyApp(ui, server)

Two things wrong:
Your list needs names, as discussed in PorkChop's answer. If this were the only required change, then PorkChop's answer would suffice.
get(input$ls_df, "ls_df") is an error. This should be rather clear, though, since it prevents the shiny interface from starting. This error is because the envir= argument of ls and get require an object, not the character name of an object. (One could go "inception" and use ls(get("ls_df")) and similarly for get, but that hardly seems necessary or useful.)
ls_df <- list(airmiles=datasets::airmiles, # <-- named list
AirPassengers=datasets::AirPassengers)
ui <- fluidPage(
selectInput("ls_df", label = "Dataset", choices = ls(ls_df)), # <-- no quotes
verbatimTextOutput("summary"),
tableOutput("table")
)
server <- function(input, output, session) {
output$summary <- renderPrint({
dataset <- get(input$ls_df, ls_df) # <-- no quotes
summary(dataset)
})
output$table <- renderTable({
dataset <- get(input$ls_df, ls_df) # <-- no quotes
dataset
})
}

Related

How to efficiently subset a dataframe in R Shiny?

In the below example code I reactively subset the mtcars dataframe inside the renderPlot() function. However, in my larger App with many render functions in the server section I am having to repeat the same rv$x[1:input$samples], etc., over and over in many places. How would I apply this subsetting instead "at the top", into the rv <- reactiveValues(...) function itself or equivalent "master function"? I tried subsetting inside the reactiveValues() and got the message "Warning: Error in : Can't access reactive value 'samples' outside of reactive consumer. Do you need to wrap inside reactive() or observer()?" I assumed incorrectly that the reactiveValues() function is a "reactive consumer".
If someone can answer this basic understanding question, please explain the logic for correctly subsetting "at the top" because I am getting very embarrassed by my repeated questions about Shiny reactivity.
library(shiny)
ui <- fluidPage(
sliderInput('samples','Nbr of samples:',min=2,max=32,value=16),
plotOutput("p")
)
server <- function(input, output, session) {
rv <- reactiveValues(
x = mtcars$mpg,
y = mtcars$wt
)
output$p <- renderPlot({plot(rv$x[1:input$samples],rv$y[1:input$samples])})
}
shinyApp(ui, server)
There are multiple ways you can handle this.
Here is one way to create new subset reactive values inside observe.
library(shiny)
ui <- fluidPage(
sliderInput('samples','Nbr of samples:',min=2,max=32,value=16),
plotOutput("p")
)
server <- function(input, output, session) {
rv <- reactiveValues(
x = mtcars$mpg,
y = mtcars$wt
)
observe({
rv$x_sub <- rv$x[1:input$samples]
rv$y_sub <- rv$y[1:input$samples]
})
output$p <- renderPlot({plot(rv$x_sub,rv$y_sub)})
}
shinyApp(ui, server)
I'd use reactiveValues only if you need them to be modified in different places.
reactive is shiny's basic solution for this:
library(shiny)
library(datasets)
ui <- fluidPage(
sliderInput(
'samples',
'Nbr of samples:',
min = 2,
max = 32,
value = 16
),
plotOutput("p")
)
server <- function(input, output, session) {
reactive_mtcars <- reactive({mtcars[1:input$samples,]})
output$p <- renderPlot({
plot(reactive_mtcars()$mpg, reactive_mtcars()$wt)
})
}
shinyApp(ui, server)

Get filtered data in reactable in shiny

I have a shiny application that lets the user filter data, eventually the user should be able to download the filtered data but I cannot access the filtered/shown data from reactable.
An MWE would be the following: (Note that the getReactableState() function does not return the filtered data but would work if one had to select all filtered data.)
library(shiny)
library(reactable)
ui <- fluidPage(
reactableOutput("table"),
verbatimTextOutput("table_state")
)
server <- function(input, output) {
output$table <- renderReactable({
reactable(iris, filterable = TRUE)
})
output$table_state <- renderPrint({
print(getReactableState("table")) #< wrong code here...
# the goal would be to get the rows which are currently shown here
})
}
shinyApp(ui, server)
Not a full answer, but at least it allows to download the filtered data as a CSV (solution from here):
tags$button("Download as CSV", onclick = "Reactable.downloadDataCSV('table')")
The full solution looks like this:
library(shiny)
library(reactable)
ui <- fluidPage(
tags$button("Download as CSV", onclick = "Reactable.downloadDataCSV('table')"),
reactableOutput("table")
)
server <- function(input, output) {
output$table <- renderReactable({
reactable(iris, filterable = TRUE)
})
}
shinyApp(ui, server)

Can you parse an XML into R Shiny and view as a data frame?

I'm new to R-shiny and I'm trying to develop an R-shiny application that would allow the user to upload an XML file, view the table as a data frame, and then download it as a CSV.
I've so far had no luck anywhere trying to find info on parsing XML's into R-shiny. Below is some code that I found from someone else's post on here which allows you to read in an XML and it will display the raw text, but I'm looking to get a proper data frame so that I can do some analysis on the data that the user uploads.
library(shiny)
ui <- fluidPage(
fileInput("File", "Choose file"),
tableOutput("Data")
)
server <- function(input, output, session) {
Data <- eventReactive(input$File, {
read_xml(input$File$datapath)
})
output$Data <- renderTable({
head(xml_text(Data()))
})
}
shinyApp(ui, server)
The code to do what I need in R is very simple, but converting this over to R-shiny is causing me lots of trouble.
data <- xmlParse("C:/filepath/data.xml")
df <- xmlToDataFrame(data, nodes =getNodeSet(data, "//nm:Row",
namespaces=c(nm = "urn:schemas-microsoft-com:office:spreadsheet")))
Can anyone help please?
Thanks in advance!
You can use package XMLthe same way you do in base R:
library(shiny)
library(XML)
ui <- fluidPage(
fileInput("File", "Choose file"),
tableOutput("Data")
)
server <- function(input, output, session) {
df <- eventReactive(input$File, {
xmlToDataFrame(input$File$datapath)
})
output$Data <- renderTable( head( df()))
}
shinyApp(ui, server)
Update: I've managed to solve the issue by writing a function that converts the "table" node of the xml into a data frame, and calling this function from within the server.
converter <- function(xml_data){
data <- xmlParse(xml_data)
df <- xmlToDataFrame(data, nodes =getNodeSet(data, "//nm:Row",
namespaces=c(nm = "urn:schemas-microsoft-com:office:spreadsheet")))
colnames(df) <- df[1,]
df <- df[-1, ]
return(df)
}
ui <- fluidPage(
fileInput("File", "Choose file"),
tableOutput("Data")
)
server <- function(input, output, session) {
df <- eventReactive(input$File, {
converter(input$File$datapath)
})
output$Data <- renderTable( head( df()))
}
shinyApp(ui, server)

How to use original and updated version of reactive data.table in Shiny?

I'm trying to include a dataset in a Shiny app that first gets read in and used as is, e.g. by displaying it as a table. I would like to allow the user to then be able to manipulate this dataset and update the same table output with the updated dataset.
I can get both parts to work separately - I can display the original data, and I can display reactive updated data. But I can't figure out how to get both to work using the same dataset? The below code is a simple example using iris, with an attempt to display the original dataset and then rbinding it so there are twice as many rows to display in the updated dataset when you hit 'Run'. Note that I've converted the data to data.table because my actual code will be using data.table a lot.
library(shiny)
library(data.table)
iris <- as.data.table(iris)
ui <- fluidPage(
fluidRow(column(4, actionButton("run", "Run"))),
fluidRow(column(12, tabPanel(title = "tab1",
DT::dataTableOutput("table1"))))
)
server <- function(input, output, session) {
irisdata <- reactive({
irisdata <- iris
})
irisdata <- eventReactive(input$run, {
rbind(irisdata(), iris, fill = TRUE)
})
output$table1 <- DT::renderDataTable({
irisdata()
})
}
shinyApp(ui, server)
The rbind results in: Error in : evaluation nested too deeply: infinite recursion / options(expressions=)?
Which is to be expected I suppose as it's self-referencing, but I can't figure out how to write the code otherwise?
Working code of the above example, based on the linked threads in the comments:
library(shiny)
library(data.table)
iris <- as.data.table(iris)
ui <- fluidPage(
fluidRow(column(4, actionButton("run", "Run"))),
fluidRow(column(12, tabPanel(title = "tab1",
DT::dataTableOutput("table1"))))
)
server <- function(input, output, session) {
irisdata <- reactiveValues(data = iris)
observeEvent(input$run, {
irisdata$data <- rbind(irisdata$data, iris, fill = TRUE)
})
output$table1 <- DT::renderDataTable({
irisdata$data
})
}
shinyApp(ui, server)

keep selected rows when changing dataset in shiny DT datatable

I am using the DT package to display a data table in my shiny app. Since I provide different data sets, I have radio buttons to select them and the data table updates automatically.
What I would like to do is to preselect the available rows from df1 in df2 when switching the datasets. At the moment, my selection always get erased. When I try to save the selected rows (uncomment the two rows), my table get reset directly.
library(shiny)
library(DT)
df1 <- data.frame(names=letters,
values=1:26)
df2 <- data.frame(names=letters,
values=(1:26)*2)[seq(1,26,2),]
ui <- shinyUI(
fluidPage(
sidebarLayout(
sidebarPanel(
radioButtons("dataset", label=h5("Select dataset"),
choices=list("df1"='df1',
"df2"='df2'),
selected='df1', inline=TRUE)
),
mainPanel(
DT::dataTableOutput("name_table")
)
)
)
)
Server side...
server <- function(input, output, session) {
getDataset <- reactive({
result <- list()
result[['dataset']] <- switch(input$dataset,
'df1'=df1,
'df2'=df2)
# result[['selection']] <-
# as.numeric(input$name_table_rows_selected)
return(result)
})
output$name_table <- DT::renderDataTable({
DT::datatable(getDataset()[['dataset']],
options=list(pageLength=5))
})
name_proxy = DT::dataTableProxy('name_table')
}
shinyApp(ui, server)
I used the DT table, since I need the proxy and some interaction with the data table.
You can save selected rows only when going to change df like
server <- function(input, output, session) {
dd=reactiveValues(select=NULL)
observeEvent(input$dataset,{
dd$select=as.numeric(isolate(input$name_table_rows_selected))
})
getDataset <- reactive({
result <- list()
result[['dataset']] <- switch(input$dataset,
'df1'=df1,
'df2'=df2)
return(result)
})
output$name_table <- DT::renderDataTable({
DT::datatable(getDataset()[['dataset']],
options=list(pageLength=5),
selection = list(mode = 'multiple', selected =dd$select )
)
})
name_proxy = DT::dataTableProxy('name_table')
}
shinyApp(ui, server)
Or a bit modification of #drmariod variant: use eventReactive instead of reactive
server <- function(input, output, session) {
getDataset <- eventReactive(input$dataset,{
result <- list()
result[['dataset']] <- switch(input$dataset,
'df1'=df1,
'df2'=df2)
result[['selection']] <- testing()
return(result)
})
testing <- function() {
list(selected=as.numeric(input$name_table_rows_selected))
}
output$name_table <- DT::renderDataTable({
DT::datatable(getDataset()[['dataset']],
options=list(pageLength=5),
selection=getDataset()[['selection']])
})
name_proxy = DT::dataTableProxy('name_table')
}
Hm, it looks like I found a solution, but I wonder if there is a better solution.
server <- function(input, output, session) {
getDataset <- reactive({
result <- list()
result[['dataset']] <- switch(input$dataset,
'df1'=df1,
'df2'=df2)
result[['selection']] <- testing()
return(result)
})
testing <- function() {
list(selected=as.numeric(input$name_table_rows_selected))
}
output$name_table <- DT::renderDataTable({
DT::datatable(getDataset()[['dataset']],
options=list(pageLength=5),
selection=getDataset()[['selection']])
})
name_proxy = DT::dataTableProxy('name_table')
}
I wonder, sometimes comes a processing message. and on each click the table shortly "blinks"... Would be great to get a better answer.

Resources