I would like to give users an option to assign different rows (subjects) to groups.
Ideally, one can highlight rows, then write a group name in the "Assign to group: " field and it is saved. Then they can select a new set of rows and add those to a different group; and so on until all desired rows are assigned.
Here is what I have so far. I can't figure out how to save the results before selecting a new set of rows..
library(shiny)
library(DT)
ui <- fluidPage(
fluidRow(
column(6,
DT::dataTableOutput('x1'),
textInput("assignGroup","Assign to group: ")),
column(6, DT::dataTableOutput('x2'))
)
)
server <- shinyServer(function(input, output, session) {
output$x1 = DT::renderDataTable(cars, server = FALSE)
output$x2 = DT::renderDataTable({
s <- input$x1_rows_selected
temp <- cars
temp$Experiment <- as.character("")
temp[s,"Experiment"] <- input$assignGroup
temp
}, server = FALSE)
})
shinyApp(ui, server)
Thanks and hope this is somewhat clear!!!
You can observe 'input$x1_rows_selected' and then edit the table on the event. To display live changes to the table, you can add a reactive table.
Hope this code works out for you.
library(shiny)
library(DT)
ui <- fluidPage(
fluidRow(
column(6,
DT::dataTableOutput('x1'),
textInput("assignGroup","Assign to group: ")
),
column(6, DT::dataTableOutput('x2'))
)
)
server <- shinyServer(function(input, output, session) {
values <- reactiveValues(
df_data = cars,
temp = {
cars[,c("Experiment")]<-NA
cars
}
)
output$x1 = DT::renderDataTable(values$df_data, server = FALSE)
observeEvent(input$x1_rows_selected,
{
s<-input$x1_rows_selected
values$temp[s,"Experiment"]<-input$assignGroup
}
)
output$x2 = DT::renderDataTable(
values$temp, server = FALSE)
})
shinyApp(ui, server)
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 want to store rows selection from the first table to a second table. Then, create plot from selected rows that are now in the second table. Below is what I have tried to do, any suggestion?
The data I have can be seen in the picture
library(shiny)
library(DT)
readfile <- read.csv("data.csv")
server <- shinyServer(function(input, output, session) {
output$x1 = DT::renderDataTable(readfile, server = FALSE)
output$x2 = DT::renderDataTable({
sel <- input$x1_rows_selected
if(length(readfile)){
readfile[sel, ]
}
}, server = FALSE)
output$x3 <- renderPlot({
s = input$x3_rows_selected
ggplot(readfile[input$x1_rows_all, ], aes(x=Month)) +
geom_bar()
})
})
ui <- fluidPage(
fluidRow(
column(6, DT::dataTableOutput('x1')),
column(6, DT::dataTableOutput('x2')),
column(6, plotOutput('x3', height = 500))
)
)
shinyApp(ui, server)
I think you just need to replace this:
ggplot(readfile[input$x1_rows_all, ], aes(x=Month))
with this:
ggplot(readfile[input$x1_rows_selected, ], aes(x=Month))
Update: Here's the whole app using the mtcars data.
library(DT)
readfile <- mtcars
server <- shinyServer(function(input, output, session) {
output$x1 = DT::renderDataTable(readfile, server = FALSE)
output$x2 = DT::renderDataTable({
sel <- input$x1_rows_selected
if(length(readfile)){
readfile[sel, ]
}
}, server = FALSE)
output$x3 <- renderPlot({
s = input$x3_rows_selected
ggplot(readfile[input$x1_rows_selected, ], aes(x=factor(cyl, levels=c(4,6,8)))) +
geom_bar()
})
})
ui <- fluidPage(
fluidRow(
column(6, DT::dataTableOutput('x1')),
column(6, DT::dataTableOutput('x2')),
column(6, plotOutput('x3', height = 500))
)
)
shinyApp(ui, server)
Here's what the output looks like - it seems to be doing what is intended.
I am using R Shiny to output a table, but I am having trouble filtering in the reactive part for the renderDataTable. I am using the mtcars table in this example, and I am trying to filter by type:
library(shiny)
library(DT)
ui <- fluidPage(
titlePanel("MTCARS"),
sidebarLayout(
sidebarPanel(id="sidebar",
textInput("type",
label = "Type",
placeholder = "Type"),)
,
mainPanel(
dataTableOutput("data")
)
)
)
server <- function(input, output, session) {
selected <- reactive({
if (length(input$type) != 0) {
mtcars$type %in% input$type
} else {
TRUE
}
})
output$data <- renderDataTable(mtcars[selected(),])
}
shinyApp(ui = ui, server = server)
Currently, mtcars$type %in% input$type filters the table based on what the user inputs as the type. However, I want to modify this so that:
The text does not have to match exactly. Rows that contain Honda Civic will show up if the user types Hond.
The table needs to start out with the full table. Currently it has no row when it is starting despite having the if/else statement.
mtcars does not have any column type so I had to create one. I used stringr::str_detect to include also partially matched types.
library(shiny)
library(DT)
data <- mtcars %>%
rownames_to_column(var = "type")
ui <- fluidPage(
titlePanel("MTCARS"),
sidebarLayout(
sidebarPanel(id="sidebar",
textInput("type",
label = "Type",
placeholder = "Type"),)
,
mainPanel(
dataTableOutput("data")
)
)
)
server <- function(input, output, session) {
selected <- reactive({
if (length(input$type) != 0) {
stringr::str_detect(data$type, input$type)
} else {
TRUE
}
})
output$data <- renderDataTable(data[selected(),])
}
shinyApp(ui = ui, server = server)
I am currently trying to limit my selection in a DataTable in Shiny to just two rows - I want the table to not allow the user to click on more than rows (but also to have the ability to deselect them afterwards).
library(DT)
shinyApp(
ui = fluidPage(
fluidRow(
column(12,
dataTableOutput('table')
)
)
),
server = function(input, output) {
output$table <- DT::renderDataTable(iris,
options = list(selection = "multiple")
)
}
)
The row selection is currently on multiple mode, which works, but I don't want the selection to exceed two rows.
Update: Does not seem to work anymore, since 04.2022 or earlier.
You could either solve it via javascript, which you may have seen already:
Limit row selection to 3 in datatables
Or you update the datatable in Shiny:
library(DT)
library(shiny)
shinyApp(
ui = fluidPage(
fluidRow(
column(12,dataTableOutput('tbl'))
)
),
server = function(input, output) {
reset <- reactiveValues(sel = "")
output$tbl <- DT::renderDataTable({
input$tbl_rows_selected
datatable(iris, selection = list(mode = 'multiple', selected = reset$sel))
})
observe({
if(length(input$tbl_rows_selected) > 2){
reset$sel <- setdiff(input$tbl_rows_selected, input$tbl_row_last_clicked)
}else{
reset$sel <- input$tbl_rows_selected
}
})
}
)
This solution might be less clean, but a bit easier to understand.
It's not exactly what you want but I've changed a bit Tonio's answer, it may help someone else.
library(DT)
library(shiny)
shinyApp(
ui = fluidPage(
fluidRow(
column(12,dataTableOutput('tbl'))
),
textOutput('selected_rows')
),
server = function(input, output) {
reset <- reactiveValues(sel = "")
output$tbl <- DT::renderDataTable({
datatable(iris, selection = list(mode = 'multiple', selected = reset$sel))
})
observe({
if(length(input$tbl_rows_selected) > 2){
reset$sel <- NULL
}else{
reset$sel <- input$tbl_rows_selected
}
})
output$selected_rows <- renderText({input$tbl_rows_selected})
}
)
I am trying to gather user input given a data set. I want to insert a column where the user can determine whether they would want to own one of the cars in the mtdata set. This is completely subjective as opinions differ from person to person so I am not able to program this in. Is there a way to append an extra column that can be a checkbox or dropdown menu to identify cars that a user would "Want to own?
library(shiny)
shinyApp(ui = shinyUI(fluidPage(
titlePanel("Interesting Cars"),
sidebarLayout(
sidebarPanel(
helpText("This is a side bar")),
mainPanel(
tableOutput("view")
)
)
)),
server = function(input, output) {
output$view <- renderTable({
head(mtcars[, 1:4], n = 6)
})
})
How about this, you can use the DT library. By adding the filter option the user can define the different components one wants and see what cars come up.
library(shiny)
library(DT)
shinyApp(ui = shinyUI(fluidPage(
titlePanel("Interesting Cars"),
sidebarLayout(
sidebarPanel(
helpText("This is a side bar")),
mainPanel(
DT::dataTableOutput("view")
)
)
)),
server = function(input, output) {
output$view <- DT::renderDataTable({
datatable(mtcars,
filter = "top"
)
})
})
Edit
If it truly is so important to add another column indicating if it is 'interesting' there will be significantly more code to written if you intend to have users assign it on different conditions. Here is an example with just the mpg. The fundamental idea here is that you assign your data to the reactiveValues function. It can then be modified as you like. This can obviously be improved upon more (as it will continue to add columns) but it demonstrates the concept.
shinyApp(ui = shinyUI(fluidPage(
titlePanel("Interesting Cars"),
sidebarLayout(
sidebarPanel(
helpText("This is a side bar"),
uiOutput("mpg"),
actionButton("add_label", "Mark Interesting")
),
mainPanel(
DT::dataTableOutput("view")
)
)
)),
server = function(input, output) {
values <- reactiveValues(
mydata = mtcars
)
output$mpg <- renderUI({
numericInput("mpg_input", "MPG Cutoff?",
value = 15
)
})
output$view <- DT::renderDataTable({
datatable(values$mydata
)
})
observeEvent(input$add_label, {
validate(
need(!is.null(input$mpg_input), "need mpg value")
)
values$mydata <- data.frame(values$mydata,
Interesting_Flag =
ifelse(values$mydata$mpg > input$mpg_input,
"Interesting",
"Not Interesting"))
})
})