I use Timevis package.
first of all I read an excel file with missions.
In my code the user can see all the missions on a time line, and he can edit/add/remove any missions.
after the user make a change I can see the update table below.
I want to save to my excel file every update that the user make.
this is my code:
library(shiny)
library(timevis)
library(readxl)
my_df <- read_excel("x.xlsx")
data <- data.frame(
id = my_df$id,
start = my_df$start,
end = my_df$end,
content = my_df$content
)
ui <- fluidPage(
timevisOutput("appts"),
tableOutput("table")
)
server <- function(input, output) {
output$appts <- renderTimevis(
timevis(
data,
options = list(editable = TRUE, multiselect = TRUE, align = "center")
)
)
output$table <- renderTable(
input$appts_data
)
}
shinyApp(ui, server)
You can use actionButton/ observe to call saveworkbook (package openxlsx) to save your changes. Technically you are not saving these changes, but replacing the file with an identical file containing the changes.
library(shiny)
library(openxlsx)
library(timevis)
library(readxl)
my_df <- read_excel("x.xlsx")
data <- data.frame(
id = my_df$id,
start = my_df$start,
end = my_df$end,
content = my_df$content
)
mypath = paste0(getwd(), "/x.xlsx") # Path to x.xlsx
ui <- fluidPage(
timevisOutput("appts"),
tableOutput("table"),
actionButton("save", "Save")
)
server <- function(input, output) {
output$appts <- renderTimevis(
timevis(
data,
options = list(editable = TRUE, multiselect = TRUE, align = "center")
))
observeEvent(input$save,
{
my_df<- createWorkbook()
addWorksheet(
my_df,
sheetName = "data"
)
writeData(
wb = my_df,
sheet = "data",
x = input$appts_data,
startRow = 1,
startCol = 1
)
saveWorkbook(my_df, file = mypath,
overwrite = TRUE)
})
output$table <- renderTable(
input$appts_data
)
}
shinyApp(ui, server)
Related
I modified the example here to include a save button as well. I want the user to be able to reset to the initial table after uploading a new file by adding a reset button (similar to the save button), but I wonder if it's possible to do so.
EDIT:
I want the button to be a part of the DT table and be placed next to the save.
library(shiny)
library(DT)
library(dplyr)
ui <- fluidPage(
fileInput("upload", NULL, accept = c(".csv")),
DTOutput("head")
)
server <- function(input, output, session) {
rv <- reactiveValues(
dataframe = data.frame(
x = seq(1:12),
y = LETTERS[1:12])
)
observe({
req(input$upload)
ext <- tools::file_ext(input$upload$name)
rv$dataframe <- switch(ext,
csv = read.csv(input$upload$datapath),
NULL)
})
output$head <- renderDT({
validate(need(!is.null(rv$dataframe)," Please upload a .csv file"))
datatable(rv$dataframe, extensions = 'Buttons',
options = list(
dom = 'Bfrtip',
buttons = list(list( extend = 'csv',
filename = '//public/comments/comments.csv',
text = 'Save'))))
})
}
shinyApp(ui, server)
Here is a snapshot of the current version:
There could be multiple ways to handle this. Here is one of it -
Used a fixed dataframe mtcars[1:6, 1:6] as the default dataframe instead of one which generates random numbers which is difficult to compare imo.
Added an actionButton for Reset feature.
Created another reactive variable called dataframe_copy which always holds the default dataframe.
library(shiny)
library(DT)
library(dplyr)
ui <- fluidPage(
fileInput("upload", NULL, accept = c(".csv")),
DTOutput("head"),
actionButton('reset', 'Reset')
)
server <- function(input, output, session) {
rv <- reactiveValues(
dataframe = mtcars[1:6, 1:6],
dataframe_copy = mtcars[1:6, 1:6]
)
observe({
req(input$upload)
ext <- tools::file_ext(input$upload$name)
rv$dataframe <- switch(ext,
csv = read.csv(input$upload$datapath),
NULL)
})
observeEvent(input$reset, {
rv$dataframe <- rv$dataframe_copy
})
output$head <- renderDT({
validate(need(!is.null(rv$dataframe)," Please upload a .csv file"))
datatable(rv$dataframe, extensions = 'Buttons',
options = list(
dom = 'Bfrtip',
buttons = list(list( extend = 'csv',
filename = '//public/comments/comments.csv',
text = 'Save'))))
})
}
shinyApp(ui, server)
I would like to download the modified version of the table when I use the filter option in the table. Since the table is reactive based on the columns, only the chosen columns will be included in the downloaded dataset, however, every row is also included.
So for example, I choose 4 different columns and filter the dataset based on the columns and get only 2 rows. Is there a way to download this specific version of the table after the filter, instead of downloading the whole dataset?
library(shiny)
library(DT)
ui <- fluidPage(
title = "DataTables",
sidebarLayout(
sidebarPanel(
conditionalPanel(
'input.dataset == "cars"',
selectInput('col', ' ',choices = names(cars),multiple = TRUE,selected = c("price", "Mileage", "Cylinder")),
downloadButton("download_cars", "Download data")
)
),
mainPanel(
tabsetPanel(
id = 'dataset',
tabPanel("cars",
DT::dataTableOutput("mytable1"),
)
)
)
))
server <- function(input, output) {
car_data <- eventReactive(input$col, {
df <- cars[, input$col, drop = FALSE]
df
})
output$mytable1 <- DT::renderDataTable({
DT::datatable(car_data(), filter = "top", options = list(
orderClasses = TRUE
)
)
})
output$download_car <- downloadHandler(
filename = function() {paste("All_cars.csv", Sys.Date(), ".csv", sep = "")},
content = function(file){
write.csv(car_data(), file, row.names = FALSE)
}
)
}
shinyApp(ui, server)
I'm trying to implement a shiny app that contains some optional checkboxes. I would like to know how do I perform an analysis with a certain selection only if it is selected and, with that, the table with the analysis made from the selection also appears on the screen.
I would like the objects inside the rbind function (below) to be included only if they are selected in the checkboxes:
ameacadas <- rbind(ameacadas_BR,ameacadas_BR2, ameacadas_pa)
External files can be found at: https://github.com/igorcobelo/data_examples (The 'minati.csv' file is the input data).
My code is presented below:
# global
library(shiny)
library(tidyverse)
# ui
ui <- navbarPage(title = "Minati Flora.",
tabPanel(title = "Home",
br(),
hr(),
# Upload csv file
sidebarLayout(
sidebarPanel(
fileInput(
inputId = "csvFile",
label = "Upload",
accept = c(".csv")
),
checkboxInput('BR1','Federal1'),
checkboxInput('BR2','Federal2'),
checkboxInput('PA','ParĂ¡'),
downloadButton("download", "Download")
),
mainPanel(
tableOutput("modifiedData")
)
)
),
tabPanel(title = "About"),
inverse = T)
# server
server <- function(input, output) {
rawData <- eventReactive(input$csvFile, {
req(input$csvFile)
df <- read.csv(input$csvFile$datapath,sep=';',check.names = F,fileEncoding = "Latin1")
#read extern files
ameacadas_BR <- read.csv("ameacadas_BR.csv",sep=';',check.names = F,fileEncoding = "Latin1")
legis_BR <- "Portaria MMA N. 148/2022"
ameacadas_BR2 <- read.csv("ameacadas_BR2.csv",sep=';',check.names = F,fileEncoding = "Latin1")
legis_BR2 <- "Decreto Federal N. 5.975/2006"
ameacadas_pa <- read.csv("ameacadas_PA.csv",sep=';',check.names = F,fileEncoding = "Latin1")
legis_pa <- "Resolucao COEMA/PA N. 54/2007"
#Rbind all files selected
ameacadas <- rbind(ameacadas_BR,ameacadas_BR2, ameacadas_pa)
#General calculate
colnames(df)[1] <- "Especie" #coluna especies
ameacadas <- ameacadas %>%
group_by(Especie) %>%
mutate(Categoria_Ameaca = toString(Categoria_Ameaca),
Legislacao = toString(Legislacao))
ameacadas <- ameacadas[!duplicated(ameacadas[,1]),]
arv_com_ameacadas <- df %>% left_join(ameacadas, by = "Especie")
})
output$modifiedData <- renderTable({rawData() })
output$download <- downloadHandler(
filename = function() {paste("Minati_Flora_", Sys.Date(), ".csv", sep = "")},
content = function(file){
write.csv(rawData(), file, row.names = FALSE)
}
)
}
# Run the application
shinyApp(ui = ui, server = server)
The below reproducible code allows the user to select either a data table or a plot of the data for viewing (via input$view). I'm trying to create a conditional around the downloadHandler() so that if the user is viewing the data table and chooses to download, then the data is downloaded; otherwise if the user is viewing the plot and chooses to download then a plot in PNG format is downloaded. I'm running into issues around input$view reactivity. How would I modify the code below to conditionally download whichever (data or plot) the user is viewing?
The code as posted below works for viewing either data or plot, but only allows the data table to be downloaded. Offending lines of code that otherwise cause a crash are commented out.
Reproducible code:
library(shiny)
library(ggplot2)
ui <- fluidPage(
radioButtons("view",
label = "View data or plot",
choiceNames = c('Data','Plot'),
choiceValues = c('viewData','viewPlot'),
selected = 'viewData',
inline = TRUE
),
conditionalPanel("input.view == 'viewData'",tableOutput("DF")),
conditionalPanel("input.view == 'viewPlot'",plotOutput("plotDF")),
downloadButton("download","Download",style = "width:20%;")
)
server <- function(input, output, session) {
data <- data.frame(Period = c(1,2,3,4,5,6),Value = c(10,20,15,40,35,30))
data1 <- reactiveValues()
inputView <- reactive(input$view) # attempt to make input$view reactive
observeEvent(input$view,{data1$plot <- ggplot(data, aes(Period,Value)) + geom_line()})
output$DF <- renderTable(data)
output$plotDF <- renderPlot(data1$plot)
output$download <-
# if(inputView() == 'viewData'){
downloadHandler(
filename = function()
paste("dataDownload","csv",sep="."),
content = function(file){
write.table(
data,
na = "",
file,
sep = ",",
col.names = TRUE,
row.names = FALSE)
}
)
# }
# else{
# downloadHandler(
# filename = function(){paste("plotDownload",'.png',sep='')},
# content = function(file){
# ggsave(file,plot=data1$plot)
# }
# )
# }
}
shinyApp(ui, server)
Try this
library(shiny)
library(ggplot2)
ui <- fluidPage(
radioButtons("view",
label = "View data or plot",
choiceNames = c('Data','Plot'),
choiceValues = c('viewData','viewPlot'),
selected = 'viewData',
inline = TRUE
),
conditionalPanel("input.view == 'viewData'",tableOutput("DF")),
conditionalPanel("input.view == 'viewPlot'",plotOutput("plotDF")),
#downloadButton("download","Download",style = "width:20%;")
uiOutput("plotrtable")
)
server <- function(input, output, session) {
data <- data.frame(Period = c(1,2,3,4,5,6),Value = c(10,20,15,40,35,30))
data1 <- reactiveValues()
inputView <- reactive(input$view) # attempt to make input$view reactive
observeEvent(input$view,{data1$plot <- ggplot(data, aes(Period,Value)) + geom_line()})
output$DF <- renderTable(data)
output$plotDF <- renderPlot(data1$plot)
output$plotrtable <- renderUI({
if(input$view == 'viewData'){downloadButton("download","Download",style = "width:20%;") }
else {downloadButton("downloadp","Download",style = "width:20%;") }
})
output$download <- downloadHandler(
filename = function()
paste("dataDownload","csv",sep="."),
content = function(file){
write.table(
data,
na = "",
file,
sep = ",",
col.names = TRUE,
row.names = FALSE)
}
)
output$downloadp <- downloadHandler(
filename = function(){paste("plotDownload",'.png',sep='')},
content = function(file){
ggsave(file,plot=data1$plot)
}
)
}
shinyApp(ui, server)
I am setting up a module, with the purpose of having two data tables in the same app, in different tabs.
I would like to be able to edit and save each table separately.
In my code, only the first "save" button works, and it saves both data tables.
Ideally, each save button should work and save only the corresponding table.
Important: I use the modified version of DTedit:
devtools::install_github('DavidPatShuiFong/DTedit#2.2.1')
Here is my problematic code:
library(shiny)
library(DTedit)
myModuleUI <- function(id,nam) {
ns <- shiny::NS(id)
shiny::tagList(
br(),
##### needs corrections!!
tabsetPanel(tabPanel("XXX", dteditmodUI(ns(nam)),actionButton(ns("reset"), "Reset to Saved", styleclass = "warning"), actionButton(ns("saveBtn"), label = "save"), br(),
id=ns('tabset'), type = 'tabs')
)
)
####
}
myModule <- function(input, output, session,df,nam,taby,wb) {
dfr=reactiveVal()
dfr(df)
Grocery_List_Results <- shiny::callModule(
dteditmod,
id = nam,
thedata =dfr)
# ### save part
savd = data.frame(isolate(dfr()))
observeEvent(input$saveBtn, {
print("Q")
## Add worksheets
st = paste(taby,as.character(unclass(Sys.time())),sep="_")
addWorksheet(wb, st)
writeData(x = Grocery_List_Results$thedata,
wb = wb,
sheet = st)
saveWorkbook(wb, "wb.xlsx", overwrite = T)
savd <<- Grocery_List_Results$thedata
shinyalert(title = "Saved!", type = "success")
})
observeEvent(input$reset, {
dfr(savd)
print(dfr)
shinyalert(title = "Reset to saved data!", type = "info")
})
}
########
ui <- fluidPage(
h3('Grocery List'),
myModuleUI('myModule1',nam="groc"),br(),
myModuleUI('myModule1',nam="groc2")
)
server <- function(input, output, session) {
df= data.frame(
Buy = c('Tea', 'Biscuits', 'Apples',"Tea","Apples"),
Quantity = c(7, 2, 5,9,44),
stringsAsFactors = FALSE
)
file = "AICs.xlsx"
wb <- loadWorkbook(file)
shiny::callModule(myModule, 'myModule1',nam="groc",df=df,taby="Tea",wb)
shiny::callModule(myModule, 'myModule1',nam="groc2",df=df,taby="Apples",wb)
}
shinyApp(ui = ui, server = server)
Appreciate your time!
At long last,
and thanks to this thread,
it seems that I managed to solve this:
library( "openxlsx" )
library("shiny" )
library(shinyalert)
library(shinysky)
library(DTedit) ## used the modified version from https://github.com/DavidPatShuiFong/DTedit
#installed with devtools::install_github('DavidPatShuiFong/DTedit#2.2.1')
results_2_UI <- function(id,nam) {
useShinyalert()
ns <- NS(id)
tabPanel(
title = "Export1",
dteditmodUI(ns(nam)),
actionButton(ns("reset"), "Reset to Saved", styleclass = "warning"), actionButton(ns("saveBtn"), label = "save")
)
}
results_3_UI <- function(id,nam) {
useShinyalert()
ns <- NS(id)
tabPanel(
title = "Export2",
dteditmodUI(ns(nam)),
actionButton(ns("reset"), "Reset to Saved", styleclass = "warning"), actionButton(ns("saveBtn"), label = "save")
)
}
results <- function(input, output, session,df,nam,taby,wb) {
## do some complicated data transformations
dfr=reactiveVal()
dfr(df)
Grocery_List_Results <- shiny::callModule(
dteditmod,
id = nam,
thedata =dfr)
# ### save part
savd = data.frame(isolate(dfr()))
observeEvent(input$saveBtn, {
print("Q")
## Add worksheets
st = paste(taby,as.character(unclass(Sys.time())),sep="_")
addWorksheet(wb, st)
writeData(x = Grocery_List_Results$thedata,
wb = wb,
sheet = st)
saveWorkbook(wb, "wb.xlsx", overwrite = T)
savd <<- Grocery_List_Results$thedata
shinyalert :: shinyalert(title = "Saved!", type = "success")
})
observeEvent(input$reset, {
dfr(savd)
print(dfr)
shinyalert::shinyalert(title = "Reset to saved data!", type = "info")
})
}
### module end
ui <- fluidPage(
tabsetPanel(
id = "tabs",
# results_1_UI(id = "test1"),
results_2_UI(id = "test2",nam="groc"),
results_3_UI(id = "test3",nam="groc2")
)
)
server <- function(input, output, session) {
df= data.frame(
Buy = c('Tea', 'Biscuits', 'Apples',"Tea","Apples"),
Quantity = c(7, 2, 5,9,44),
stringsAsFactors = FALSE
)
file = "AICs.xlsx"
wb <- loadWorkbook(file)
callModule(
module = results,
id = "test2",
nam="groc",df=df,taby="groc",wb=wb
)
callModule(
module = results,
id = "test3",
nam="groc2",df=df,taby="groc2",wb=wb
)
}
shinyApp(ui = ui, server = server)
Fingers crossed, it is OK!