Related
I have the following code that basically uploads the data and once you have clicked on the row of the dataset you have uploaded, it reads the file. If you go to the second page in the navbar called regression you can choose variables from the dataset and run linear model. That works with the summary table. I want to achieve is something like here: https://towardsdatascience.com/build-an-interactive-machine-learning-model-with-shiny-and-flexdashboard-6d76f59a37f9
I want the prediction table and plot visualisation based on what has been selected. Appreciate your understanding and helpfulness.
library(shiny)
library(magrittr)
library(shiny)
library(readxl)
library(tidyverse)
library(DT)
library(reactable)
ui <- navbarPage("Demo",
tabPanel("Data Manipulation",
sidebarLayout(
sidebarPanel(
fileInput("upload", "Upload your file", multiple = TRUE, accept = c(".csv", ".xlsx") ),
selectInput('mydropdown', label = 'Select', choices = 'No choices here yet'),
h2("Modify variable type"),
selectInput("var_name", "Select variable", choices = c()),
radioButtons("action", NULL,
choiceNames = c("Make factor", "Make numeric"),
choiceValues = c("factor", "numeric")),
actionButton("modify", "Do it!"),
verbatimTextOutput("str")
),
mainPanel(
DT::DTOutput("files"),
reactable::reactableOutput("uploaded_files")
)
)
),
tabPanel("Regression",
sidebarLayout(
sidebarPanel(
selectInput("dep_var", "Select dependent variable", choices = c()),
selectInput("ind_var", "Select independent variables", choices = c(), multiple = TRUE),
actionButton("submit_reg", "Do it!")),
mainPanel(
verbatimTextOutput(outputId = "regsum")
)
)
),
)
server <- function(input, output, session) {
output$files <- DT::renderDT({
DT::datatable(input$upload, selection = c("single"))
})
selected_file <- reactiveVal()
observe({
## when developing, use a sample file you have on your computer so that you
## can load it immediately instead of going through button clicks
# demofile <- "/path/to/your/file.csv"
# selected_file( read.csv(demofile) )
# return()
req(input$upload, input$files_rows_selected)
idx <- input$files_rows_selected
file_info <- input$upload[idx, ]
if (tools::file_ext(file_info$datapath) == "csv") {
selected_file(read.csv(file_info$datapath))
} else if (tools::file_ext(file_info$datapath) == "xlsx") {
selected_file(readxl::read_xlsx(file_info$datapath))
} else {
stop("Invalid file type")
}
})
output$uploaded_files <- reactable::renderReactable({
req(selected_file())
reactable::reactable(
selected_file(),
searchable = TRUE
)
})
observe({
req(input$upload)
file_names <- input$upload$name
updateSelectInput(
session,
"mydropdown",
choices = file_names
)
})
observe({
req(selected_file())
updateSelectInput(session, "var_name", choices = names(selected_file()))
})
output$str <- renderPrint({
req(selected_file())
str(selected_file())
})
observeEvent(input$modify, {
df <- selected_file()
if (input$action == "factor") {
df[[input$var_name]] <- as.factor(df[[input$var_name]])
} else if (input$action == "numeric") {
df[[input$var_name]] <- as.numeric(df[[input$var_name]])
} else {
stop("Invalid action")
}
selected_file(df)
})
# Second Page
observe({
req(selected_file())
Dependent <- updateSelectInput(session, "dep_var", choices = names(selected_file()))
})
observe({
req(selected_file())
Independent <- updateSelectInput(session, "ind_var", choices = names(selected_file()))
})
observeEvent(input$submit_reg, {
lm1 <- reactive({
req(selected_file())
Model1 <- lm(reformulate(input$ind_var, input$dep_var), data = selected_file())})
options(scipen=999)
output$regsum <- renderPrint({summary(lm1())})
DT::renderDataTable({
df <- req(selected_file())
DT::datatable(df %>% select(input$dep_var, input$ind_var) %>% mutate(predicted = predict(lm1()), residuals = residuals(lm1())) %>% select(input$dep_var, predicted, residuals),
rownames = FALSE, colnames = c('actual value', 'predicted value', 'residuals'), extensions = c('Buttons', 'Responsive'),
options = list(columnDefs = list(list(className = 'dt-center', targets = "_all")), dom = 'Blfrt',
buttons = c('copy', 'csv', 'excel', 'print'), searching = FALSE, lengthMenu = c(20, 100, 1000, nrow(housing)), scrollY = 300, scrollCollapse = TRUE))
})
})
}
shinyApp(ui, server)
Is there a way to automatically upload the excel file.
Right now, the user has to manually upload the excel file(file.xlsx) that is kept under project folder.
Now the expected output is the moment the user clicks on "Automatically Upload the exceil file", the file should get uploaded.
Is there a way to achieve this? Let me know if this makes sense
library(tidyverse)
library(shiny)
library(shinydashboard)
library(DT)
ui <-
dashboardPage(
skin = "green",
dashboardHeader(
title = "Test",
titleWidth = 280
),
dashboardSidebar(
width = 280,
sidebarMenu(
menuItem(text = "File(s) Upload", tabName = "Files", icon = icon("file-upload")),
menuItem(text = "Output", tabName = "Out1", icon = icon("file-upload"))
)
),
dashboardBody(
tabItems(
tabItem(
tabName = "Files",
fluidRow(
column(
width = 4,
inputPanel(
fileInput(inputId = "File1", label = "File", multiple = TRUE, accept = c(".xlsx")),
selectInput(inputId = "Sheet1", label = "Select sheet", choices = NULL, selected = NULL),
actionButton("sub", "Automatically Upload the exceil file")
)
)
)
),
tabItem(
tabName = "Out1",
fluidRow(column(width = 10, strong("Data")), align = "center"),
br(),
fluidRow(dataTableOutput("Data1"))
)
)
)
)
server <- function(input, output){
# Populate the drop down menu with the names of the different Excel Sheets, but
# only after a new file is supplied
observe({
sheet_names <- readxl::excel_sheets(input$File1$datapath)
shiny::updateSelectInput(
inputId = "Sheet1",
choices = sheet_names,
selected = sheet_names[[1]]
)
}) %>%
bindEvent(input$File1)
# When the drop down meny is populated, read the selected sheet from the Excel
# file
thedata <- reactive({
req(input$Sheet1)
readxl::read_xlsx(input$File1$datapath, sheet = input$Sheet1)
})
output$Data1 <-
renderDataTable(
thedata()
, extensions = "Buttons"
, options = list(
dom = "Bfrtip"
, buttons = c("copy", "csv", "excel", "pdf", "print")
)
)
# observe({
# print(reactiveValuesToList(input, all.names = FALSE))
# })
}
runApp(
list(ui = ui, server = server)
, launch.browser = TRUE
)
I was wondering if it is possible to save DT table content together with some additional information which is not part of the data frame/table like app version number, date of execution, sliderInput value etc.
Thank you!
Reprex below:
library(shiny)
library(DT)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
sliderInput(inputId = "range", "Set range", 1, 10, 5, 1)
),
mainPanel(
DT::dataTableOutput("table")
)
)
)
server <- function(input, output) {
dfr <- data.frame(var1 <- c(1,2,3),
var2 <- c(11, 22, 33))
output$table <- DT::renderDataTable(
datatable(dfr, extensions = 'Buttons',
class="cell-border stripe",
rownames = FALSE, colnames = c("var1", "var2"),
options = list(dom = "Blfrtip",
buttond = list("copy", list(extend = "collection",
buttons = c("csv", "excel", "pdf"),
text = "Download")), pageLength=10, autoWidth = TRUE,
searchHighlight = TRUE, filter = "top"))
)
}
shinyApp(ui = ui, server = server)
You could save the contents of the data frame and the other information in a list and then save the list.
Or, any R object can have attributes which are completely arbitrary and under your control. You could set attributes of the data frame to record the information you want.
Personally, I'd use the list approach, purely because I don't like attributes.
Here's a suggestion in response to OP's request below.
library(shiny)
library(DT)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
sliderInput(inputId = "range", "Set range", 1, 10, 5, 1),
actionButton("saveRds", "Save to Rds"),
actionButton("loadRds", "Load from Rds")
),
mainPanel(
DT::dataTableOutput("table"),
wellPanel(h4("Current data"), verbatimTextOutput("text")),
wellPanel(h4("File data"), verbatimTextOutput("loadedData"))
)
)
)
server <- function(input, output) {
dfr <- data.frame(var1 <- c(1,2,3),
var2 <- c(11, 22, 33))
output$table <- DT::renderDataTable(
datatable(dfr, extensions = 'Buttons',
class="cell-border stripe",
rownames = FALSE, colnames = c("var1", "var2"),
options = list(dom = "Blfrtip",
buttond = list("copy", list(extend = "collection",
buttons = c("csv", "excel", "pdf"),
text = "Download")), pageLength=10, autoWidth = TRUE,
searchHighlight = TRUE, filter = "top"))
)
listInfo <- reactive({
list("data"=dfr, "version"="WebApp Version 1.0", "runDate"=date(), "sliderValue"=input$range)
})
output$text <- renderPrint({
listInfo()
})
observeEvent(input$saveRds, {
saveRDS(listInfo(), "data.Rds")
})
fileData <- reactive({
req(input$loadRds)
readRDS("data.Rds")
})
output$loadedData <- renderPrint({
fileData()
})
}
shinyApp(ui = ui, server = server)
The way you implement "save to file" will depend on the file format: Excel files will clearly have different requirements to PDF files, for example. As a minimum effort demonstation, I've created "Save to Rds" and "Load from RDS" buttons in the sidebar and added a verbatimTextOutput to display the contents of the file when it's loaded. [I'm not sufficiently familiar with DT to know how to add the buttons in the table toolbar.]
OP's effort was pretty close: it's just that writing a list to CSV file takes a little more effort than just calling write.csv...
I am wroking on an shiny app as a volonteer trying to produce an app that would register all of the calls citizens have in the these times of a lockdown for a local Red Cross office. I have managed to get the entry form and to review the DT, but I need to the DT editable so I have included some code to do that.
All is working, except when I write the changes in some of the columns the app changes the column -1 (one to left), overwrites its previous entry in column -1 that I didn't wanted to edit and leaves the entry I actually wanted to edit in the column I wanted to edit (if that makes any sense). What am I doing wrong? I am pasting the code, datasets stored on Dropbox.
## app.R ##
# load the required packages
library(shiny)
library(shinyjs)
require(shinydashboard)
library(ggplot2)
library(dplyr)
library(DT)
library(data.table)
# Obavezna polja
fieldsMandatory <- c("Ime", "Prezime", "Problem")
# Označiti obavezna polja s crvenim asteriksom
labelMandatory <- function(label) {
tagList(
label,
span("*", class = "mandatory_star")
)
}
# CSS za obavezna polja, *
appCSS <-
".mandatory_star { color: red; }"
# HumanTime za time stamp u csv
humanTime <- function() format(Sys.time(), "%Y%m%d-%H%M%OS")
# Čuvanje odgovora u folderu "reponses"
fieldsAll <- c("Ime", "Prezime", "Adresa", "BrojTel", "OIB",
"Problem", "Pomagac","Trajanje","Rjesenje")
# DropBox autorizacija
library(rdrop2)
# This will launch your browser and request access to your Dropbox account.
# You will be prompted to log in if you aren't already logged in.
#drop_auth()
# Once completed, close your browser window and return to R to complete authentication.
# The credentials are automatically cached (you can prevent this) for future use.
# If you wish to save the tokens, for local/remote use
#token <- drop_auth()
#saveRDS(token, file = "dropbox_token.rds")
# Then in any drop_* function, pass `dtoken = token
# Tokens are valid until revoked.
outputDir <- "responses"
outputJedan <- "reponsesJedanFajl"
loadData <- function() {
files_info <- drop_dir(outputDir)
file_paths <- files_info$path_display
# Only take the last 20 because each file takes ~1 second to download
file_paths <- tail(file_paths, 1)
zadnji <-
lapply(file_paths, drop_read_csv, stringsAsFactors = FALSE, encoding = 'UTF-8') %>%
do.call(rbind, .)
write.csv(zadnji, "zadnji.csv", row.names = FALSE, quote = TRUE, fileEncoding = "UTF-8")
# Upload the file to Dropbox
drop_upload("zadnji.csv", path = outputDir, mode = "overwrite")
# files_info2 <- drop_dir(outputJedan)
# file_paths2 <- files_info2$path_display
# Only take the last 20 because each file takes ~1 second to download
#file_paths2 <- tail(file_paths, 20)
data <-
lapply(c("responses/zadnji.csv", "reponsesJedanFajl/fajl.csv"),
drop_read_csv, stringsAsFactors = FALSE, encoding = 'UTF-8') %>%
do.call(rbind, .)
write.csv(data, "fajl.csv", row.names = FALSE, quote = TRUE, fileEncoding = "UTF-8")
# Upload the file to Dropbox
drop_upload("fajl.csv", path = outputJedan, mode = "overwrite")
data
}
# UI
ui <- dashboardPage(
dashboardHeader(title = "HDCK-ČK Dashboard"),
skin = "red",
## Sidebar content
dashboardSidebar(
collapsed = TRUE,
sidebarMenu(
#menuItem("Dashboard", tabName = "dashboard", icon = icon("dashboard")),
menuItem("Evidencija", tabName = "evidencija", icon = icon("th")),
#menuItem("Evidencija", tabName = "evidencija", icon = icon("th")),
menuItem("Sajt", icon = icon("send",lib='glyphicon'),
href = "http://www.crveni-kriz-cakovec.hr")
)
),
## Body content
dashboardBody(
tabItems(
# First tab content
tabItem(
tabName = "evidencija",
navbarPage("",
tabPanel("Upis",
fluidPage(
shinyjs::useShinyjs(),
shinyjs::inlineCSS(appCSS),
sidebarPanel(
width = 3,
id = "form",
textInput("Ime", labelMandatory("1. Ime")),
textInput("Prezime", labelMandatory("2. Prezime")),
textInput("Adresa", label = "3. Adresa (ulica i broj, mjesto)"),
textInput(inputId = "BrojTel", label = "4. Broj telefona",
value = NULL),
numericInput(inputId = "OIB", label = "5. OIB", value = NULL),
#checkboxInput("CZSS", "Označiti ako je korisnik CZSS", FALSE),
#sliderInput("Dob", "5. Dob", 1, 100, 50, ticks = FALSE),
textAreaInput("Problem", labelMandatory("6. Opis problema ili potrebe"),
"", height = 100),
textAreaInput("Rjesenje", "7. Na koji način je problem riješen?",
"", height = 50),
selectInput("Pomagac", "8. Pomagač",
c("", "Barbara", "Elizabeta",
"Ines", "Iva", "Lana", "Vlatka", "Željka")),
numericInput(inputId = "Trajanje", label = "9. Trajanje razgovora u min", value = 5),
actionButton("submit", "Unesi")#, class = "btn-primary")
),
mainPanel(
width = 9,
h3("Tablica s pregledom prethodnih zapisa:"),
DT::dataTableOutput("responsesTable"),
style = "overflow-y: scroll;overflow-x: scroll; overflow: auto;",
#downloadButton("downloadBtn", "Skini *.csv"),
# br(),
# actionButton("viewBtn","View"),
br(),
actionButton("saveBtn", "Zapiši rješenje", style="float:right")
# br(),
# DT::dataTableOutput("updated.df")
)
)),
tabPanel("Upute"
)
)
)
)
)
)
# Server
# Učitavnje podataka na prvom učitavnju app
tablica <- function() {
data <- drop_read_csv("reponsesJedanFajl/fajl.csv", fileEncoding = "UTF-8",
stringsAsFactors = FALSE)
data
}
server <- function(input, output, session) {
drop_auth(rdstoken = "dropbox_token.rds")
# Prikaži tablicu na onload
tablicica <- data.frame(tablica())
output$responsesTable <- DT::renderDataTable(
tablicica,
selection = "none",
editable = TRUE,
rownames = FALSE,
extensions = 'Buttons',
server = FALSE,
options = list(
paging = TRUE,
searching = TRUE,
scroller = TRUE,
dom = 'Bfrtip',
extensions = c('Responsive', 'Buttons'),
buttons = c('excel', 'pdf', 'copy', 'csv', 'print')
))
# Provjera obaveznih polja kod upisa
observe({
mandatoryFilled <-
vapply(fieldsMandatory,
function(x) {
!is.null(input[[x]]) && input[[x]] != ""
},
logical(1))
mandatoryFilled <- all(mandatoryFilled)
shinyjs::toggleState(id = "submit", condition = mandatoryFilled)
})
# Čuvanje pojedinih inputa u csv nakon upisa
formData <- reactive({
data <- sapply(fieldsAll, function(x) input[[x]])
data <- c(data, VremenskiPoredak = humanTime())
data <- t(data)
data
})
# Čuvanje inputa u pojedinim csv i što učiniti nakon što se stisne gumb
saveData <- function(data) {
#data <- t(data)
# Unique file name
fileName <- sprintf("%s_%s.csv", humanTime(), digest::digest(data))
# Čuvanje fajla u prvremenom direktoriju
filePath <- file.path(tempdir(), fileName)
write.csv(data, filePath, row.names = FALSE, quote = TRUE, fileEncoding = "UTF-8")
# Upload fajla na Dropbox
drop_upload(filePath, path = outputDir)
}
# akcija kad se pritisne gumb Zapiši, za zapisivanje novih upisa
observeEvent(input$submit, {
saveData(formData())
# I prikaži tablicu s novim upisima
output$responsesTable <- DT::renderDataTable(
datatable(
loadData(),
rownames = FALSE,
extensions = 'Buttons',
#server = FALSE,
options = list(
paging = TRUE,
searching = TRUE,
#fixedColumns = FALSE,
#autoWidth = TRUE,
#ordering = TRUE,
deferRender = TRUE,
#scrollY = 400,
scroller = TRUE,
dom = 'Bfrtip',
orientation ='landscape',
extensions = c('Responsive', 'Buttons'),
buttons = c('excel', 'pdf', 'copy', 'csv', 'print')
))
)
})
observeEvent(input$responsesTable_cell_edit, {
tablicica[input$responsesTable_cell_edit$row,
input$responsesTable_cell_edit$col] <<- input$responsesTable_cell_edit$value
})
observeEvent(input$saveBtn,{
write.csv(tablicica, "fajl.csv", row.names = FALSE, quote = TRUE, fileEncoding = "UTF-8")
# Upload the file to Dropbox
drop_upload("fajl.csv", path = outputJedan, mode = "overwrite")
# Prikaži tablicu nakon što su unesene promjene
output$responsesTable <- DT::renderDataTable(
datatable(
tablicica,
rownames = FALSE,
options = list(
searching = TRUE,
lengthChange = TRUE
# # fixedColumns = FALSE,
# # autoWidth = TRUE,
# # ordering = FALSE,
# dom = 'tB',
# buttons = c('copy', 'csv', 'excel', 'pdf')
# ),
# # class = "display", #if you want to modify via .css
# # extensions = "Buttons"
))
)
})
# # Download button
# output$downloadBtn <- downloadHandler(
# filename = function() {
# sprintf("evidencija-psihosocijalne_%s.csv", humanTime())
# },
# content = function(file) {
# write.csv(loadData(), file, row.names = FALSE)
# }
# )
# Reset formu nakon submita
observeEvent(input$submit, {
reset("form")
})
}
shinyApp(ui, server)
R and DT count columns differently. In R the leftmost column is column 1. In DT the leftmost column is column 0. This is also known as one or zero-based array indexing.
Adding a few strategic +1 or -1 will do the trick.
If you need help knowing where to put those, feel free to post a minimal example and we can help you work through it.
I have a reactive graph that takes in multiple inputs but it is dependent on all those inputs. Is there a way that the graph can take all the inputs but it isn't dependent on them all. For example if the user selects one drop down the graph will update and not need any of the other inputs but if the user adds a second input the graph will update with the 2nd input but not need the 3rd unless it is selected. Also if what the user has selected is null it won't change the graph.
UI:
ui <- dashboardPage(
dashboardHeader(title = "Human Trafficking"),
dashboardSidebar(
sidebarMenu(
selectInput("Source", "Choose a Data Source: ", choices = sort(unique(ngo$Data.Provided.By)), selected = NULL,
multiple = TRUE, selectize = TRUE, width = NULL, size = NULL),
dateInput("startdate", "Start Date:", value = "2009-01-01", format = "dd-mm-yyyy",
min = "2009-01-01", max = "2019-08-26"),
dateInput("enddate", "End Date:", value = "2019-08-27", format = "dd-mm-yyyy",
min = "2009-01-02", max = "2019-08-27"),
selectInput("Nationality", "Select a nation: ", choices = sort(unique(ngo$Victim.Nationality))),
actionButton("button", "Apply")
)
),
dashboardBody(
fluidRow(
box(width = 4, solidHeader = TRUE,
selectInput("traffickingType", "Choose a trafficking type: ", choices = sort(unique(ngo$Trafficking.Type)), selected = NULL,
multiple = TRUE, selectize = TRUE, width = NULL, size = NULL)
),
box(width = 4, solidHeader = TRUE,
selectInput("traffickingSubType", "Choose a trafficking sub type: ", choices = sort(unique(ngo$Trafficking.Sub.Type)), selected = NULL,
multiple = TRUE, selectize = TRUE, width = NULL, size = NULL)
),
box(width = 4, solidHeader = TRUE,
selectInput("gender", "Choose a gender: ", choices = sort(unique(ngo$Victim.Gender)), selected = NULL,
multiple = TRUE, selectize = TRUE, width = NULL, size = NULL)
)
),
fluidRow(
box(width = 6, solidHeader = TRUE, status = "primary",
title = "Trafficking Type",
plotlyOutput("coolplot", width = '750px', height = '600px')
),
box(width = 6, solidHeader = TRUE, status = "primary",
title = "Trafficking Sub-Type",
plotlyOutput("Sub", width = '750px', height = '600px')
)
)
)
)
Server:
server <- function(input, output, session) {
output$coolplot <- renderPlotly({
ngo <-
ngo %>%
filter(Victim.Nationality %in% input$Nationality,
Victim.Gender %in% input$gender,
Trafficking.Type %in% input$traffickingType,
Trafficking.Sub.Type %in% input$traffickingSubType,
Data.Provided.By %in% input$Source
) %>%
plot_ly(labels = ~Trafficking.Type, type = "pie")
})
}
I want to be able to allow the user to select one input and it will update graph and the more they add the graph will keep updating.
Not the neatest but what about separating the filtering as below:
server <- function(input, output, session) {
output$coolplot <- renderPlotly({
req(c(input$gender, input$traffickingType, input$traffickingSubType))
if(!is.null(input$Nationality)) {
ngo <- ngo %>% filter(Victim.Nationality %in% input$Nationality)
}
if(!is.null(input$gender)) {
ngo <- ngo %>% filter(Victim.Gender %in% input$gender)
}
if(!is.null(input$traffickingType)) {
ngo <- ngo %>% filter(Trafficking.Type %in% input$traffickingType)
}
if(!is.null(input$traffickingSubType)) {
ngo <- ngo %>% filter(Trafficking.Sub.Type %in% input$traffickingSubType)
}
if(!is.null(input$Source)) {
ngo <- ngo %>% filter(Data.Provided.By %in% input$Source)
}
plot_ly(ngo, labels = ~Trafficking.Type, type = "pie")
})
}
shinyApp(ui, server)
Update
based on comment below.
I added req(c(input$gender, input$traffickingType, input$traffickingSubType)).
I left out input$Nationality as that equals "A" on startup and input$Source I assumed but you can add input$source to the vector c(...) above if you want.