I am making a shiny app that interacts with a big data.frame that I have stored as an RData file. I want the user to select the file, and once the RData is completely loaded (takes ~15 seconds) a second panel should show up allowing the user to input some sample name and do some operations.
Here is how my app looks now
header <- dashboardHeader(title="Analysis and database")
sidebar <- dashboardSidebar(
useShinyjs(),
sidebarUserPanel(),
hr(),
sidebarMenu(
# Setting id makes input$tabs give the tabName of currently-selected tab
id = "sidebarmenu",
menuItem("Analyse old data by Sample", tabName="oldfile", icon = icon("table"), startExpanded = FALSE),
fileInput(inputId = "file1", "Choose database file"),
conditionalPanel(
#condition = "input.sidebarmenu === 'oldfile'",
condition = "output.fileUploaded == 'true' ",
textInput(inputId = "sample", label ="Type a sample ID"),
actionButton("go2", "Filter")
)
)
)
body <- dashboardBody(
tags$style(type="text/css",
".shiny-output-error { visibility: hidden; }",
".shiny-output-error:before { visibility: hidden; }"),
tabItems(
tabItem("oldfile", "Sample name data.table",
fluidRow(DT::dataTableOutput('tabla_oldfile') %>% withSpinner(color="#0dc5c1")))
)
)
ui <- dashboardPage(header, sidebar, body)
### SERVER SIDE
server = function(input, output, session) {
options(shiny.maxRequestSize=100000*1024^2)
prop <- reactive({
if (input$go2 <= 0){
return(NULL)
}
result <- isolate({
if (is.null(input$file1))
return(NULL)
if (is.null(input$sample))
return(NULL)
inFile <- input$file1
print(inFile$datapath)
#big_df <- load(inFile$datapath)
print (big_df)
print(input$sample)
oldtable <- big_df1 %>% filter_at(vars(GATK_Illumina.samples:TVC_Ion.samples),
any_vars(stringi::stri_detect_fixed(., as.character(input$sample))))
oldtable
})
result
})
output$fileUploaded <- reactive({
return(!is.null(prop()))
})
outputOptions(output, 'fileUploaded', suspendWhenHidden=FALSE)
output$tabla_oldfile <- DT::renderDataTable({
DT::datatable(prop(),
filter = 'top',
extensions = 'Buttons',
options = list(
dom = 'Blftip',
buttons =
list('colvis', list(
extend = 'collection',
buttons = list(list(extend='csv',
filename = 'results'),
list(extend='excel',
filename = 'results'),
list(extend='pdf',
filename= 'results')),
text = 'Download'
)),
scrollX = TRUE,
pageLength = 5,
lengthMenu = list(c(5, 15, -1), list('5', '15', 'All'))
), rownames = FALSE
)
})
}
shinyApp(ui, server)
I have used the solution provide in Make conditionalPanel depend on files uploaded with fileInput but I can't make it work, there is another implementation using shinyjs package but don't know how to use it on my example
Related
I am very new to Shiny and am not sure if I am doing this remotely correct/completely oversimplified. I am trying to pull the column headers from an excel fileInput into a selectInput drop down box.
So essentially I would like the options for the select box be determined by the headers of the file input. Then it would link into my equation in the server, which would perform the calculation based on the dataset in the column (the bit in the server with input$col).
I appreciate any comments/answers,
Thanks
EDIT: at a guess, would I need to use uiOutput and renderUI??
ui
ui <- fluidPage(theme = shinytheme(),
setBackgroundColor("white"),
titlePanel(img(src = "image.png", height = 125, width = 450)),
(h1("review app", style = "color:#337ab7")),
p("Calculate"),
headerPanel(h3("Input data here", style = "color:#337ab7")),
sidebarLayout(
sidebarPanel( position =c("left"), style = "color:#337ab7",
numericInput("SL",
"SL", 1, min=1, max=10),
numericInput("LT", "LT",0, min=0, max = 52),
fileInput("file1", 'choose file',
accept = c(".xlsx") ),
selectInput("col", "Column", choices = unique(colnames(input$file1)
)),
checkboxInput("smooth", "Clean my data", value = FALSE, width = NULL),
actionButton("action_Calc", label = "Refresh & Calculate", icon("redo"),
style="color: #fff; background-color: #337ab7; border-color: #2e6da4"),
),
mainPanel(
tabsetPanel(
tabPanel("SS", h1(textOutput("SS"), style = "color:#337ab7")),
tabPanel("guide", img(src = "guide.png", height = 200, width = 600)),
tabPanel("Mydata", div(tableOutput('contents'), style="font-size:55%"))
))))
server
server <- function(input, output) {
Data <- reactive({
req(input$file1)
inFile <- input$file1
read_excel(inFile$datapath, 1)
})
output$contents <- renderTable(bordered = TRUE, style= "border-color:#337ab7", hover = TRUE, {
Data()
})
values<- reactiveValues()
observe({
input$action_Calc
values$int<- isolate({ if (input$smooth) (round( input$SL*sqrt(input$LT/4)*sd( tsclean(Data()[[input$col]],
replace.missing = TRUE, lambda = NULL)) , digits= 2))
else (round( input$SL*sqrt(input$LT/4)*sd(Data()[[input$col]]), digits = 2)) })})
output$SS <- renderText({paste("Calculated is", values$int)} )
}
shinyApp(ui, server)
updatedSelectInput should do it for you. Below is a minimal example.
To reduce package dependencies I switched to loading .csv rather than .xlsx. Note that the loaded file isn't validated, so if junk goes in you'll get junk out.
library(shiny)
#UI
ui <- fluidPage(
selectInput('mydropdown', label = 'Select', choices = 'No choices here yet'),
fileInput('myfileinput', label = 'Select File', accept = c(".csv"))
)
#Server
server <- function(input, output, session) {
observeEvent(input$myfileinput, {
mytable <- read.csv(input$myfileinput$datapath)
updateSelectInput(session, "mydropdown", label = "Select", choices = colnames(mytable))
})
}
shinyApp(ui = ui, server = server)
I have the following code:
library(shiny)
library(shinydashboard)
library(rhandsontable)
header <- dashboardHeader(title = "Sample", titleWidth = 375)
sidebar <- dashboardSidebar(width = 270,
sidebarMenu(id="mymenu",
menuItem(text = "Home", tabName = "tabCars", icon = icon("home", class="home"))
))
body <- dashboardBody (
tabItems(
tabItem(tabName = "tabCars",
fluidRow(
column(width = 2,
selectInput(
inputId = "selected_CarCylinders",
label = "Car Cylinders",
choices = mtcars$cyl,
selectize = TRUE,
width = "250px",
multiple = FALSE
)),
column(width = 2, style = "margin-top: 25px",
actionButton("deleteBtn", "Delete Selected Cylinders")),
column(width = 1, style = "margin-top: 25px",
actionButton("refreshBtn", "Refresh Filter/Chart")),
rHandsontableOutput("carDT")
)
)
)
)
ui <- dashboardPage(header, sidebar, body)
server <- function(input, output, session) {
output$carDT <- renderRHandsontable({
df <- mtcars
rhandsontable(df, stretchH = "all")
})
observeEvent(input$deleteBtn, {
# need help here
})
observeEvent(input$refreshBtn, {
# need help here
})
}
shinyApp(ui, server)
I need help writing what would go into the input$deleteBtn and input$refreshBtn sections of the server side. If you run the code as is, the idea is to select the number of cylinders from mtcars, then click the Delete button to remove all those entries from the table and filter; however, the filter and table would only update after clicking the refresh button.
While permanently delete screams a SQLite database to me, you could achieve this by using a reactiveVal to store the dataframe and call req to only refresh the table when you click the refreshBtn (in this case, you also have to click it to display the table at the start of the app).
server <- function(input, output, session) {
# Create a `reactiveVal` and set a value to it
df <- reactiveVal()
df(mtcars)
output$carDT <- renderRHandsontable({
req(input$refreshBtn)
rhandsontable(df(), stretchH = "all")
})
observeEvent(input$deleteBtn, {
data <- dplyr::filter(df(), cyl != input$selected_CarCylinders)
# Update `selectInput` to filter out the choices too (for good measure)
updateSelectInput(session, "selected_CarCylinders", choices = data$cyl)
# Update the `reactiveVal` value
df(data)
})
}
I have looked everywhere and cant seem to find help with what must be a common issue.
I have a datatable in a shiny app. I load data into it when it first appears. It consists of one column of text
I want the user be able to press a button that takes the data in the datatable and performs an action on it and then presents a datatable with the result of that function. The function (not shown) basically splits the single column up into several columns.
I cant seem to figure out how to run a function from a button that refreshes and shows the new datatable.
This is what I have so far:
server.R
library(shiny)
library(EndoMineR)
RV <- reactiveValues(data = PathDataFrameFinalColon)
server <- function(input, output) {
output$mytable = DT::renderDT({
RV$data
})
output2$mytable = DT::renderDT({
RV$data<-myCustomFunction(RV$data)
})
}
ui.R
library(shiny)
basicPage(
fluidPage(
DT::dataTableOutput("mytable")
))
basically how do I allow a button on the page to run a specific function that then updates the datatable?
You can use observeEvent() and ignoreInit = TRUE so that the initial dataframe is rendered without the function being applied.
server <- function(input, output) {
RV <- reactiveValues(data = PathDataFrameFinalColon)
output$mytable = DT::renderDT({
RV$data
})
observeEvent(input$my_button,{
RV$data<-myCustomFunction(RV$data)
},ignoreInit = TRUE)
}
ui <- basicPage(
fluidPage(
DT::dataTableOutput("mytable"),
actionButton("my_button",label = "Run Function")
))
I hope this helps you. Have fun;
library(shiny)
library(shinydashboard)
dat = data.frame(id = c("d","a","c","b"), a = c(1,2,3,4), b = c(6,7,8,9))
header <- dashboardHeader(
)
sidebar <- dashboardSidebar(
tags$head(tags$style(HTML('.content-wrapper { height: 1500px !important;}'))),
sidebarMenu (
menuItem("A", tabName = "d1"),
menuItem("B", tabName = "d2"),
menuItem("C", tabName = "d3")
)
)
body <- dashboardBody(
tabItems(
tabItem(tabName = "d1",
box(title = "AAA",
actionButton("refreshTab1_id", "Refresh Tab 1"),
actionButton("sortTable1_id", "Sort Table 1"),
DT::dataTableOutput("table_for_tab_1", width = "100%"))
),
tabItem(tabName = "d2",
box(title = "BBB",
actionButton("refreshTab2_id", "Refresh Tab 2"),
actionButton("sortTable2_id", "Sort Table 2"),
DT::dataTableOutput("table_for_tab_2", width = "100%"))
),
tabItem(tabName = "d3",
box(title = "CCC",
actionButton("refreshTab3_id", "Refresh Tab 3"),
actionButton("sortTable3_id", "Sort Table 3"),
DT::dataTableOutput("table_for_tab_3", width = "100%"))
)
)
)
# UI
ui <- dashboardPage(header, sidebar, body)
# Server
server <- function(input, output, session) {
observe({
if (input$sortTable1_id || input$sortTable2_id || input$sortTable3_id) {
dat_1 = dat %>% dplyr::arrange(id)
} else {
dat_1 = dat
}
output$table_for_tab_1 <- output$table_for_tab_2 <- output$table_for_tab_3 <- DT::renderDataTable({
DT::datatable(dat_1,
filter = 'bottom',
selection = "single",
colnames = c("Id", "A", "B"),
options = list(pageLength = 10,
autoWidth = TRUE#,
# columnDefs = list(list(targets = 9,
# visible = FALSE))
)
)
})
})
observe({
if (input$refreshTab1_id || input$refreshTab2_id || input$refreshTab3_id) {
session$reload()
}
})
}
# Shiny dashboard
shiny::shinyApp(ui, server)
I have a shiny app where I load a file and a tabla is rendered, I want to hid a button in the body until the table is rendered. This button is going to save the filters in a file. I am using shinySaveButton from shinyFiles because I want the user to navigate until a folder and choose a custom filename
Here is the UI
header <- dashboardHeader()
sidebar <- dashboardSidebar(
sidebarUserPanel("Test"),
sidebarMenu(
id = "tabs",
menuItem("Archivo variantes", tabName = "fileupload", icon = icon("table")),
conditionalPanel("input.tabs == 'fileupload' ",
shinyFilesButton("file", "Choose a file" , multiple = FALSE,
title = "Please select a file:",
buttonType = "default", class = NULL)#,
)
)
)
body <- dashboardBody(
tags$style(type="text/css",
".shiny-output-error { visibility: hidden; }",
".shiny-output-error:before { visibility: hidden; }"),
shinyjs::useShinyjs(),
tabItems(
tabItem(tabName = "fileupload",
fluidRow(column(12,
div(DT::dataTableOutput('tabla') %>% withSpinner(color="#0dc5c1"), style = 'overflow-x: auto'))),
fluidRow(column(2, offset = 0,
shinySaveButton('save', 'Save filters', 'Save as...') )))
)
)
ui <- dashboardPage(header, sidebar, body)
And here is the server
## Server side
server = function(input, output, session) {
options(shiny.maxRequestSize=100*1024^2)
if (!exists("default_search_columns")) default_search_columns <- NULL
volumes = getVolumes()
volumes <- c(Home = fs::path_home(), "R Installation" = R.home(), getVolumes()())
file_selected <- reactive({
shinyFileChoose(input, "file", roots = volumes, session = session)
if (is.null(input$file))
return(NULL)
print(parseFilePaths(volumes, input$file)$datapath)
return(parseFilePaths(volumes, input$file)$datapath)
})
contents <- reactive({
if (is.null(file_selected()))
return()
print(file_selected())
df <- read.delim(file_selected(), header = TRUE, stringsAsFactors=FALSE, as.is=TRUE)
return(tidyr::separate_rows(df, Gene.refGene, sep = ";"))
})
# Reactive function creating the DT output object
output$tabla <- DT::renderDataTable({
if(is.null(contents()))
return()
datos <- contents()
DT::datatable(datos,
rownames = FALSE,
style = 'bootstrap',
class = 'compact cell-border stripe hover',
filter = list(position = 'top', clear = FALSE),
escape = FALSE,
extensions = c('Buttons', "FixedHeader", "Scroller"),
options = list(
stateSave = FALSE,
autoWidth = TRUE,
search = list(regex = TRUE, caseInsensitive = TRUE),
initComplete = JS(
"function(settings, json) {",
"$(this.api().table().header()).css({'font-size': '12px'});",
"}"),
scroller = TRUE,
scrollX = TRUE,
scrollY = "600px",
deferRender=TRUE,
buttons = list('colvis', list(
extend = 'collection',
buttons = list(list(extend='csv',
filename = 'results'),
list(extend='excel',
filename = 'results')),
text = 'Download'
)),
FixedHeader = TRUE
),
callback = JS('table.page(3).draw(false); "setTimeout(function() { table.draw(true); }, 300);"')) %>% formatStyle(columns = colnames(.$x$data), `font-size` = "12px")
})
filtros <- eventReactive(input$tabla_search_columns, {
str(input$tabla_search_columns)
return(input$tabla_search_columns)
})
observeEvent(input$save,
{
observe(
if(is.null(input$tabla)) {
shinyjs::disable("save")
} else { shinyjs::enable("save") }
)
})
observe({
volumes <- getVolumes()
volumes <- c(Home = fs::path_home(), "R Installation" = R.home(), getVolumes()())
shinyFileSave(input, "save", roots=volumes, session=session)
fileinfo <- parseSavePath(volumes, input$save)
if (nrow(fileinfo) > 0) {
write.table(filtros(), fileinfo$datapath, row.names = FALSE, col.names=FALSE, quote=TRUE, sep="\t")
}
})
}
shinyApp(ui, server)
I am trying to use shinyjs::disable and shinyjs::enable but I can't make it work, the button save filters is shown before selecting a file. And I want to be hidden until the table is rendered
Any help would be appreciated
Shiny triggers the JavaScript event shiny:value when an output is rendered. So you can disable the button at the initialization of the app, and with the help of this JS event you can enable the button whenever the table is rendered. Here is a minimal example:
library(shiny)
library(shinyFiles)
js <- paste(
"$(document).ready(function(){",
" $('#save').prop('disabled', true);", # disable the 'save' button
"});",
"$(document).on('shiny:value', function(e){",
" if(e.name === 'table'){", # if 'table' is rendered
" $('#save').prop('disabled', false);", # then enable the 'save' button
" }",
"});"
, sep = "\n"
)
ui <- fluidPage(
tags$head(tags$script(HTML(js))),
shinySaveButton("save", "Save", "Save file"),
actionButton("go", "Render table"),
tableOutput("table")
)
server <- function(input, output){
output[["table"]] <- renderTable({
req(input[["go"]]>0)
iris[1:4, ]
})
}
shinyApp(ui, server)
I want to implement a function in a Shiny app. My own function get_calculate() has the arguments data and tolerance as input and retruns a list with a data.frame and a plot.
I want to show the output depending on tolerance. In my server function I use reactive() to run get_calculate() but it doesn't work.
If I write in renderPlot() and renderDataTable() get_calculate() works.
For large datasets, however, it's inefficient because Shiny will have to run get_calculate() twice.
library(shiny)
library(shinydashboard)
library(foreign)
#load my own function
source("01-get_calculate.R")
ui <- dashboardPage(
dashboardHeader(title = "Analysis"),
dashboardSidebar(
sidebarMenu(
menuItem("Load data", tabName = "data", icon = icon("database")),
menuItem("Mainboard", tabName = "Mainboard", icon = icon("dashboard"))
)
),
dashboardBody(
tabItems(
tabItem(tabName = "data",
fileInput("datafile", "Choose file",
accept = c("text/csv/rds/dbf", 'text/comma-separated-values,text/plain')),
dataTableOutput("mytable")
),
tabItem(tabName = "Mainboard",
fluidRow(
box(
title = "Input", status = "primary", solidHeader = TRUE, collapsible = TRUE,
sliderInput(inputId = "tol",
label = "Tolerance",
value = 4, min = 1, max = 15, step = 1)
)),
fluidRow(
box(
title = "Adherence Curve", status = "warning", solidHeader = TRUE, collapsible = TRUE,
plotOutput("plot_kpm")
),
box(
title = "Overview Table", status = "primary", solidHeader = TRUE, collapsible = TRUE,
tableOutput("table_kpm")
)
)
)
)
)
)
server <- function(input, output) {
filedata <- reactive({
infile <- input$datafile
if (is.null(infile)) {
return(NULL)
}
read.dbf(infile$datapath)
})
output$mytable <- renderDataTable({
filedata()
})
**test <- reactive({
get_calculate(filedata(), tolerance = input$tol)
})
output$plot_kpm <- renderPlot({
test$kpm_chart
})
output$table_kpm <- renderDataTable({
test$data_kpm[, c("Time", "numbers", "Percent")]
})**
}
shinyApp(ui = ui, server = server)
The error you mentioned is most likely from renderDataTable where you are trying to pick couple of columns from test$data_kpm. Check the dataframe for exact column names.
This version of my shiny app runs. But it' ineffcient because shiny have to runs get_calculate twice.
server <- function(input, output) {
#This function is repsonsible for loading in the selected file
filedata <- reactive({
infile <- input$datafile
if (is.null(infile)) {
# User has not uploaded a file yet
return(NULL)
}
read.dbf(infile$datapath)
})
output$mytable <- renderDataTable({
filedata()
})
output$plot_kpm <- renderPlot({
get_calculate(filedata(), tolerance = input$tol)$kpm_chart
})
output$table_kpm <- renderTable({
get_calculate(filedata(), tolerance = input$tol)$data_kpm[, c("Time", "Percent", "Patients")]
})
output$download_mainboard_adherence_table <- downloadHandler(
filename = paste("adherence_table", '.csv', sep=''),
content = function(file) {
write.csv(get_calculate(filedata(), tolerance = input$tol)$data_kpm[, c("Time", "Percent", "Patients")], file)
}
)
}
Why don't you use a reactive expression to run your get_calculate just once ? And then use the result in your output$plot_kpm and output$table_kpm ?
This will optimize your code.