In data table, we can use argument editable to make the table editable. I'm making a shiny app in which table is both editable and downloadable.
My question is how I can download a datatable after I edit it?
Here is my app code:
library(shiny)
library(DT)
server <- function(input, output) {
df = iris
output$data = DT::renderDataTable ({
DT::datatable(df, editable = list(
target = 'row',
disable = list(columns = c(1, 3, 4))
))
})
output$downloadData <- downloadHandler(
filename = function() {
#paste(input$dataset, ".csv", sep = "")
},
content = function(file) {
write.csv(df, file, row.names = FALSE)
}
)
}
ui <- fluidPage(
DT::dataTableOutput('data'),
downloadButton("downloadData", "Download")
)
shinyApp(ui = ui, server = server)
When you edit a cell of a datatable named "XXX", the info about the cell edit is in input$XXX_cell_edit. This info contains the indices of the edited cell and its new value. So you can do:
library(shiny)
library(DT)
dat <- iris[1:3, ]
ui <- fluidPage(
downloadButton("downloadData", "Download"),
DTOutput("table")
)
server <- function(input, output){
output[["table"]] <- renderDT({
datatable(dat, editable = "cell")
})
df <- reactiveVal(dat)
observeEvent(input[["table_cell_edit"]], {
cell <- input[["table_cell_edit"]]
newdf <- df()
newdf[cell$row, cell$col] <- cell$value
df(newdf)
})
output[["downloadData"]] <- downloadHandler(
filename = function() {
"mydata.csv"
},
content = function(file) {
write.csv(df(), file, row.names = FALSE)
}
)
}
shinyApp(ui, server)
Alternatively, as suggested by #MrGumble, you can use the embedded button of Datatables instead of a downloadHandler. This is more stylish.
library(shiny)
library(DT)
dat <- iris[1:3, ]
ui <- fluidPage(
DTOutput("table")
)
server <- function(input, output){
output[["table"]] <- renderDT({
datatable(dat, editable = "cell", extensions = "Buttons",
options = list(
dom = "Bfrtip",
buttons = list(
"csv"
)
))
})
observeEvent(input[["table_cell_edit"]], {
cellinfo <- input[["table_cell_edit"]]
dat <<- editData(dat, input[["table_cell_edit"]], "table")
})
}
shinyApp(ui, server)
You can add a download button directly to a DT datatable, which offers the user to download the current data in the table, see R Shiny: How to add download buttons in DT::renderDataTable
If you however want to use the edited data for server-side calculations, you are are on the right track, but need to save the edited table into the data.frame using replaceData. See e.g. https://yihui.shinyapps.io/DT-edit/
Related
I am trying to delete the row in the table below but not able to . Can anyone please guide me here.
The row should get deleted when the user selects the row and then clicks on action button
library(shiny)
library(httr)
library(jsonlite)
library(readxl)
library(DT)
library(glue)
ui <- fluidPage({
au <- read_excel("au.xlsx")
au <- as.data.frame(au)
df <- reactiveValues(asd = NULL)
mainPanel(
dataTableOutput("ir"),
actionButton("ac", "ac")
)
})
server <- function(input, output, session) {
output$ir <- renderDataTable({
df$asd <- head(iris)
datatable(df$asd)
})
observeEvent(input$ac,{
# browser()
df$asd <- df$asd[-c(as.numeric(input$ir_rows_selected)),]
})
}
shinyApp(ui, server)
Here is the way using a Shiny button:
library(shiny)
library(DT)
ui <- fluidPage(
actionButton("delete", "Delete selected row"),
br(),
DTOutput("tbl")
)
server <- function(input, output, session){
output[["tbl"]] <- renderDT({
datatable(iris[1:5,],
callback = JS(c(
"$('#delete').on('click', function(){",
" table.rows('.selected').remove().draw();",
"});"
))
)
}, server = FALSE)
}
shinyApp(ui, server)
And here is the way using a button integrated in the DT table:
library(shiny)
library(DT)
ui <- fluidPage(
br(),
DTOutput("tbl")
)
server <- function(input, output, session){
output[["tbl"]] <- renderDT({
datatable(iris[1:5,],
extensions = 'Buttons',
options = list(
dom = 'Bfrtip',
buttons = list(
list(
extend = "collection",
text = "Delete selected row",
action = DT::JS(c(
"function ( e, dt, node, config ) {",
" dt.rows('.selected').remove().draw();",
"}"))
)
)
)
)
}, server = FALSE)
}
shinyApp(ui, server)
With these methods, the table is not re-rendered when the row is deleted.
I have the following data:
> data
products id
1 P1 280386
2 P1 285184
3 P2 293154
4 P1 294245
I have built a simple shiny code. I first filter the table and then I want to download the filtered table. I write the following
library(shiny)
library(shinyWidgets)
library(tidyverse)
library(DT)
data <- read.csv("Desktop/data.csv")
products <- unique(data$products)
ui <- fluidPage(
fluidRow(
column(4,
selectInput("product", "Product", products,
multiple = TRUE),
downloadButton("download", "Download")),
column(8,
tableOutput("errorTable")
)
)
)
server <- function(input, output, session) {
output$errorTable <- renderTable({
subset(data, products == input$product)
}
)
output$download <- downloadHandler(
filename = function() {
paste("data-",Sys.Date(), ".csv", sep = "")
},
content = function(file) {
write.csv(data, file)
}
)
}
shinyApp(ui, server)
However, this code only downloads the full table, not the filtered one. I have searched some question but none explained this case specifically. thanks in advance
Try this
library(shiny)
library(shinyWidgets)
library(tidyverse)
library(DT)
data <- read.csv("Desktop/data.csv")
products <- unique(data$products)
ui <- fluidPage(
fluidRow(
column(4,
selectInput("product", "Product", products,
multiple = TRUE),
downloadButton("download", "Download")),
column(8,
tableOutput("errorTable")
)
)
)
server <- function(input, output, session) {
#you need to create a reactive object with a NULL starting value
listofitems <- reactiveValues(data = NULL )
#observe the changes in input$product and update the reactive object
observeEvent( input$product, {
print("Hello: observeEvent for input$product is triggered")
#debug using browser()
listofitems$data <- subset(data, products == input$product)
showNotification("Products updated",
type = "message",
duration = 4,
closeButton = TRUE)
}, ignoreInit = T,ignoreNULL = TRUE)
output$errorTable <- renderTable({
listofitems$data
}
)
output$download <- downloadHandler(
filename = function() {
paste("data-",Sys.Date(), ".csv", sep = "")
},
content = function(file) {
write.csv(listofitems$data, file)
}
)
}
shinyApp(ui, server)
I'm trying to make an editable and downloadable data table in shiny app. After I edit the table, the data table automatically disappear for some reason. This only happen when the data dat is reactive (which is necessary in my app).
Does anyone knows what is going on? Thanks a lot.
example code below:
library(shiny)
library(DT)
ui <- fluidPage(
selectInput("nrow",
"num of rows",
choices = 1:5,
selected = 3,
multiple = FALSE),
DTOutput("table")
)
server <- function(input, output){
dat = reactive({
iris[1:as.integer(input$nrow),]
})
output[["table"]] <- renderDT({
datatable(dat(), editable = "cell", extensions = "Buttons",
options = list(
dom = "Bfrtip",
buttons = list(
"csv"
)
))
})
observeEvent(input[["table_cell_edit"]], {
cellinfo <- input[["table_cell_edit"]]
dat() <<- editData(dat(), input[["table_cell_edit"]], "table")
})
}
shinyApp(ui, server)
Try this:
library(shiny)
library(DT)
ui <- fluidPage(
selectInput("nrow","num of rows",choices = 1:5,selected = 3,multiple = FALSE),
DTOutput("table")
)
server <- function(input, output){
v <- reactiveValues()
observeEvent(input$nrow,{
v$dat <- iris[1:as.integer(input$nrow),]
})
output[["table"]] <- renderDT({
datatable(v$dat, editable = "cell", extensions = "Buttons", options = list(dom = "Bfrtip",buttons = list("excel")))
})
observeEvent(input[["table_cell_edit"]], {
cellinfo <- input[["table_cell_edit"]]
v$dat <<- editData(v$dat, input[["table_cell_edit"]], "table")
})
}
shinyApp(ui, server)
Is it OK like this ? A possible unwanted behavior is that the table is reset after changing the number of rows. But I don't think we can avoid that... since these are two different tables.
library(shiny)
library(DT)
ui <- fluidPage(
selectInput("nrow",
"num of rows",
choices = 1:5,
selected = 3,
multiple = FALSE),
DTOutput("table")
)
server <- function(input, output){
dat0 <- iris
dat <- reactiveVal()
observe({
dat(dat0[1:as.integer(input$nrow),])
})
output[["table"]] <- renderDT({
datatable(dat(), editable = "cell", extensions = "Buttons",
options = list(
dom = "Bfrtip",
buttons = list(
"csv"
)
))
})
observeEvent(input[["table_cell_edit"]], {
cellinfo <- input[["table_cell_edit"]]
dat(editData(dat(), input[["table_cell_edit"]], "table"))
})
}
shinyApp(ui, server)
I am trying to download a file using downloadHandler with observeEvent shiny but I am not able to download the file,
library(shiny)
load(url("http://s3.amazonaws.com/assets.datacamp.com/production/course_4850/datasets/movies.Rdata"))
ui <- fluidPage(
sidebarLayout(
# Input
sidebarPanel(
# Numeric input for number of rows to show
numericInput(inputId = "n_rows",
label = "How many rows do you want to see?",
value = 10),
# Action button to show
actionButton(inputId = "button",
label = "Show")
),
# Output:
mainPanel(
tableOutput(outputId = "datatable")
)
)
)
server <- function(input, output, session) {
# creating a reactive expression
df <- eventReactive(input$button, {
movies %>% head(input$n_rows)
})
# download a csv everytime when user click on show button
observeEvent(input$button, {
output$button <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".csv", sep="")
},
content = function(file) {
write.csv(df(), file)
}
)
cat("done downloading file \n")
})
# displays the data on the web in tabular format, data comes from reactive event
output$datatable <- renderTable({
df()
})
}
# Create a Shiny app object
shinyApp(ui = ui, server = server)
I was able to execute above code without any errors, but csv file is not downloading, i want to display the data table and download the displayed data on same button click event , how can i achieve this, Am I missing something, any help would be appreciated
Try this:
library(shiny)
library(dplyr)
load(url("http://s3.amazonaws.com/assets.datacamp.com/production/course_4850/datasets/movies.Rdata"))
ui <- fluidPage(
sidebarLayout(
# Input
sidebarPanel(
# Numeric input for number of rows to show
numericInput(inputId = "n_rows",
label = "How many rows do you want to see?",
value = 10),
# Action button to show
downloadButton('downloadData', 'Download data')
),
# Output:
mainPanel(
tableOutput(outputId = "datatable")
)
)
)
server <- function(input, output, session) {
# Reactive value for selected dataset ----
df <- reactive({
movies %>% head(input$n_rows)
})
output$datatable <- renderTable({
df()
})
output$downloadData <- downloadHandler(
filename = function() {
paste("dataset-", ".csv", sep = "")
},
content = function(file) {
write.csv(df(), file, row.names = FALSE)
})
}
# Create a Shiny app object
shinyApp(ui = ui, server = server)
I have written an app allowing users to provide some inputs. The app will call a function to do some calculations and generate an output in table format.
I would like to add a button that allows users to download both the inputs and outputs into an Excel spreadsheet (with two tabs)
Below is a simplified version of the code where I want to download the inputs and the example table. I have tried the following code but failed:
library(shiny)
library(openxlsx)
somefunction <- function() {
data.frame(text = c("sample1","sample2"))}
server <- function(input, output, session) {
dataReactive <- reactive({
data.frame(text = c(input$text1, input$text2, input$text3))
})
observeEvent(input$goButton,{
output$exampleTable <- DT::renderDataTable({somefunction()})
})
output$downloadExcelSheet <- downloadHandler(
filename = function() {
paste("result",Sys.Date(), ".xlsx",sep="")
},
content = function(file) {
write.xlsx(list(dataReactive(),exampleTable), file)
})
}
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
textInput("text1","Text 1:",value="Input 1"),
textInput("text2","Text 2:",value="Input 2"),
actionButton("goButton", "Calculate"),
downloadButton("downloadExcelSheet", "Download Data")
),
mainPanel(
DT::dataTableOutput("exampleTable")
)
)
)
shinyApp(ui = ui, server = server)
server <- function(input, output, session) {
dataReactive <- reactive({
data.frame(text = c(input$text1, input$text2, input$text3))
})
data <- reactiveValues()
observeEvent(input$goButton,{
output$exampleTable <- DT::renderDataTable({
data$df <- somefunction()
})
})
output$downloadExcelSheet <- downloadHandler(
filename = function() {
paste("result",Sys.Date(), ".xlsx",sep="")
},
content = function(file) {
write.xlsx(list(dataReactive(),data$df), file)
})
}
It's better to move data$df <- somefunction() to observeEvent and move DT::renderDataTable outside observeEvent like so
observeEvent(input$goButton,{
data$df <- somefunction()
})
output$exampleTable <- DT::renderDataTable({data$df})
Use reactiveValues as an intermediate state to save variables and in order to reuse them later.