Update table in R Shiny - r

I am just learning R. I have a small project where a timetable is displayed and the user has the possibility to enter a subject.
My problem: I do not know how to enter a subject (for example "math") in the timetable (dataframe). As soon as the user presses the action button, the subject should be entered in the table at the position ["1", "monday"].
I tried it here by:
output$my_table <- renderDataTable(df())
df <- eventReactive(input$button, {
timetable["1", "monday"] <- input$select1
})
which unfortunately does not work. Any tips and advice on how I can enter something into a table would be greatly appreciated!
This is my Code:
library(shiny)
ui <- fluidPage(
theme = bs_theme(version = 4, bootswatch = "minty"),
titlePanel(h1("My timetable", align = "center" )),
sidebarLayout(
position = c("left"),
sidebarPanel(
width = 4,
selectInput("select1", label = h5("Event:"),
choices = c("math" , "sience", "sport") ,
selected = 1,
width = 400),
actionButton("action", label = "Add")),
mainPanel(
width = 8,
tableOutput('my_table')),
),
)
and the server:
server <- function(input, output, session) {
output$my_table = renderTable({timetable<- data.frame(monday <- c("","","","",""),
tuesday <- c("","","","",""),
wednesday <- c("","","","",""),
thursday <- c("","","","",""),
friday <- c("","","","",""))},
bordered = TRUE,
spacing = c('l'),
width = "100%",
striped = TRUE,
align = 'c',
rownames = TRUE)
output$timetable <- renderDataTable(df())
df <- eventReactive(input$action, { timetable["1","monday"] <- input$select1 })
}
shinyApp(ui, server)

Here is a complete working example that may be helpful.
First, I might define a separate reactiveVal to store your data.frame. This will be accessible in both your table output as well as either observeEvent or eventReactive methods.
When you reference your reactiveVal, use timetable() with parentheses at the end. When you want to replace the data.frame stored in timetable, you can do timetable(new_data_frame_here). In the observeEvent, I created a temporary tmp data.frame that can be used to edit further for convenience.
library(shiny)
library(bslib)
ui <- fluidPage(
theme = bs_theme(version = 4, bootswatch = "minty"),
titlePanel(h1("My timetable", align = "center" )),
sidebarLayout(
position = c("left"),
sidebarPanel(
width = 4,
selectInput("select1", label = h5("Event:"),
choices = c("math" , "sience", "sport") ,
selected = 1,
width = 400),
actionButton("action", label = "Add")),
mainPanel(
width = 8,
tableOutput('my_table')
)
)
)
server <- function(input, output, session) {
timetable <- reactiveVal(
data.frame(monday = c("","","","",""),
tuesday = c("","","","",""),
wednesday = c("","","","",""),
thursday = c("","","","",""),
friday = c("","","","",""))
)
output$my_table = renderTable(timetable(),
bordered = TRUE,
spacing = c('l'),
width = "100%",
striped = TRUE,
align = 'c',
rownames = TRUE)
observeEvent(input$action, {
tmp <- timetable()
tmp[1, "monday"] <- input$select1
timetable(tmp)
})
}
shinyApp(ui, server)

Related

R Shiny click on table field

