R shiny build links between tabs with DT package - r

Solution for creating links between tabs a have found here R shiny build links between tabs is really nice, but it's not working with DT package (for me..).
Can anybody tell me, what am I doing wrong in my example code using DT library in compare to the solution without DT package?
library(shiny)
library(DT)
server <- function(input, output) {
output$iris_type <- DT::renderDataTable({
datatable(data.frame(Species=paste0("<a href='#filtered_data'>", unique(iris$Species), "</a>")),
escape = FALSE,
options = list(initComplete = JS(
'function(table) {
table.on("click.dt", "tr", function() {
Shiny.onInputChange("rows", table.row( this ).index());
tabs = $(".tabbable .nav.nav-tabs li a");
$(tabs[1]).click();
});
}')))
})
output$filtered_data <- DT::renderDataTable({
if(is.null(input$rows)){
iris
}else{
iris[iris$Species %in% unique(iris$Species)[as.integer(input$rows)+1], ]
}
})
}
ui <- shinyUI(fluidPage(
mainPanel(
tabsetPanel(
tabPanel("Iris Type", DT::dataTableOutput("iris_type")),
tabPanel("Filtered Data", DT::dataTableOutput("filtered_data"))
)
)
))
shinyApp(ui = ui, server = server)

You could try the code below. I changed the function switching the tabs to the callback (which has table as an argument) and in your output$filtered_data, replaced iris by datable(iris) since you are rendering with DT::renderDataTable
library(shiny)
library(DT)
server <- function(input, output) {
output$iris_type <- DT::renderDataTable({
datatable(data.frame(Species=paste0("<a href='#filtered_data'>", unique(iris$Species), "</a>")),
escape = FALSE,
callback = JS(
'table.on("click.dt", "tr", function() {
tabs = $(".tabbable .nav.nav-tabs li a");
$(tabs[1]).click();})'))
})
output$filtered_data <- DT::renderDataTable({
selected <- input$iris_type_rows_selected
if(is.null(selected)){
datatable(iris)
} else {
datatable(iris[iris$Species %in% unique(iris$Species)[selected], ])
}
})
}
ui <- shinyUI(fluidPage(
mainPanel(
tabsetPanel(
tabPanel("Iris Type", DT::dataTableOutput("iris_type")),
tabPanel("Filtered Data", DT::dataTableOutput("filtered_data"))
)
)
))
shinyApp(ui = ui, server = server)
Please note this requires DT >= 0.0.62.

In the end I used a little hack with onclick event on . Which way do you think is more clear? (NicE's or this one?)
library(shiny)
library(DT)
server <- function(input, output) {
output$iris_type <- DT::renderDataTable({
datatable(data.frame(Species=paste0("<a href='#filtered_data'",
"alt='",unique(iris$Species),"'",
"onclick=\"",
"tabs = $('.tabbable .nav.nav-tabs li');",
"tabs.each(function() {",
"$(this).removeClass('active')",
"});",
"$(tabs[1]).addClass('active');",
"tabsContents = $('.tabbable .tab-content .tab-pane');",
"tabsContents.each(function() {",
"$(this).removeClass('active')",
"});",
"$(tabsContents[1]).addClass('active');",
"$('#filtered_data').trigger('change').trigger('shown');",
"Shiny.onInputChange('species', getAttribute('alt'));",
"\">",
unique(iris$Species),
"</a>")),
escape = FALSE)
})
output$filtered_data <- DT::renderDataTable({
if(is.null(input$species)){
datatable(iris)
}else{
datatable(iris[iris$Species %in% input$species, ])
}
})
}
ui <- shinyUI(fluidPage(
mainPanel(
tabsetPanel(
tabPanel("Iris Type", DT::dataTableOutput("iris_type")),
tabPanel("Filtered Data", DT::dataTableOutput("filtered_data"))
)
)
))
shinyApp(ui = ui, server = server)

Related

Delete the row in DT table shiny

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.

How to solve encoding issues in a shiny app

Any tips to solve encoding problem. I am not able to generate the up (↑) and down (↓) arrows in the code below. When running, the following warning message appears:
Warning messages:
1: unable to translate 'Maximize <U+2191>' to native encoding
2: unable to translate 'Minimize <U+2193>' to native encoding
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fluidRow(
column(
width = 6,
selectInput("maxmin", label = h5("Maximize or Minimize"),
choices = list("Maximize \u2191" = 1, "Minimize \u2193" = 2), selected = "")
)
)),
mainPanel(
))
)
server <- function(input, output, session) {
}
shinyApp(ui = ui, server = server)
You can use HTML code for the arrows and proceed like this:
library(shiny)
choicesNames <- list("Minimize", "Maximize")
choicesHTML <- list("Minimize ↓", "Maximize ↑")
choices <- setNames(choicesNames, choicesHTML)
ui <- fluidPage(
selectizeInput("select", label = "Select", choices = NULL),
textOutput("txt")
)
server <- function(input, output, session) {
updateSelectizeInput(
session, "select",
choices = choices,
options = list(render = I("
{
item: function(item, escape) { return '<div>' + item.label + '</div>'; },
option: function(item, escape) { return '<div>' + item.label + '</div>'; }
}
"))
)
output$txt <- renderText({
paste("You chose", input$select)
})
}
shinyApp(ui, server)
Another option is to use my package shinySelect and fontawesome icons for the arrows.
library(shiny)
library(shinySelect)
library(bslib)
library(fontawesome)
choices <- HTMLchoices(
labels = list(
tags$span("Minimize", fa_i("arrow-alt-circle-down")),
tags$span("Maximize", fa_i("arrow-alt-circle-up"))
),
values = list("minimize", "maximize")
)
styles <- list(
borderBottom = "5px solid orange",
color = list(selected = "lime", otherwise = "pink"),
backgroundColor = list(selected = "cyan", otherwise = "seashell")
)
ui <- fluidPage(
theme = bs_theme(version = 4),
titlePanel("shinySelect example"),
selectControlInput(
"inputid",
label = tags$h1("Make a choice", style = "color: red;"),
optionsStyles = styles,
choices = choices,
selected = "minimize",
multiple = FALSE,
animated = TRUE
),
br(),
verbatimTextOutput("textOutput")
)
server <- function(input, output, session) {
output$textOutput <- renderPrint({
sprintf("You selected: %s", input$inputid)
})
}
shinyApp(ui, server)
This is an alternate solution. Solutions provided by #Stephane Laurent are great. To translate unicode points to UTF-8, you can use chr_unserialise_unicode() from rlang package. Try this
library(shiny)
library(rlang)
ll <- chr_unserialise_unicode("<U+2193>")
uu <- chr_unserialise_unicode("<U+2191>")
choicesNames <- list(1,2)
choiceValues <- list(sprintf("Minimize %s",ll),sprintf("Maximize %s",uu))
choices <- setNames(choicesNames, choiceValues)
ui <- fluidPage(
selectInput("maxmin", label = h5("Maximize or Minimize"), choices = NULL),
textOutput("mytxt")
)
server <- function(input, output, session) {
updateSelectInput(session, "maxmin", choices = choices )
output$mytxt <- renderText({
paste("You chose", input$maxmin)
})
}
shinyApp(ui = ui, server = server)

Show a tabPanel in popup window or modalDialog

I need some help I want to show my reactive tabPanel in a popup with the shinyBS package.
Everything seems to work well except the creation of popup.
I am inspired by :
1) R Shiny - add tabPanel to tabsetPanel dynamically (with the use of renderUI)
2)Show dataTableOutput in modal in shiny app
My code :
library(shiny)
library(DT) # need datatables package
library(shinyBS)
ui <- shinyUI(fluidPage(
titlePanel("Example"),
sidebarLayout(
sidebarPanel(
selectInput("decision", label = "Choose your specie",
choices = iris$Species,
selected = "mtcars", multiple = TRUE)
),
mainPanel(
uiOutput('mytabs')
)
)
))
server <- shinyServer(function(input, output, session) {
output$mytabs <- renderUI({
nTabs = length(input$decision)
# create tabPanel with datatable in it
myTabs = lapply(seq_len(nTabs), function(i) {
tabPanel(paste0("dataset_", input$decision[i]),
tableOutput(paste0("datatable_",i))
)
})
do.call(tabsetPanel, myTabs)
})
# create datatables in popup ?
bsModal(
id = "modalExample",
"yb",
observe(
lapply(seq_len(length(input$decision)), function(i) {
output[[paste0("datatable_",i)]] <- renderTable({
as.data.frame(iris[iris$Species == input$decision[i], ])
})
})
)
)
})
shinyApp(ui, server)
Thanks in advance for any help !
bsModal is an UI element, so you need to put it into you UI. Within this modal you want to show the tabPanels (rendered via uiOutput), so all you need to do is to place your bsModal into the UI, and within this bsModal you have your uiOutput. All what is left is to add an actionButton which shows the modal.
library(shiny)
library(shinyBS)
ui <- shinyUI(fluidPage(
titlePanel("Example"),
sidebarLayout(
sidebarPanel(
selectInput("decision", label = "Choose your species",
choices = unique(iris$Species),
selected = unique(iris$Species), multiple = TRUE),
actionButton("show", "Show")
),
mainPanel(
bsModal("modalExample",
"myTitle",
"show",
uiOutput('mytabs')
)
)
)
))
server <- shinyServer(function(input, output, session) {
output$mytabs <- renderUI({
nTabs <- length(input$decision)
# create tabPanel with datatable in it
myTabs <- lapply(seq_len(nTabs), function(i) {
tabPanel(paste0("dataset_", input$decision[i]),
tableOutput(paste0("datatable_",i))
)
})
do.call(tabsetPanel, myTabs)
})
# create datatables in popup ?
observe(
lapply(seq_len(length(input$decision)), function(i) {
output[[paste0("datatable_",i)]] <- renderTable({
as.data.frame(iris[iris$Species == input$decision[i], ])
})
})
)
})
shinyApp(ui, server)
It's not clear to me what you want to do (maybe #thothal has the right answer). What about this app ?
library(shiny)
library(DT) # need datatables package
library(shinyBS)
ui <- shinyUI(fluidPage(
titlePanel("Example"),
sidebarLayout(
sidebarPanel(
selectInput("decision", label = "Choose your specie",
choices = iris$Species,
selected = "mtcars", multiple = TRUE),
actionButton("trigger_modal", "View modal")
),
mainPanel(
uiOutput("modal")
# uiOutput('mytabs')
)
)
))
server <- shinyServer(function(input, output, session) {
# output$mytabs <- renderUI({
# nTabs = length(input$decision)
# # create tabPanel with datatable in it
# myTabs = lapply(seq_len(nTabs), function(i) {
# tabPanel(paste0("dataset_", input$decision[i]),
# tableOutput(paste0("datatable_",i))
# )
# })
#
# do.call(tabsetPanel, myTabs)
# })
# create datatables in popup ?
observe(
lapply(seq_len(length(input$decision)), function(i) {
output[[paste0("datatable_",i)]] <- renderTable({
as.data.frame(iris[iris$Species == input$decision[i], ])
})
})
)
output$modal <- renderUI({
bsModal(
id = "modalExample",
"yb",
trigger = "trigger_modal",
do.call(tagList, lapply(seq_along(input$decision), function(i){
tableOutput(paste0("datatable_",i))
}))
)
})
})
shinyApp(ui, server)

