I just started to use Shiny and I'm having some troubles with my code. I tried several codes and searched a lot but I can't figure out how to create what I need.
I have a .R file that has several formulas and in the end returns a .csv file. I need to make this more "user friendly", so I'm trying to do that with Shiny.
This is what I've achieved so far...
So, I need a field to insert a password and if the password is correct, I can press Run Code. The Run Code must run the code with the formulas and create a csv file. Fisrtly I tried to connect the shiny app with .R file, then I tried to insert the code in Shiny and create a table that will be downloaded using the download data button.
Previous Code
library(shiny)
library(shinyWidgets)
library(shinydashboard)
CODE <- function(){
DATA <- data.frame(
Name = c("Claudia","Dan","Mike","Brian","Gary"),
Age = c(3,51,20,45,5)
return(DATA)
}
ui<- fluidPage(tags$head(tags$style(
HTML('
#sidebar {
background-color: #CCCCCC ;
}
body, label, input, button, select {
font-family: "Arial";
}
<script type="text/javascript">
$(document).ready(function() {
$("#downloadData").click(function() {
var filtered_table_data = $("#DataTables_Table_0").dataTable()._("tr", {"filter":"applied"});
Shiny.onInputChange("filtered_table", filtered_table_data);
});
});
</script>')
)),
setBackgroundColor(
color = c("#FFFFFF", "#999999"),
gradient = "linear",
direction = "bottom"
),#headerPanel(
# HTML('<p><img src="dhp_logo.png"/></p>')
#),
dashboardHeader(title = span("TEST ",style = "color: #999999; font-size: 50px;font-weight: bold")),
sidebarLayout(sidebarPanel(id="sidebar",passwordInput("password", "Password:"),
actionButton("go", "Go"),
verbatimTextOutput("DHP2021")),
mainPanel(actionButton("run", "Run Code",icon("refresh", "fa-3x"), width="400px",style="color: #FFFFFF; background-color: #666666; border-color: #666666")
,downloadButton('downloadData', 'Download Data'),dataTableOutput("table")
)))
server <- function(input, output, session){
output$value <- renderText({
req(input$go)
isolate(input$password)
})
Data <- reactive({
DATA <- input$run
return(data.frame(DATA))
})
output$table <- renderDataTable({
Data()
}, options = list(sDom = "ilftpr"))
ProcessedFilteredData <- reactive({
v <- input$filtered_table_data
col_names <- names(Data())
n_cols <- length(col_names)
n_row <- length(v)/n_cols
m <- matrix(v, ncol = n_cols, byrow = TRUE)
df <- data.frame(m)
names(df) <- col_names
return(df)
})
output$downloadData <- downloadHandler(
filename = function() { 'DATA.csv' }, content = function(file) {
write.csv(ProcessedFilteredData(), file, row.names = FALSE)
})
}
shinyApp(ui,server)
UPDATE
library(shiny)
library(shinyWidgets)
library(shinydashboard)
CODE <- function(){
DATA <- data.frame(
Name = c("Claudia","Dan","Mike","Brian","Gary"),
Age = c(3,51,20,45,5)
return(DATA)
}
Logged = FALSE
my_username <- "test"
my_password <- "test"
ui1 <- function(){
tagList(
div(id = "login",
wellPanel(textInput("userName", "Username"),
passwordInput("passwd", "Password"),
br(),
actionButton("Login", "Log in"),
verbatimTextOutput("dataInfo")
)
),
tags$style(type="text/css", "#login {font-size:30px; text-align: left;position:absolute;top: 40%;center: 90%}")
)}
ui2 <- function(){tagList(
"Successful login!"
)
mainPanel(actionButton("run", "Run Code",icon("refresh", "fa-3x"), width="400px",style="color: #FFFFFF; background-color: #666666; border-color: #666666")
,downloadButton('downloadData', 'Download Data'),dataTableOutput("table")
) }
header <- dashboardHeader(title = "Login")
sidebar <- dashboardSidebar()
body <- dashboardBody(htmlOutput("page"))
ui = dashboardPage(header, sidebar, body)
server <- function(input, output, session){
Logged <- FALSE
Security <- TRUE
USER <- reactiveValues(Logged = Logged)
SEC <- reactiveValues(Security = Security)
observe({
if (USER$Logged == FALSE) {
if (!is.null(input$Login)) {
if (input$Login > 0) {
Username <- isolate(input$userName)
Password <- isolate(input$passwd)
if(my_username == Username & my_password == Password) {
USER$Logged <- TRUE
} else {SEC$Security <- FALSE}
}
}
}
})
observe({
if (USER$Logged == FALSE) {output$page <- renderUI({ui1()})}
if (USER$Logged == TRUE) {output$page <- renderUI({ui2()})}
if(USER$Logged == TRUE){output$run <- reactiveUI(CODE)}
if(USER$Logged==TRUE){output$table <- renderDataTable(output$run())}
if(USER$Logged==TRUE){output$downloadData <- downloadHandler(
filename = function() { 'Data.csv' }, content = function(file) {
write.csv(Data(), file, row.names = FALSE)})
}})
observe({
output$dataInfo <- renderText({
if (SEC$Security) {""}
else {"Incorrect username or password"}
})
})
}
What is going wrong?
I can't run code or create the table
Warning: Error in $.shinyoutput: Reading from shinyoutput object is not allowed.
As I previously said, I'm just starting to use Shiny, so probably I'm making code mistakes that I can't perceive yet. I hope the example helps, if you need me to be more enlightening, just say.
Thanks in advance for any help or advice you can give me
=)
Related
I need a shiny app to do the following:
The user clicks a button
N pop-ups appear to the user asking for input
Then the user downloads the information displayed in the app with a download button
I've been able to achieve points 1 & 2, however I haven't been able to get to 3 because of the fact that the user inputs are reactive values. Here is a sample of code that almost works:
library(shiny)
library(shinyalert)
test <- c("C", "D", "F")
NUM_MODALS <- length(test)
ui <- fluidPage(
shinyalert::useShinyalert(),
actionButton("show", "Show modal dialog"),
lapply(seq(NUM_MODALS), function(id) {
div(id, ":", textOutput(paste0("modal", id), inline = TRUE))
}),
downloadButton("downloadData", "Download")
)
server <- function(input, output) {
observeEvent(input$show, {
for(id in 1:NUM_MODALS){
shinyalert::shinyalert(
type = "input",
text = paste("¿Cuál es la industria de la siguiente empresa?:", test[id]),
inputPlaceholder = "Cuidado con mayúsculas/minúsculas",
inputId = paste0("modal", id)
)
}
})
lapply(seq(NUM_MODALS), function(id) {
output[[paste0("modal", id)]] <- renderText({paste(test[id],input[[paste0("modal", id)]])})
})
export <- reactive(c(input$modal1, input$modal2, input$modal3))
export2 <- isolate(export)
print(export2)
#browser()
output$downloadData <- downloadHandler(
filename = function() {
paste('data-', Sys.Date(), '.csv', sep='')
},
content = function(filesillo) {
fs <- c()
tmpdir <- tempdir()
setwd(tempdir())
path <- paste("prueba.txt", sep = "")
fs <- c(fs, path)
write.csv(export2, filesillo)
}
)
}
shinyApp(ui = ui, server = server)
Instead of the inputs being assigned as a reactive, you can assign to reactiveValues in an observe.
export <- reactiveValues(
dat = NULL
)
observe({
export$dat <- dplyr::bind_rows(
modal1 = input$modal1,
modal2 = input$modal2,
modal3 = input$modal3
)
})
# export <- reactive(c(input$modal1, input$modal2, input$modal3))
# export2 <- isolate(export)
# print(export2)
#browser()
Then in your downloadHandler
#write.csv(export2, filesillo)
write.csv(export$dat, filesillo)
This will output a csv with modal inputs as columns
I'm modularizing a Shiny app I developed using shinydashboard packages. Despite it traditionally works when I use it without involving modules, I can't make it work when I try to divide it into modules and submodules. Here I would like to combine two UIs (one for the sidebar, one for the body) in order to upload a dataset from the sidebar and show it into the body.
I'd be very glad if anybody could provide me some help with this.
Here is the code of the general Shiny app:
library(shiny)
library(excelR)
library(vroom)
library(readxl)
library(janitor)
library(dplyr)
library(shinydashboard)
library(shinydashboardPlus)
# # load separate module and function scripts
source("modules.R")
# app_ui
app_ui <- function() {
tagList(
shinydashboardPlus::dashboardPagePlus(
header = shinydashboardPlus::dashboardHeaderPlus(title = "module_test",
enable_rightsidebar = FALSE),
sidebar = shinydashboard::dashboardSidebar(
shinydashboard::sidebarMenu(id = "tabs",
import_sidebar_ui("import"))
),
body = shinydashboard::dashboardBody(shinydashboard::tabItems(
import_body_ui("import"))
),
rightsidebar = NULL,
title = "Module App"
)
)
}
# app_server
app_server <- function(input, output, session) {
shiny::moduleServer(id = "import", module = import_server)
}
####################################################################
run_app <- function(...) {
shiny::shinyApp(
ui = app_ui,
server = app_server)
}
#---------------------------------
run_app()
and here is the modules.R file I wrote containing the UIs for sidebar and body, plus the server:
# Import module ####
#
# Import sidebar UI
import_sidebar_ui <- function(id) {
ns <- NS(id)
shinydashboard::menuItem("Module Testing",
tabName = "tab_testing_mod",
icon = icon("th"),
tagList(
selectInput(ns("input_type"),
"Type of file:",
choices = c("Choose one" = "",".csv" = "csv",
".txt" = "txt", ".xls/.xlsx" = "xlsx"),
selected = NULL),
uiOutput(ns("inputControls")),
fileInput(ns("file"), "Data", buttonLabel = "Upload..."),
checkboxInput(ns("rownames"), "Check if 1st column contains rownames"),
checkboxInput(ns("constant"), "Remove constant columns?"),
checkboxInput(ns("empty"), "Remove empty cols?"),
actionButton(ns("bttn_import"), "Import data")
)
)
}
# Import body UI
import_body_ui <- function(id) {
ns <- NS(id)
shinydashboard::tabItem(tabName = "tab_testing_mod",
fluidRow(
h3("Imported Data"),
excelR::excelOutput(ns("preview")))
)
}
# Import server
import_server <- function(input, output, session) {
ns <- session$ns
output$inputControls <- renderUI({
tagList(
switch(input$input_type,
"csv" = textInput("delim", "Delimiter (leave blank to guess)", ""),
"txt" = textInput("delim", "Delimiter (leave blank to guess)", "")
),
switch(input$input_type,
"xlsx" = numericInput("sheet", "Sheet number", value = 1))
)
})
raw <- reactive({
req(input$file)
if (input$input_type == "csv" || input$input_type == "txt") {
delim <- if (input$delim == "") NULL else input$delim
data <- vroom::vroom(input$file$datapath, delim = delim)
} else if (input$input_type == "xlsx") {
data <- tibble::as.tibble(readxl::read_excel(input$file$datapath, sheet = input$sheet, col_names = TRUE))
} else {
return(NULL)
}
raw <- data
raw
})
tidied <- eventReactive(input$bttn_import,{
out <- raw()
if (input$empty) {
out <- janitor::remove_empty(out, "cols")
}
if (input$constant) {
out <- janitor::remove_constant(out)
}
if (input$rownames) {
out <- tibble::column_to_rownames(out, var = colnames(out[1]))
}
out <- out %>% dplyr::mutate_if(is.character,as.factor)
out
})
output$preview <- excelR::renderExcel({
excelR::excelTable(data = raw(),
colHeaders = toupper(colnames(raw())),
fullscreen = FALSE,
columnDrag = TRUE,
rowDrag = TRUE,
wordWrap = FALSE,
search =TRUE,
showToolbar = TRUE,
minDimensions = c(ncol(raw()),10)
)
})
}
It seems to me I can upload the dataset (.csv, .txt or .xlsx) files but I can't show it into the body.
I'd be very glad if you can help me, thank you very much in advance for your assistance.
I am developing a shiny app which stores the arbitrary data. I have referred This link for the same. I can able to display all the responses including previous responses, but i want to display only the current response, not all response. My code snippet is as given below:
library(shiny)
outputDir <- "C:\\Users/dell/Desktop/"
saveData <- function(data) {
data <- as.data.frame(t(data))
if (exists("responsesiq")) {
responsesiq <<- rbind(responsesiq, data)
} else {
responsesiq <<- data
}
fileName <- "test_irty.csv"
write.csv(
x = responsesiq, sep = ",",
file = file.path(outputDir, fileName),
row.names = FALSE, quote = TRUE
)
}
loadData <- function() {
if (exists("responsesiq")) {
responsesiq
}
}
fields <- c("acc", "staff_name")
shinyApp(
ui = fluidPage(
titlePanel(" System"),
DT::dataTableOutput("responsesiq", width = 300), tags$hr(),
numericInput("acc", "Acc Number", ""),
selectInput("staff_name", "Staff Name",
c("Rajivaksh " = "RT",
"Arvind " = "AKS",
"Ashutosh " = "AS")),
actionButton("submit", "Submit")
),
server = function(input, output, session) {
formData <- reactive({
data <- sapply(fields, function(x) input[[x]])
data
})
observeEvent(input$submit, {
saveData(formData())
})
# Show the previous responses
# (update with current response when Submit is clicked)
output$responsesiq <- DT::renderDataTable({
input$submit
loadData()
})
}
)
Create reactiveValues to hold the current entry, which will trigger when clicking submit
shinyApp(
ui = fluidPage(
titlePanel(" System"),
DT::dataTableOutput("responsesiq", width = 300), tags$hr(),
numericInput("acc", "Acc Number", ""),
selectInput("staff_name", "Staff Name",
c("Rajivaksh " = "RT",
"Arvind " = "AKS",
"Ashutosh " = "AS")),
actionButton("submit", "Submit")
),
server = function(input, output, session) {
formData <- reactive({
data <- sapply(fields, function(x) input[[x]])
data
})
tmp <- reactiveValues(df=NULL)
observeEvent(input$submit, {
saveData(formData())
tmp$df <- t(formData())
})
# Show the previous responses
# (update with current response when Submit is clicked)
output$responsesiq <- DT::renderDataTable({
input$submit
#loadData()
data.frame(tmp$df)
})
}
)
I was trying to switch the label of a show/hide columns button, and also keep the track of the number of times it is clicked in order to alter the number of columns showed of a table. I made it, but I couldn't use a direct even/odd differentiation of the value of the counter. Instead I had to use this: (vars$counter+1)/2) %% 2 == 0) to make it work, because each click changes the counter 2 times. I would like to request an easier procedure, maybe there is a shinyBS for that?
## app.R ##
library(shiny)
library(shinydashboard)
library(DT)
body<-dashboardBody(
textOutput("count"),
uiOutput('showallcolumnsbutton'),
DT::dataTableOutput('table2')
)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
body
)
server <- function(input, output) {
table<-data.frame(replicate(10,sample(0:1,1000,rep=TRUE)))
vars<-reactiveValues()
vars = reactiveValues(counter = 0)
observe({
if(!is.null(input$showallcolumns)){
input$showallcolumns
isolate({
vars$counter <- vars$counter + 1
})
}
})
label <- reactive({
if(!is.null(input$showallcolumns)){
if( ( (vars$counter+1)/2) %% 2 == 0) label <- "Hide"
else label <- "Show"
}
})
output$showallcolumnsbutton <- renderUI({
actionButton("showallcolumns", label = label(),
icon("hand-pointer-o"),
style="color: #000; background-color: #0099ff; border-color: #2e6da4"
)
})
output$count<-renderText({paste("counter value:",vars$counter)})
columnstoshow = reactive ({
x= ((vars$counter+1)/2) # %% 2 == 0)
if (!is.null (x))
{
if (x %% 2 == 0) {
c=c(1:10)
}
else {
c=c(1:5)
}
} #end 1st if
else {
c=c(1:10)
}
})
output$table2 = DT::renderDataTable({
DT::datatable(table[, columnstoshow()])
})
} # end server
shinyApp(ui, server)
Since Im not 100% what you want, is this it? Note that I used other library such as shinyBS
rm(list = ls())
library(shiny)
library(shinydashboard)
library(DT)
library(shinyBS)
body <- dashboardBody(bsButton("showallcolumns", label = "Hide", block = F, style="danger",icon=icon("hand-pointer-o")),br(),DT::dataTableOutput('table2'))
ui <- dashboardPage(dashboardHeader(),dashboardSidebar(),body)
server <- function(input, output,session) {
table <- data.frame(replicate(10,sample(0:1,1000,rep=TRUE)))
vars <- reactiveValues(counter = 1:10)
observeEvent(input$showallcolumns,{
if(input$showallcolumns %% 2){
updateButton(session, "showallcolumns",label = "Show", block = F, style = "success",icon=icon("hand-pointer-o"))
vars$counter <- 1:5
}
else{
updateButton(session, "showallcolumns",label = "Hide", block = F, style = "danger",icon=icon("hand-pointer-o"))
vars$counter <- 1:10
}
})
output$table2 = DT::renderDataTable({
DT::datatable(table[, vars$counter])
})
} # end server
shinyApp(ui, server)
I am running an example from here.
library(rhandsontable)
library(shiny)
runApp(shinyApp(
ui = fluidPage(rHandsontableOutput("hot")),
server = function(input, output, session) {
fname <- "mtcars2.csv"
values <- reactiveValues()
setHot <- function(x) values[["hot"]] = x
observe({
if(!is.null(values[["hot"]])) write.csv(values[["hot"]], fname)
})
output$hot <- renderRHandsontable({
if (!is.null(input$hot)) {
DF <- hot_to_r(input$hot)
} else {
DF <- read.csv("mtcars.csv", stringsAsFactors = FALSE)
}
setHot(DF)
rhandsontable(DF) %>%
hot_table(highlightCol = TRUE, highlightRow = TRUE) %>%
hot_cols(columnSorting = TRUE)
})
}
))
I want changes made to table be saved in file mtcars2.csv. I also want to preserve row order. In project home page it says "sorting only impacts the widget and will not reorder the original data set". Can I somehow get current view of a table and save it?
The best way to answer this question will be to file an issue at https://github.com/jrowen/rhandsontable. Currently, these lines define only a partial list of handsontable events. This list does not include afterColumnSort which would be what you need. Here is a quick hack to partially answer your question.
library(rhandsontable)
library(shiny)
library(htmlwidgets)
runApp(shinyApp(
ui = fluidPage(
rHandsontableOutput("hot"),
tags$script(
'
setTimeout(
function() {
HTMLWidgets.find("#hot").hot.addHook(
"afterColumnSort",
function(){
console.log("sort",this);
Shiny.onInputChange(
"hot_sort",
{
data: this.getData()
}
)
}
)
},
1000
)
'
)
),
server = function(input, output, session) {
observeEvent(
input$hot_sort
,{
print(input$hot_sort$data)
}
)
output$hot <- renderRHandsontable({
if (!is.null(input$hot)) {
DF <- hot_to_r(input$hot)
} else {
DF <- mtcars
}
rhandsontable(DF) %>%
hot_table(highlightCol = TRUE, highlightRow = TRUE) %>%
hot_cols(columnSorting = TRUE)
})
}
))
I don't think there is a way to preserve the sorted columns in DataTables for shiny, Sad!
With the below code I'm able to save changes made in shiny app to the file mtcars2.csv. Interestingly! post sorting by desired column, clicking on any data cell and pressing enter key saves the row order to the mtcars2.csv. Agree with timelyportolio's point on filing an issue on git.
R Code:
library(shiny)
library(rhandsontable)
runApp(shinyApp(
ui = fluidPage(titlePanel("Edit Data File"),
helpText("Changes to the table will be automatically saved to the source file."),
# actionButton("saveBtn", "Save"),
rHandsontableOutput("hot")),
shinyServer(function(input, output, session) {
values = reactiveValues()
data = reactive({
if (is.null(input$hot)) {
hot = read.csv("mtcars.csv", stringsAsFactors = FALSE)
} else {
hot = hot_to_r(input$hot)
}
# this would be used as a function input
values[["hot"]] = hot
hot
})
observe({
# input$saveBtn
if (!is.null(values[["hot"]])) {
write.csv(values[["hot"]], "mtcars.csv", row.names = FALSE)
}
})
output$hot <- renderRHandsontable({
hot = data()
if (!is.null(hot)) {
hot = rhandsontable(hot) %>%
hot_table(highlightCol = TRUE, highlightRow = TRUE) %>%
hot_cols(columnSorting = TRUE)
hot
}
})
})
))