I am currently learning R. I have a small project where a timetable is displayed and the user has the option to enter a subject.
After adding the subject to the timetable, it should be possible to click on it to open the modalDialog.
Unfortunately my code does not work. I have tried it here:
observeEvent(input$mytable_cells_selected, {
showModal(modalDialog(
title = "Somewhat important message",
"This is a somewhat important message.",
easyClose = TRUE,
footer = NULL))
})
Can someone help me and tell where my error is?
ui <- fluidPage(
theme = bs_theme(version = 4, bootswatch = "minty"),
titlePanel(h1("My timetable", align = "center" )),
sidebarLayout(
position = c("left"),
sidebarPanel(
width = 4,
selectInput("select1", label = h5("Event:"),
choices = c("math" , "sience", "sport") ,
selected = 1,
width = 400),
actionButton("action", label = "Add")),
mainPanel(
width = 8,
tableOutput('mytable')),
),
)
and server:
server <- function(input, output, session) {
timetable <- reactiveVal(
data.frame(monday = c("","","","",""),
tuesday = c("","","","",""),
wednesday = c("","","","",""),
thursday = c("","","","",""),
friday = c("","","","",""))
)
output$mytable <- renderTable(timetable(),
bordered = TRUE,
spacing = c('l'),
width = "100%",
striped = TRUE,
align = 'c',
rownames = TRUE,
selection = list(target = 'cell'))
observeEvent(input$action, {
tmp <- timetable()
tmp[1, "monday"] <- input$select1
timetable(tmp)
})
observeEvent(input$mytable_cells_selected, {
showModal(modalDialog(
title = "message",
"This is a somewhat important message.",
easyClose = TRUE,
footer = NULL))
})
}
shinyApp(ui, server)
As mentioned in the comment, you can use the DT library. Here is a complete example.
Use dataTableOutput in your ui for your data table.
In server, you can include renderDataTable and customize here. In this case, selection is set for single cells.
You can capture the selection event (or can capture clicked event) with input$my_table_cells_selected. In my version I used an underscore for my_table. This information will include the row and column values of the cell selected.
Note that the DT data table could be editable and allow for other interactivity, depending on your needs.
library(shiny)
library(bslib)
library(DT)
ui <- fluidPage(
theme = bs_theme(version = 4, bootswatch = "minty"),
titlePanel(h1("My timetable", align = "center" )),
sidebarLayout(
position = c("left"),
sidebarPanel(
width = 4,
selectInput("select1", label = h5("Event:"),
choices = c("math" , "sience", "sport") ,
selected = 1,
width = 400),
actionButton("action", label = "Add")),
mainPanel(
width = 8,
dataTableOutput('my_table')
)
)
)
server <- function(input, output, session) {
timetable <- reactiveVal(
data.frame(monday = c("","","","",""),
tuesday = c("","","","",""),
wednesday = c("","","","",""),
thursday = c("","","","",""),
friday = c("","","","",""))
)
output$my_table = renderDataTable(timetable(), selection = list(mode = "single", target = "cell"))
observeEvent(input$action, {
tmp <- timetable()
tmp[1, "monday"] <- input$select1
timetable(tmp)
})
observeEvent(input$my_table_cells_selected, {
req(input$my_table_cells_selected)
showModal(modalDialog(
title = "message",
paste("This is a somewhat important message:",
input$my_table_cells_selected[1],
input$my_table_cells_selected[2]),
easyClose = TRUE,
footer = NULL))
})
}
shinyApp(ui, server)

How can I interactively filter nodes/edges from a visNetwork using checkboxes? (using R Shiny)

Using the Shiny and visNetwork R packages I have created an interactive network visualisation. I would like to enable users to remove/add nodes and edges by using checkboxes in the UI. I managed to get this working partially, but somehow my solution does not work when multiple items are filtered.
An example of the behaviour I am trying to achieve can be viewed here.
Please find my code below.
library(visNetwork)
library(shiny)
library(dplyr)
nodes <- data.frame("id" = 1:6)
edges <- data.frame("id" = 1:4, "to" = c(1,2,4,5), "from" = c(2,3,5,6))
ui <- fluidPage(title = "example",
fillPage(
sidebarLayout(
sidebarPanel(
checkboxGroupInput(inputId = "filterNodes",
label = "Select nodes:",
choices = nodes$id,
selected = nodes$id),
width = 3),
mainPanel(
visNetworkOutput("network_proxy_update",width = "100%", height = "90vh"),
width = 9)
)
)
)
server <- function(input, output) {
output$network_proxy_update <- renderVisNetwork({
visNetwork(nodes, edges) %>% visNodes (color = "blue")
})
observe ({
filteredNodes <- data.frame("id" = nodes[nodes$id %in% input$filterNodes, "id"])
hiddenNodes <- anti_join(nodes, filteredNodes)
visNetworkProxy("network_proxy_update") %>%
visRemoveNodes(id = hiddenNodes) %>%
visUpdateNodes(nodes = filteredNodes)
})
}
shinyApp(ui = ui, server = server)
Any help would be greatly appreciated.
Best regards,
Tim
visRemoveNodes expects a vector of id's while visUpdateNodes needs a data.frame of nodes:
library(visNetwork)
library(shiny)
library(dplyr)
nodes <- data.frame("id" = 1:6)
edges <- data.frame(
"id" = 1:4,
"to" = c(1, 2, 4, 5),
"from" = c(2, 3, 5, 6)
)
ui <- fluidPage(title = "example",
fillPage(sidebarLayout(
sidebarPanel(
checkboxGroupInput(
inputId = "filterNodes",
label = "Select nodes:",
choices = nodes$id,
selected = nodes$id
),
width = 3
),
mainPanel(
visNetworkOutput("network_proxy_update", width = "100%", height = "90vh"),
width = 9
)
)))
server <- function(input, output) {
output$network_proxy_update <- renderVisNetwork({
visNetwork(nodes, edges) %>% visNodes (color = "blue")
})
myVisNetworkProxy <- visNetworkProxy("network_proxy_update")
observe ({
filteredNodes <- nodes[nodes$id %in% input$filterNodes, , drop = FALSE]
hiddenNodes <- anti_join(nodes, filteredNodes)
visRemoveNodes(myVisNetworkProxy, id = hiddenNodes$id)
visUpdateNodes(myVisNetworkProxy, nodes = filteredNodes)
})
}
shinyApp(ui = ui, server = server)