Output more than 1 datatables in shiny main panel

I have a shiny app that a user can check whether they want the data table displayed in the main panel. Depending on the numericinput, if they select 1, only 1 datatable be displayed or if they select 2 it will display 2 datatables I am not so sure how to code this in shiny R since I am new to this. Thank you for looking into this.
Here is my code
library("shiny")
df1 <- data.frame("2010-01"=double(),
"2010-02"=double(),
"2010-03"=double(),
"2010-04"=double()
)
df1<-rbind(df1,setNames(as.list(c(10,20,30,40)), names(df2)))
df2 <- data.frame("2010-01"=double(),
"2010-02"=double(),
"2010-03"=double(),
"2010-04"=double()
)
df2<-rbind(df2,setNames(as.list(c(100,200,300,400)), names(df2)))
df3 <- data.frame("2010-01"=double(),
"2010-02"=double(),
"2010-03"=double(),
"2010-04"=double()
)
df3<-rbind(df3,setNames(as.list(c(1000,2000,3000,4000)), names(df2)))
ui <-fluidPage(
sidebarPanel(
checkboxInput("add_data", "Add Data Table(s)"),
conditionalPanel(condition="input.add_data === true",
numericInput("numofdata",
label="Number of Data Table(s):",
min = 1,
max = 3,
value = 1,
step = 1),
uiOutput("num_of_data"),
textOutput("see_ranges")
),
actionButton("submit", "Submit")
),
mainPanel(
titlePanel("Output Data Table"),
DT::dataTableOutput("datatable.view", width = "95%")
) # end of main panel
)
server <- function(input, output, session) {
output$num_of_data <- renderUI({
lapply(1:input$numofdata, function(i) {
print(trend_list())
})
})
output$see_ranges <- renderPrint({
print(trend_list())
})
data.filter <- reactive({
df(i)
})
output$datatable.view <- DT::renderDataTable(
{
input$submit
if (input$submit==0) return()
isolate({
for(i in 1:input$numoftrends) {
datatable(data.filter(i),
rownames=FALSE,
extensions = c("FixedColumns", "FixedHeader", "Scroller"),
options = list(searching=FALSE,
autoWidth=TRUE,
rownames=FALSE,
scroller=TRUE,
scrollX=TRUE,
pagelength=1,
fixedHeader=TRUE,
class='cell-border stripe',
fixedColumns =
list(leftColumns=2,heightMatch='none')
)
)
}
})
})
}
shinyApp(ui = ui, server = server)
You should look at this article:
http://shiny.rstudio.com/gallery/creating-a-ui-from-a-loop.html
You will seen then that one has to create multiple renderDataTable instead of muliple datatable within one renderDataTable().
Also in your code you call df like a function df() but it is only defined as a variable.
See a generic running example below.
EDIT: Changed dynamic part of UI.
library(DT)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
selectInput("amountTable", "Amount Tables", 1:10, 3)
),
mainPanel(
# UI output
uiOutput("dt")
)
)
)
server <- function(input, output, session) {
observe({
lapply(1:input$amountTable, function(amtTable) {
output[[paste0('T', amtTable)]] <- DT::renderDataTable({
iris[1:amtTable, ]
})
})
})
output$dt <- renderUI({
tagList(lapply(1:input$amountTable, function(i) {
dataTableOutput(paste0('T', i))
}))
})
}
shinyApp(ui, server)

