I want to include sparklines in a shiny DT. It works fine in the RStudio viewer but in Shiny the sparklines are not rendered. Here is a minimal example.
# dependencies
require(sparkline)
require(DT)
require(shiny)
# create data with sparklines
spark_data <- data.frame(
id = c('spark1', 'spark2'),
spark = c(
spk_chr(values = 1:3, elementId = 'spark1'),
spk_chr(values = 3:1, elementId = 'spark2')
)
)
# render in RStudio viewer (this works)
tbl <- datatable(spark_data, escape = FALSE)
spk_add_deps(tbl)
# render in Shiny (no sparklines rendered in DT)
ui <- fluidPage(
sparklineOutput("test_spark"),
dataTableOutput("tbl")
)
server <- function(input, output) {
# sparkline outside DT (works fine) - also ensures sparkline dependencies are attached
output$test_spark <- renderSparkline(sparkline(1:3))
# sparkline inside DT (does not render)
output$tbl <- renderDataTable(
expr = spark_data,
escape = FALSE
)
}
shinyApp(ui = ui, server = server)
I have modified your code to generate sparklines. I refered to this link to generate the sparklines.
require(sparkline)
require(DT)
require(shiny)
# create data
spark_data1<- data.frame(id = c('spark1', 'spark2'),
spark = c("1,2,3", "3,2,1"))
ui <- fluidPage(
sparklineOutput("test_spark"),
DT::dataTableOutput("tbl")
)
server <- function(input, output) {
line_string <- "type: 'line', lineColor: 'black', fillColor: '#ccc', highlightLineColor: 'orange', highlightSpotColor: 'orange'"
cd <- list(list(targets = 1, render = JS("function(data, type, full){ return '<span class=sparkSamples>' + data + '</span>' }")))
cb = JS(paste0("function (oSettings, json) {\n $('.sparkSamples:not(:has(canvas))').sparkline('html', { ",
line_string, " });\n}"), collapse = "")
output$tbl <- DT::renderDataTable({
dt <- DT::datatable(as.data.frame(spark_data1), rownames = FALSE, options = list(columnDefs = cd,fnDrawCallback = cb))
})
}
shinyApp(ui = ui, server = server)
Hope it helps!
Old-ish question, I know, but based on info in the question Add label to sparkline plot in datatable I think the solution is what you tried originally plus just a few lines. Here I trimmed out the parts demo-ing it works in the viewer and added just what is needed to make the sparklines work.
# dependencies
require(sparkline)
require(DT)
require(shiny)
# create data with sparklines
spark_data <- data.frame(
id = c('spark1', 'spark2'),
spark = c(
spk_chr(values = 1:3, elementId = 'spark1'),
spk_chr(values = 3:1, elementId = 'spark2')
)
)
### adding this <------------
cb <- htmlwidgets::JS('function(){debugger;HTMLWidgets.staticRender();}')
ui <- fluidPage(
### and this <------------
htmlwidgets::getDependency('sparkline'),
dataTableOutput("tbl")
)
server <- function(input, output) {
output$tbl <- renderDataTable(
expr = spark_data,
escape = FALSE,
### and this <------------
options = list(
drawCallback = cb
)
)
}
shinyApp(ui = ui, server = server)
Related
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)
I would like to update a table which is edited in Shiny App. I can't figure out why in below code mean() works fine within observeEvent() but fails to update itself in output$tekst.
library(shiny)
library(DT)
ui <- fluidPage(
textOutput('tekst'),
DTOutput('tabela')
)
server <- function(input, output) {
A <- data.frame("a" = c(1,2,6,5,NA,1), "b" = c(2,2,NA,5,7,NA))
output$tabela = renderDT(A
, selection = 'none'
, editable = 'column')
observeEvent(input$tabela_cell_edit, {
A <<- editData(A, input$tabela_cell_edit, 'tabela')
cat(mean(A$a, na.rm = TRUE), "\n\n")
})
output$tekst <- renderText({mean(A$a, na.rm = TRUE)})
}
shinyApp(ui = ui, server = server)
Help :)
Use a reactive value:
library(shiny)
library(DT)
ui <- fluidPage(
textOutput('tekst'),
DTOutput('tabela')
)
server <- function(input, output) {
A <- data.frame("a" = c(1,2,6,5,NA,1), "b" = c(2,2,NA,5,7,NA))
reactA <- reactiveVal(A)
output$tabela = renderDT(A
, selection = 'none'
, editable = 'column')
observeEvent(input$tabela_cell_edit, {
reactA(editData(reactA(), input$tabela_cell_edit, 'tabela'))
})
output$tekst <- renderText({mean(reactA()$a, na.rm = TRUE)})
}
shinyApp(ui = ui, server = server)
I'm trying to create unit tests for a shiny app I've been working on but can't work out how to input values for an editable DT table.
Example app:
library(shiny)
library(DT)
ui <- fluidPage(
DTOutput("table"),
textOutput("mean")
)
server <- function(input, output) {
tableUpdate <- reactiveVal(0)
table <- data.frame(A = 1:5, B = 6:10, C = 11:15)
output$table <- renderDT({table},
options = list(paging = FALSE, dom = 't'),
selection = 'none',
server = FALSE,
editable = list(target = 'row')
)
observeEvent(input$table_cell_edit, {
table <<- editData(table, input$table_cell_edit)
tableUpdate(tableUpdate() + 1)
})
output$mean <- renderText({
tableUpdate()
paste(mean(table$A), mean(table$B), mean(table$C))
})
}
shinyApp(ui, server)
Example test:
library(shinytest)
app <- ShinyDriver$new(".")
app$setInputs(table_cell_clicked = list(row = 2, col = 2, value = 7), allowInputNoBinding_ = TRUE)
app$setInputs(table_cell_edit = data.frame(row = 2, col = 0:3, value = "1"),
allowInputNoBinding_ = TRUE, priority_ = "event", wait_ = FALSE, values_ = FALSE)
app$takeScreenshot()
app$stop()
rm(app)
I've kept this mostly how it came out when I recorded the test, but I've corrected the setInputs values of table_cell_edit and table_cell_clicked (which came out as vectors).
This gives the error:
Error in sd_getAllValues(self, private, input, output, export) :
Unable to fetch all values from server. Is target app running with options(shiny.testmode=TRUE?)
Running in test mode does not fix the issue.
While experiencing the same issue, I managed to fix yours.
the mistake was here (when you are trying to update the reactive value):
tableUpdate(tableUpdate() + 1)
instead of ....
tableUpdate(table)
Please find the updated entire code below.
library(shiny)
library(DT)
ui <- fluidPage(
DTOutput("tabled"),
textOutput("mean")
)
server <- function(input, output) {
tableUpdate <- reactiveVal(NULL)
table <- data.frame(A = 1:5, B = 6:10, C = 11:15)
output$tabled <- renderDT({table},
options = list(paging = FALSE, dom = 't'),
selection = 'none',
server = TRUE,
editable = 'row')
observeEvent(input$tabled_cell_edit, {
table<<- editData(table, input$tabled_cell_edit,'tabled')
tableUpdate(table)
a<-mean(table$A)
b<-mean(table$B)
c<-mean(table$C)
output$mean <- renderText(paste(a,b,c))
})
}
shinyApp(ui, server)
I have the following program. As the title suggests, every time I edit an item on pages after the first page the table goes back to the first page. I'd like the table to stay on the page I'm editing without jumping back to the first page.
I've seen this problem on other threads here but their solutions don't seem to work with current version of DT and shiny packages.
library(shiny)
library(DT)
shinyApp(
ui = fluidPage(
DTOutput('x1'),
verbatimTextOutput("print")
),
server = function(input, output, session) {
x = reactiveValues(df = NULL)
observe({
df <- iris
df$Date = Sys.time() + seq_len(nrow(df))
x$df <- df
})
output$x1 = renderDT(x$df, selection = 'none', editable = TRUE)
proxy = dataTableProxy('x1')
observeEvent(input$x1_cell_edit, {
info = input$x1_cell_edit
str(info)
i = info$row
j = info$col
v = info$value
x$df[i, j] <- isolate(DT::coerceValue(v, x$df[i, j]))
})
output$print <- renderPrint({
x$df
})
}
)
Any help would be appreciated
You can do like this:
library(shiny)
library(DT)
shinyApp(
ui = fluidPage(
DTOutput('x1'),
verbatimTextOutput("print")
),
server = function(input, output, session) {
dat <- reactiveVal(cbind(iris, Date = Sys.time() + seq_len(nrow(iris))))
output$x1 = renderDT(isolate(dat()), selection = 'none', editable = TRUE)
proxy = dataTableProxy('x1')
observeEvent(input$x1_cell_edit, {
info = input$x1_cell_edit
dat(editData(dat(), info, proxy, resetPaging = FALSE))
})
output$print <- renderPrint({
dat()
})
}
)
Please see DT-edit. I have copied the 2 relevant examples below:
library(shiny)
library(DT)
dt_output = function(title, id) {
fluidRow(column(
12, h1(paste0('Table ', sub('.*?([0-9]+)$', '\\1', id), ': ', title)),
hr(), DTOutput(id)
))
}
render_dt = function(data, editable = 'cell', server = TRUE, ...) {
renderDT(data, selection = 'none', server = server, editable = editable, ...)
}
shinyApp(
ui = fluidPage(
title = 'Double-click to edit table cells',
dt_output('client-side processing (editable = "cell")', 'x1'),
dt_output('server-side processing (editable = "cell")', 'x5')
),
server = function(input, output, session) {
d1 = iris
d1$Date = Sys.time() + seq_len(nrow(d1))
d5 = d1
options(DT.options = list(pageLength = 5))
# client-side processing
output$x1 = render_dt(d1, 'cell', FALSE)
observe(str(input$x1_cell_edit))
# server-side processing
output$x5 = render_dt(d5, 'cell')
# edit a single cell
proxy5 = dataTableProxy('x5')
observeEvent(input$x5_cell_edit, {
info = input$x5_cell_edit
str(info) # check what info looks like (a data frame of 3 columns)
d5 <<- editData(d5, info)
replaceData(proxy5, d5, resetPaging = FALSE) # important
# the above steps can be merged into a single editData() call; see examples below
})
}
)
I am not sure why you seem to be unnecessarily complicating the process with your reactiveValues but that is probably the cause of your table needing to refresh back to the first page.
I am developing a shiny app where user can select multiple columns in a big dataset to create a subset of this dataset. I use the package DT to render the table nicely in the shiny app.
I previously used version 0.2 of DT package where the following code was working :
library("DT")
library("shiny")
ui <- fluidPage(
DT::dataTableOutput('table1'),
DT::dataTableOutput("table2")
)
server <- function(input, output) {
output$table1 <- DT::renderDataTable({
datatable(mtcars, extensions = 'Select', selection = 'none', options = list(ordering = FALSE, searching = FALSE, pageLength = 25, select = list(style = 'os', items = 'column')),
callback = JS(
"table.on( 'click.dt', 'tbody td', function (e) {",
"var type = table.select.items();",
"var idx = table[type + 's']({selected: true}).indexes().toArray();",
"var DT_id = table.table().container().parentNode.id;",
"Shiny.onInputChange(DT_id + '_columns_selected', idx);",
"})"
))
})
output$table2 <- DT::renderDataTable({
subset_table <- mtcars[,input$table1_columns_selected]
datatable(subset_table)
})
}
shinyApp(ui = ui, server = server)
Unfortunately, this code is not working anymore (I am now under version 0.4). The input$table1_columns_selected does not render the indices of the selected columns.
According to this https://rstudio.github.io/DT/shiny.html there is now a functionnality to select multiples rows, but I can't figure out how to do the same with columns.
Any idea ?
Thank you very much for your help !
I am not sure why you need to use the callback argument to do this. Here's a simplified approach -
library("DT")
library("shiny")
ui <- fluidPage(
DT::dataTableOutput('table1'),
DT::dataTableOutput("table2")
)
server <- function(input, output) {
output$table1 <- DT::renderDataTable({
datatable(mtcars, extensions = 'Select', selection = list(target = "column"), options = list(ordering = FALSE, searching = FALSE, pageLength = 25))
})
output$table2 <- DT::renderDataTable({
subset_table <- mtcars[, input$table1_columns_selected, drop = F]
datatable(subset_table)
})
}
shinyApp(ui = ui, server = server)
Note the change in the datatable arguments in output$table1. Hope this is what you were looking for.
I have tested your code and its working fine for me (see picture below) and i am also using DT package version 0.4.
So my guess is that, its not DT package problem but something else in your global configuration that is causing the issue.