How to add comment to a reactive data table in shiny

This question is an extension of the question I posted: this question
I created a dataframe with 3 columns: num, id and val. I want my shiny app to do the following:
a dataframe dat is filtered by num column
select an value from id column from dat (selectInput).
add text comment in a text box (textInput)
click on an action button
A new column called comment is created in the data table, text comments are added to the comment column in the row where id equals the value selected.
The code is below. I cannot figure out why it's not working.
Thank a lot in advance!
library(shiny)
library(DT)
dat = data.frame(num=rep(1:2, each=5), id=rep(LETTERS[1:5],2), val=rnorm(10))
ui = fluidPage(
fluidRow(
column(12, selectInput('selectNum', label='Select Num',
choices=1:10, selected='')),
column(2, selectInput(inputId = 'selectID',
label = 'Select ID2',
choices = LETTERS[1:10],
selected='',
multiple=TRUE)),
column(6, textInput(inputId = 'comment',
label ='Please add comment in the text box:',
value = "", width = NULL,
placeholder = NULL)),
column(2, actionButton(inputId = "button",
label = "Add Comment"))
),
fluidRow (
column(12, DT::dataTableOutput('data') )
)
)
server <- function(input, output, session) {
## make df reactive
df = reactive ({ dat %>% filter(num %in% input$selectNum) })
df_current <- reactiveVal(df())
observeEvent(input$button, {
req(df_current())
## update df by adding comments
df_new <- df_current()
df_new[df_current()$id %in% input$selectID, "Comment"] <- input$comment
df_current(df_new)
})
output$data <- DT::renderDataTable({
req(df_current())
DT::datatable(df_current(),
options = list(orderClasses = TRUE,
lengthMenu = c(5, 10, 20), pageLength = 5))
})
shinyApp(ui=ui, server=server)
Instead of using a reactive/eventReactive statement for df, it might be more natural to keep track of previously inputted comments in the Comment column using a reactiveVal object for df. See also the responses to this question: R Shiny: reactiveValues vs reactive. If you prefer to use a reactive/eventReactive statement for df it is probably better to work with a separate object to store previous input comments (instead of incorporating it into the reactive statement for df).
library(shiny)
library(DT)
dat = data.frame(num=1:10, id=LETTERS[1:10], val=rnorm(10))
ui = fluidPage(
fluidRow(
column(12, selectInput('selectNum', label='Select Num',
choices=1:10)),
column(2, selectInput(inputId = 'selectID',
label = 'Select ID2',
choices = LETTERS[1:10],
selected='',
multiple=TRUE)),
column(6, textInput(inputId = 'comment',
label ='Please add comment in the text box:',
value = "", width = NULL,
placeholder = NULL)),
column(2, actionButton(inputId = "button",
label = "Add Comment"))
),
fluidRow (
column(12, DT::dataTableOutput('data') )
)
)
server <- function(input, output, session) {
## make df reactive
df_current <- reactiveVal(dat)
observeEvent(input$button, {
req(df_current(), input$selectID %in% dat$id)
## update df by adding comments
df_new <- df_current()
df_new[df_current()$id %in% input$selectID, "Comment"] <- input$comment
df_current(df_new)
})
output$data <- DT::renderDataTable({
req(df_current())
## filter df_current by 'selectNum'
df_filtered <- df_current()[df_current()$num %in% input$selectNum, ]
## show comments if non-empty
showComments <- is.null(df_filtered$Comment) || !all(is.na(df_filtered$Comment))
DT::datatable(df_filtered,
options = list(orderClasses = TRUE,
lengthMenu = c(5, 10, 20), pageLength = 5,
columnDefs = list(
list(targets = ncol(df_filtered), visible = showComments)
)
)
)
})
}
shinyApp(ui=ui, server=server)
Edit: below an edited server function that using df_current <- reactive({...}) instead of df_current <- reactiveVal({...}) and defining a separate reactiveVal object to keep track of the comments.
server <- function(input, output, session) {
## initialize separate reactive object for comments
df_comments <- reactiveVal({
data.frame(
id = character(0),
Comment = character(0),
stringsAsFactors = FALSE
)
})
## reactive object df
df_current <- reactive({
## reactivity that df depends on
## currently df = dat does not change
df <- dat
## merge with current comments
if(nrow(df_comments()) > 0)
df <- merge(df, df_comments(), by = "id", all.x = TRUE)
return(df)
})
observeEvent(input$button, {
req(input$selectID)
## update df_comments by adding comments
df_comments_new <- rbind(df_comments(),
data.frame(id = input$selectID, Comment = input$comment)
)
## if duplicated id's keep only most recent rows
df_comments_new <- df_comments_new[!duplicated(df_comments_new$id, fromLast = TRUE), , drop = FALSE]
df_comments(df_comments_new)
})
output$data <- DT::renderDataTable({
req(df_current())
## filter df_current by 'selectNum'
df_filtered <- df_current()[df_current()$num %in% input$selectNum, ]
## show comments if non-empty
showComments <- is.null(df_filtered$Comment) || !all(is.na(df_filtered$Comment))
DT::datatable(df_filtered,
options = list(orderClasses = TRUE,
lengthMenu = c(5, 10, 20), pageLength = 5,
columnDefs = list(
list(targets = ncol(df_filtered), visible = showComments)
)
)
)
})
}
There you have got a working example.
I think the thing is that you are trying to update a value through an observeEvent which is not good according to the documentation. ?observeEvent
Use observeEvent whenever you want to perform an action in response to an event. (Note that "recalculate a value" does not generally count as performing an action–see eventReactive for that.)
library(shiny)
library(DT)
dat = data.frame(num=1:10, id=LETTERS[1:10], val=rnorm(10))
ui = fluidPage(
fluidRow(
column(12, selectInput('selectNum', label='Select Num',
choices=1:10, selected='')),
column(2, selectInput(inputId = 'selectID',
label = 'Select ID2',
choices = LETTERS[1:10],
selected='',
multiple=TRUE)),
column(6, textInput(inputId = 'comment',
label ='Please add comment in the text box:',
value = "", width = NULL,
placeholder = NULL)),
column(2, actionButton(inputId = "button",
label = "Add Comment"))
),
fluidRow (
column(12, DT::dataTableOutput('data') )
)
)
server <- function(input, output, session) {
## make df reactive
df_current = reactive({
df = dat %>% filter(num %in% input$selectNum)
if(input$button != 0) {
input$button
df[df$id %in% input$selectID, "Comment"] <- isolate(input$comment)
}
return(df)
})
output$data <- DT::renderDataTable({
req(df_current())
DT::datatable(df_current(),
options = list(orderClasses = TRUE,
lengthMenu = c(5, 10, 20), pageLength = 5))
})
}
shinyApp(ui=ui, server=server)
So you can either go with your reactive value or using eventReactive as stated in the doc.

Using Paste to get the input data from the checkboxGroupInput aggregated and seperated by comma

I am using the below code to get the input from checkboxGroupInput to aggregate and separated by comma so that i can use them in my further query as an input.
I tried the below code but this is not working and giving me error.
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(title = "Basic Dashboard"),
dashboardSidebar(
checkboxGroupInput(inputId="variable", label="OG to show:",
choiceNames=c("All","CMT","FS","HPS","PRD","RES"),
choiceValues=c("All","CMT","FS","HPS","PRD","RES"),
selected = NULL,
inline = T
#, multiple = T,selectize = T),
)),
dashboardBody(
textOutput('table1')
))
server <- function(input, output) {
OG <- reactive({
switch(input$variable,
"All" = 1,
"CMT" = 2,
"FS" = 3,
"HPS" = 4,
"PRD" = 5,
"RES" = 6)
})
OG1 <- reactive({icons1 <- paste(OG(), collapse = ",")})
output$table1 <-renderText({OG1()})
}
runApp(shinyApp(ui, server),launch.browser = TRUE)
Expected Output is 2,3,....
As per the selection from checkbox it should give me the # separated by comma.
You could use req() and sapply() to solve the issues.
To avoid using NULL if no option is selected use req(). In order to pass an vector of inputs to switch() you can use sapply().
Reproducible example:
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(title = "Basic Dashboard"),
dashboardSidebar(
checkboxGroupInput(inputId = "variable", label = "OG to show:",
choiceNames = c("All","CMT","FS","HPS","PRD","RES"),
choiceValues = c("All","CMT","FS","HPS","PRD","RES"),
selected = NULL, inline = T
)
),
dashboardBody(
textOutput('table1')
))
server <- function(input, output) {
OG <- reactive({
req(input$variable)
unname(sapply(input$variable, switch,
"All" = 1, "CMT" = 2, "FS" = 3, "HPS" = 4, "PRD" = 5, "RES" = 6))
})
output$table1 <-renderText({
print(OG() %in% 2:6)
})
}
runApp(shinyApp(ui, server))