Use selection from gvisTable in shiny

Quick question: How is it possible to use/get the selection of a gvisTable in shiny?
I can achieve this with the DT package like this:
library(DT)
library(shiny)
server <- function(input, output) {
output$dt <- renderDataTable({
datatable(cbind(c(1,2,3,4,5),c(5,4,3,2,1)))
})
output$dtselect <- renderText({
input$dt_rows_selected
})
}
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
"Selected Rows from Datatable in Text Output"
),
mainPanel(dataTableOutput("dt"),
textOutput("dtselect"))
)
)
shinyApp(ui = ui, server = server)
Is it possible to get the same selection with gvis? I googled a lot but could not find somebody reproducing the same in shiny.
You can add a listenerto the options and bind it to a variable called text as I did
rm(list = ls())
library(shiny)
library(googleVis)
mydata <- as.data.frame(cbind(c(1,2,3,4,5),c(5,4,3,2,1)))
server <- function(input, output) {
output$myTable <- renderGvis({
gvisTable(mydata, chartid = "mydata",
options = list(gvis.listener.jscode = "var text = data.getValue(chart.getSelection()[0].row,0);Shiny.onInputChange('text', text.toString());"))})
output$dtselect <- renderText({input$text})
}
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
"Selected Rows from Datatable in Text Output"
),
mainPanel(htmlOutput("myTable"),textOutput("dtselect"))
)
)
shinyApp(ui = ui, server = server)
Variant to handle multiple selection (as told here )
library(googleVis)
library(shiny)
mydata <- as.data.frame(cbind(c(1,2,3,4,5),c(5,4,3,2,1)))
shinyApp(
ui = fluidPage(
htmlOutput("myTable")
)
,
server = function(input,output){
observe({
print(input$r_select)
})
output$myTable <- renderGvis({
gt= gvisTable(mydata,chartid="mydata")
jsInsert ="
google.visualization.events.addListener(chart, 'select', selectHandler);
var selectedRows = new Array();
function selectHandler() {
var selection = chart.getSelection();
for (var idx in selection){
var item = selection[idx];
if (item) {
i = selectedRows.indexOf(item.row);
if (i == -1){
selectedRows.push(item.row);
data.setProperty(item.row, 0,'style','background-color:#d6e9f8;');
data.setProperty(item.row, 1,'style','background-color:#d6e9f8;');
} else {
selectedRows.splice(i,1);
data.setProperty(item.row,0,'style',null);
data.setProperty(item.row,1,'style',null);
}
}
}
chart.setSelection(null);
Shiny.onInputChange('r_select',selectedRows);
chart.draw(data,options);
}
chart.draw(data,options);
"
gt$html$chart[['jsDrawChart']] <- gsub("chart.draw\\(data,options\\);", jsInsert, gt$html$chart[['jsDrawChart']])
gt
})
}
)
Print values of selected rows in observe.
Indexing start from 0

Resources