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)
Related
I am not able to delete the generated map after I press the reset button on shiny, could you help me to insert the code to delete the map made after pressing the button? For both selectInput works normally, only the map that is not deleted from the screen.
library(shiny)
library(shinythemes)
library(lubridate)
library(googleway)
set_key("API KEY")
df1<- structure(
list(
Marketname = c("Market1","Market1", "Market2","Market2", "Market3", "Market3", "Market4", "Market4"),
Latitude = c(-22.900200453490385, -22.900200453490385,-22.89279876292728,-22.89279876292728,-22.89107669207457,-22.89107669207457,-22.91668421655409,-22.91668421655409),
Longitude = c(-48.448779371935494,-48.448779371935494, -48.45043377250408,-48.45043377250408,-48.44108027972275,-48.44108027972275,-48.43786997555729,-48.43786997555729)),
row.names = c(NA, 8L), class = "data.frame")
ui <- fluidPage(
shiny::navbarPage(theme = shinytheme("flatly"), collapsible = TRUE,
br(),
tabPanel("Rota",
sidebarLayout(
sidebarPanel(
selectizeInput("market1", label = h5("Choose starting point:"), choices = NULL,
multiple = TRUE,
options = list(maxItems = 1)),
selectizeInput("market2", label = h5("Choose destination point:"), choices = NULL,
multiple = TRUE,
options = list(maxItems = 1)),
actionButton(inputId = "getRoute", label = "Get route"),
actionButton(inputId = "reset", label = "Reset")),
mainPanel(
tabsetPanel(
tabPanel("Route",google_mapOutput(outputId = "mapWarsaw"),
)
))
))))
server <- function(input, output,session) {
observe({
updateSelectizeInput(session, "market1",
choices = unique(df1$Marketname)
)
})
observe({
excludeOption <- NULL
if (!is.null(input$market1)) {
excludeOption <- input$market1
}
updateSelectizeInput(session, "market2",
choices = unique(df1$Marketname[df1$Marketname != excludeOption])
)
})
observeEvent(input$getRoute, {
origin <- df1[df1$Marketname == input$market1, c("Latitude", "Longitude")][1, ]
destination <- df1[df1$Marketname == input$market2, c("Latitude", "Longitude")][1, ]
route <- google_directions(origin = origin,
destination = destination,
mode = "driving")
df_routes <- data.frame(polyline = direction_polyline(route))
df_way <- cbind(
route$routes$legs[[1]]$end_location,
data.frame(address = route$routes$legs[[1]]$end_address)
)
m3<-google_map() %>%
add_polylines(data = df_routes, polyline = "polyline", stroke_weight = 4)
output$mapWarsaw <- renderGoogle_map({
m3
})
})
observeEvent(input$reset, {
updateSelectInput(session, "market1", selected = "")
updateSelectInput(session, "market2", selected = "")
})
}
shinyApp(ui = ui, server = server)
Here I pressed reset, the selectInput was cleared, but the map was not, so I would like to insert some code that cleared the screen. Of course, after inserting the selectInput options again, the map was generated normally on the screen.
I recommend using a reactiveVal to store whether you want to plot or not, then req(.) that value in your plot.
A simple example:
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
numericInput("n", "N", value = 2),
actionButton("toggle", "Toggle")
),
mainPanel(
plotOutput("plot")
)
)
)
server <- function(input, output, session) {
doplot <- reactiveVal(TRUE)
observeEvent(input$toggle, {
doplot(!isTRUE(doplot()))
})
output$plot <- renderPlot({
req(doplot())
plot(runif(input$n))
})
}
shinyApp(ui, server)
doplot defaults to TRUE, so it starts plotting immediately (assuming input$n has a value), and every time input$n is changed, a new plot is rendered;
when you click on toggle, the doplot is inverted, and the dependent output$plot will "fail" the req(doplot()) requirement and clear the plot;
this could be improved to give a clearer indication that the empty plot is because the user toggled the button ... in this case, I should likely change the style of the button to clearly indicate the state, but that's aesthetics and may or may not apply to your app
Another similar method would be to store the data in a reactiveVal, and require it, perhaps like this:
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
numericInput("n", "N", value = 2),
actionButton("toggle", "Toggle")
),
mainPanel(
plotOutput("plot")
)
)
)
server <- function(input, output, session) {
mydat <- reactiveVal(NULL)
observeEvent(input$toggle, {
req(input$n)
if (is.null(mydat())) {
mydat(runif(input$n))
} else mydat(NULL)
})
output$plot <- renderPlot({
plot(req(mydat()))
})
}
shinyApp(ui, server)
This second method won't work as well if you need to preserve the data.
I have the following app which allows for text to be entered and it is then saved as VALUE and printed on a panel.
Although it looks like I can only do this with one text input at a time - even if I click add (so I don't believe this button is working). On top of that I would like for the user to be able to add multiple inputs (like I have below).
And then my VALUE function should be list with multiple inputs.
code below
library(shiny)
ui <- fluidPage(
headerPanel("R Package App"),
sidebarPanel(
# selectInput("options", "options", choices=c('abc','def')),
textInput("textbox", "Enter R Package Name", ""),
actionButton("add","Add")
),
mainPanel(
textOutput("caption")
)
)
server <- function(input, output, session) {
observe({
VALUE <- ''
if(input$add>0) {
isolate({
VALUE <- input$textbox
})
}
updateTextInput(session, inputId = "textbox", value = VALUE)
})
output$caption <- renderText({
input$textbox
})
}
shinyApp(ui = ui, server = server)
Have you considered using selectizeInput with it's create option?
library(shiny)
packagesDF <- as.data.frame(installed.packages())
ui <- fluidPage(
headerPanel("R Package App"),
sidebarPanel(
selectizeInput(
inputId = "selectedPackages",
label = "Enter R Package Name",
choices = packagesDF$Package,
selected = NULL,
multiple = TRUE,
width = "100%",
options = list(
'plugins' = list('remove_button'),
'create' = TRUE,
'persist' = TRUE
)
)
),
mainPanel(textOutput("caption"))
)
server <- function(input, output, session) {
output$caption <- renderText({
paste0(input$selectedPackages, collapse = ", ")
})
}
shinyApp(ui = ui, server = server)
I am trying to make an xlsx sheet of customers orders of certain items. I created a shiny app to input each order in the form of a datatable row which is added to the table on click of "Add" Button. But I face a problem, each time I add a new order (row) an extra cell of row number is generated in all the previous ones like in the picture.
and all row cells are shifted to the right!!
This is my code:
library(shiny)
library(shinythemes)
library(readxl)
library(xlsx)
library(DT)
items <- read_excel("items.xlsx",col_names = F)
colnames(items) <- c("Items", "Euro", "Cost")
ui <- fluidPage(theme = shinytheme('journal'),
sidebarLayout(
sidebarPanel(
tags$img(height = 118, width = 160, src="logo.jpg"),
br(),br(),
textInput('name','Name'),
br(),
selectizeInput(inputId = "item",
label = "Item",
choices = c(items$Items),
options = list(
placeholder = '',
onInitialize = I('function() { this.setValue(""); }'))),
br(),
numericInput('number','Quantity',value = 1,step = 1),
br(),
numericInput('price','Price/pc',value = ''),
br(),
actionButton(inputId = "button", label = "Add", icon = icon("plus"),
style="color: #fff; background-color: #337ab7; border-color: #2e6da4"),
width = 3),
mainPanel(DTOutput('out')))
)
server <- function(input, output,session) {
observeEvent(input$button,{
order <- data.frame(read_excel("Order.xlsx"))
price <- items[items$Items == input$item,][c(2,3)]
order[nrow(order) + 1,] <- c(ifelse(input$name %in% order$Name,'',input$name),input$item,input$number,
price,price[2]* input$number,input$price*input$number,
(input$price*input$number) - (price[2]* input$number))
write.xlsx(order,'order.xlsx')
output$out<- renderDT({datatable(order)})
})
}
shinyApp(ui = ui, server = server)
items.xlsx
Items Euro Cost
some item 2.5 10
some item2 5 20
some item3 4 18
order.xlsx
Name Item Quantity Euro Cost Total cost Total price Gain
can somebody know what is the cause for that and how to solve?
Thanks all
I couldn't recreate your exact app because I had trouble getting xlsx package to load on my system. I recreated a similar working example by saving the two excel files as CSV files and using readr read_csv and write_csv in place of your read_excel and write.xlsx. This version appears to work as you want it to but with csv output instead of excel. Having a read of the xlsx documentation I might have a guess that row names are being written out each time you write.xlsx and this is showing up when you read them back in. Could it be that you need to pass row.names = FALSE to your write.xlsx call?
https://cran.r-project.org/web/packages/xlsx/xlsx.pdf
library(shiny)
library(shinythemes)
library(DT)
library(readr)
items <- readr::read_csv("items.csv",col_names = T)
ui <- fluidPage(theme = shinytheme('journal'),
sidebarLayout(
sidebarPanel(
tags$img(height = 118, width = 160, src="logo.jpg"),
br(),br(),
textInput('name','Name'),
br(),
selectizeInput(inputId = "item",
label = "Item",
choices = c(items$Items),
options = list(
placeholder = '',
onInitialize = I('function() { this.setValue(""); }'))),
br(),
numericInput('number','Quantity',value = 1,step = 1),
br(),
numericInput('price','Price/pc',value = ''),
br(),
actionButton(inputId = "button", label = "Add", icon = icon("plus"),
style="color: #fff; background-color: #337ab7; border-color: #2e6da4"),
width = 3),
mainPanel(DTOutput('out')))
)
server <- function(input, output,session) {
observeEvent(input$button,{
order <- data.frame(read_csv("order.csv"))
price <- items[items$Items == input$item,][c(2,3)]
order[nrow(order) + 1,] <- c(ifelse(input$name %in% order$Name,'',input$name),input$item,input$number,
price,price[2]* input$number,input$price*input$number,
(input$price*input$number) - (price[2]* input$number))
write_csv(order,'order.csv')
output$out<- renderDT({datatable(order)})
})
}
shinyApp(ui = ui, server = server)
Try to perform data reading and data wrangling outside of the observer as shown below.
items <- read.table(text='"Items","Euro","Cost"
some item, 2.5, 10
some item2, 5,20
some item3, 4,18', header=TRUE, sep=",")
ui <- fluidPage(theme = shinytheme('journal'),
sidebarLayout(
sidebarPanel(
tags$img(height = 118, width = 160, src="logo.jpg"),
br(),br(),
textInput('name','Name'),
br(),
selectizeInput(inputId = "item",
label = "Item",
choices = c(items$Items),
options = list(
placeholder = '',
onInitialize = I('function() { this.setValue(""); }'))),
br(),
numericInput('number','Quantity',value = 1,step = 1),
br(),
numericInput('price','Price/pc',value = ''),
br(),
actionButton(inputId = "button", label = "Add", icon = icon("plus"),
style="color: #fff; background-color: #337ab7; border-color: #2e6da4"),
width = 3),
mainPanel(DTOutput('out')))
)
server <- function(input, output,session) {
order <- eventReactive(input$button,{
req(input$number,input$price,input$name)
order <- data.frame(read_excel("order.xlsx"))
price <- items[items$Items == input$item,][c(2,3)]
order[nrow(order) + 1,] <- c(ifelse(input$name %in% order$Name,'',input$name),input$item,input$number,
price,price[2]* input$number,input$price*input$number,
(input$price*input$number) - (price[2]* input$number))
order
})
observeEvent(input$button,{ write.xlsx(order(),'order.xlsx') })
output$out<- renderDT({datatable(order())})
}
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 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