Format table output in R shiny based on user inputs

I have a table being display in a shiny app. I want to format the tables based on the values and color it accordingly. I have seen the formattable area coloring where based on the range of the values it defines the breaks and then color gradients are generated which are applied to the table. What I want to do is allow the user to fill the min and max value and depending on it the values in the table will be colored. So if the values range from 1-20 and if the user inputs are 5 and 15 , values below 5 and above 15 shouldnt have any color gradients applied to them. Below is the code of how I am doing currently using formatable area formatting.
library(shiny)
library(shinyWidgets)
library(shinydashboard)
library(DT)
sidebar <- dashboardSidebar(
sidebarMenu(id = "tab",
menuItem("1", tabName = "1")
)
)
body <- ## Body content
dashboardBody(box(width = 12,fluidRow(
fluidRow( column(
width = 3, textInput("text1", label = h5("Min"), value = "Enter min")),
column(
width = 3, textInput("text2", label = h5("Max"), value = "Enter max"))),
DT::dataTableOutput("op")
)))
ui <- dashboardPage(dashboardHeader(title = "Scorecard"),
sidebar,
body)
# Define the server code
server <- function(input, output,session) {
df <- data.frame(month = c("mazda 3", "mazda cx5", "mazda 6","mazda miata","honda civic","honda accord"),
april = c(.1,.2,.3,.3,.4,.5),
may = c(.3,.4,.5,.2,.1,.5),
june = c(.2,.1,.5,.1,.2,.3))
brks <- reactive({ quantile(df$april, probs = seq(.05, .95, .05), na.rm = TRUE)})
clrs <- reactive({ round(seq(255, 175, length.out = length(brks()) + 1), 0) %>%
{paste0("rgb(",.,",", ., ",255 )")}})
df_format<- reactive ({datatable(df,options = list(searching = FALSE,pageLength = 15, lengthChange = FALSE))%>%
formatStyle(names(df),backgroundColor = styleInterval(brks(), clrs()))})
output$op <-renderDataTable({
df_format()
})
}
shinyApp(ui = ui, server = server)
Here is your working code.
You must use that input minimal and maximal value as limits for your sequence (I just change it to range - is easier for user to put a range like that)
Then you generate sequence - according your notation - brks() - in my case I use length.out of 10 but you can put as many breaks as you want or dynamically.
Then generate on
number of colors - 1
and in the end in styleInterval() for background add limits of white - or any other color you want.
library(shiny)
library(shinyWidgets)
library(shinydashboard)
library(DT)
sidebar <- dashboardSidebar(
sidebarMenu(id = "tab",
menuItem("1", tabName = "1")
)
)
body <- ## Body content
dashboardBody(box(width = 12,fluidRow(
fluidRow(column(
width = 3,
sliderInput("range_value",
label = h3("Put a range value"),
min = 0,
max = 100,
value = c(5, 15)
)
)
),
DT::dataTableOutput("op")
)))
ui <- dashboardPage(dashboardHeader(title = "Scorecard"),
sidebar,
body)
# Define the server code
server <- function(input, output,session) {
df <- data.frame(month = c("mazda 3", "mazda cx5", "mazda 6","mazda miata","honda
civic","honda accord"),
april = c(9, 8, 11,14,16,1),
may = c(3,4,15,12,11, 19),
june = c(2,11,9,7,14,1))
brks <- reactive({
seq(input$range_value[1], input$range_value[2], length.out = 10)
})
clrs <- reactive({ round(seq(255, 175, length.out = length(brks()) - 1), 0) %>%
{paste0("rgb(",.,",", ., ",255)")}})
df_format<- reactive ({datatable(df,options = list(searching = FALSE, pageLength = 15, lengthChange = FALSE)) %>%
formatStyle(names(df),
backgroundColor = styleInterval(c(brks()), c('white', clrs() ,'white'))
)
})
output$op <-renderDataTable({
df_format()
})
}
shinyApp(ui = ui, server = server)

Resources