change label of shiny button and counting clicks - r

I was trying to switch the label of a show/hide columns button, and also keep the track of the number of times it is clicked in order to alter the number of columns showed of a table. I made it, but I couldn't use a direct even/odd differentiation of the value of the counter. Instead I had to use this: (vars$counter+1)/2) %% 2 == 0) to make it work, because each click changes the counter 2 times. I would like to request an easier procedure, maybe there is a shinyBS for that?
## app.R ##
library(shiny)
library(shinydashboard)
library(DT)
body<-dashboardBody(
textOutput("count"),
uiOutput('showallcolumnsbutton'),
DT::dataTableOutput('table2')
)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
body
)
server <- function(input, output) {
table<-data.frame(replicate(10,sample(0:1,1000,rep=TRUE)))
vars<-reactiveValues()
vars = reactiveValues(counter = 0)
observe({
if(!is.null(input$showallcolumns)){
input$showallcolumns
isolate({
vars$counter <- vars$counter + 1
})
}
})
label <- reactive({
if(!is.null(input$showallcolumns)){
if( ( (vars$counter+1)/2) %% 2 == 0) label <- "Hide"
else label <- "Show"
}
})
output$showallcolumnsbutton <- renderUI({
actionButton("showallcolumns", label = label(),
icon("hand-pointer-o"),
style="color: #000; background-color: #0099ff; border-color: #2e6da4"
)
})
output$count<-renderText({paste("counter value:",vars$counter)})
columnstoshow = reactive ({
x= ((vars$counter+1)/2) # %% 2 == 0)
if (!is.null (x))
{
if (x %% 2 == 0) {
c=c(1:10)
}
else {
c=c(1:5)
}
} #end 1st if
else {
c=c(1:10)
}
})
output$table2 = DT::renderDataTable({
DT::datatable(table[, columnstoshow()])
})
} # end server
shinyApp(ui, server)

Since Im not 100% what you want, is this it? Note that I used other library such as shinyBS
rm(list = ls())
library(shiny)
library(shinydashboard)
library(DT)
library(shinyBS)
body <- dashboardBody(bsButton("showallcolumns", label = "Hide", block = F, style="danger",icon=icon("hand-pointer-o")),br(),DT::dataTableOutput('table2'))
ui <- dashboardPage(dashboardHeader(),dashboardSidebar(),body)
server <- function(input, output,session) {
table <- data.frame(replicate(10,sample(0:1,1000,rep=TRUE)))
vars <- reactiveValues(counter = 1:10)
observeEvent(input$showallcolumns,{
if(input$showallcolumns %% 2){
updateButton(session, "showallcolumns",label = "Show", block = F, style = "success",icon=icon("hand-pointer-o"))
vars$counter <- 1:5
}
else{
updateButton(session, "showallcolumns",label = "Hide", block = F, style = "danger",icon=icon("hand-pointer-o"))
vars$counter <- 1:10
}
})
output$table2 = DT::renderDataTable({
DT::datatable(table[, vars$counter])
})
} # end server
shinyApp(ui, server)

Related

Shiny bookmark - unable to restore some of user's selections

I have just started include bookmark functionality to my app. My app have a few selection inputs which do not seem to be restored and I couldnt figure out the problems.
The app has 2 key inputs:
The radio button on the sidebar
The date/number ranges
At the current state, the app cant seem to restore the radio button (if I switch to duration, it just doesnt work)
The simplify code is below:
library(shiny)
library(data.table)
library(tidyverse)
library(lubridate)
library(shinydashboard)
library(zoo)
library(shinyWidgets)
library(nycflights13)
flight.dt <- flights %>% mutate(flight.date =ymd(substr(time_hour,1,10)),duration=round(air_time,-2))
### --------Analyse module ---------------------------
plotUI <- function(id) {
ns <- NS(id)
tagList(
uiOutput(ns("groupmenu")),
plotOutput(ns("plot"))
)
}
plotServer <- function(id,method,carr) {
moduleServer(
id,
function(input, output, session) {
filtered.data <- reactive(flight.dt %>% filter(carrier == carr))
output$groupmenu <- renderUI({
getselection <- if (method() != "duration") c("Year Quarter"="yearqtr") else c("Duration"="dur.grp")
rng.min <- switch (method(),
"date" = min(filtered.data()$flight.date),
"duration" = max(0,min(filtered.data()$duration,na.rm = TRUE)))
rng.max <- switch(method(),
"date" = max(filtered.data()$flight.date),
"duration" = max(0,max(filtered.data()$duration,na.rm = TRUE)))
ns <- session$ns
tagList(
fluidRow(
column(2,selectInput(ns("group"), "Group by:",choices =as.list(getselection))),
conditionalPanel("input.method == 'date'",
dateRangeInput(ns("daterange"),"Date range:",start = rng.min,end = rng.max,format = "dd/mm/yyyy", separator = " - ")),
conditionalPanel("input.method == 'duration'",
numericRangeInput(ns("durrange"), label = "Duration range:",value = c(rng.min,rng.max)))
)
)
})
dt <- reactiveVal(NULL)
observeEvent(input$group,{
tmp <- filtered.data() %>% mutate(sel.method = switch(method(),"date" = flight.date,"duration" = duration))
if (input$group == "yearqtr") {
tmp$key <- paste0(year(tmp$sel.method),"-Q",quarter(tmp$sel.method))
} else if (input$group == "dur.grp") {
tmp$key <- tmp$duration
}
dt(tmp)
})
dt.sum <- reactive({
req(dt())
setDT(dt())
if (method() == "date") {
tmp <- dt()[sel.method >= input$daterange[1] & sel.method <= input$daterange[2]]
} else if (method() == "duration") {
tmp <- dt()[key >= input$durrange[1] & key <= input$durrange[2]]
}
tmp %>% group_by(key) %>% dplyr::summarise(count=n())
})
output$plot <- renderPlot({
dt.sum() %>% ggplot(aes(x = as.character(key), y = count)) + geom_col()
})
}
)
}
### UI part -----------------------
header <- dashboardHeader(title = 'Analysis')
sidebar <- dashboardSidebar(
radioButtons("method", "Select method:",c("Date" = "date","Duration" = "duration"),selected = "date"),
bookmarkButton()
)
body <- dashboardBody(uiOutput('tablist'))
ui <- function(request) {
dashboardPage(title="Analysis", header,sidebar,body)
}
### Server part ----------------------------
server = function(input, output) {
method <- reactive(input$method)
carr <- reactive(unique(flight.dt$carrier)[1:3])
ntabs <- reactive(length(carr()))
observeEvent(ntabs(),{
lapply(1:ntabs(), function (i) plotServer(paste0("count",i),method,carr()[i]))
})
output$tablist = renderUI({
addtabs <- lapply(1:ntabs(),function (i) {
tabPanel(carr()[i],plotUI(paste0("count",i)))
})
do.call(tabsetPanel, addtabs)
})
}
### Running part ----------------------------
enableBookmarking("server")
shinyApp(ui, server)
Put your ui elements you want restored within ui function. See simplified example:
library(shiny)
library(shinydashboard)
### UI part -----------------------
ui <- function(request) {
header <- dashboardHeader(title = 'Analysis')
sidebar <- dashboardSidebar(
radioButtons("method", "Select method:",c("Date" = "date","Duration" = "duration"),selected = "date"),
bookmarkButton()
)
body <- dashboardBody("BODY")
dashboardPage(title="Analysis", header,sidebar,body)
}
### Server part ----------------------------
server = function(input, output) {
}
### Running part ----------------------------
enableBookmarking("server")
shinyApp(ui, server)

updateSelectInput modifies the format of selectInput box in Shiny

I have a selectInput inside of a datatable that gets its value updated by a button in another column of the table. I have modified the original size of the box to make the rows smaller, but when updating the value with the updateSelectInput function, it resizes the box outside the boundaries of the row. Does anyone know why the original styling is being lost when updating the value of the box or how to set the formatting with updateSelectInput (maybe updateSelectizeInput using Options)?
Additionally, the functionality only works if I have the "test" selectInput box included in the code even though it actually does nothing functionally. Any help is greatly appreciated!
enlarged selectInput boxes
library(shiny)
library(DT)
library(data.table)
# ui ----
ui <- fluidPage(
sidebarLayout(
sidebarPanel(width = 2,
selectInput("test","test",choices = c(1,2)),
actionButton("refresh","Run Report")
),
mainPanel(
tags$style(type='text/css', ".selectize-input { font-size: 13px; line-height: 10px;}
.selectize-dropdown { font-size: 13px; line-height: 13px; }
.form-group, .selectize-control {margin-top:-10px;margin-bottom:-5px;max-height: 100px !important;}
.box-body {padding-top: 1px;padding-bottom: 1px;}"
)
,dataTableOutput('currentData')
)
)
)
# server ----
server <- function(input, output, session) {
data <- reactiveValues()
counter <<- 1
rawData <- eventReactive(input$refresh,{
rawData <- data.table(testID = c(1),comment = "test")
rawData <- rbind(rawData,data.table(testID = c(2,3),comment = " "))
list(rawData)
})
preppedData <- reactive({
outputData <- rawData()[[1]]
for (i in 1:nrow(outputData)) {
outputData$comments[i] <- as.character(selectInput(paste0("sel",i,"_",counter),"",selected = outputData$comment[i],choices = c(" ","test","other comment"),width = "350px"))
}
data$Data <- outputData
counter <<- counter + 1
list(outputData)
})
output$currentData = DT::renderDataTable({
outputData <- preppedData()[[1]]
outputData <- outputData[,fillCommentFromAbove := (buttonInput(
FUN = actionButton,
len = nrow(outputData),
id = 'button_',
label = "Fill Comment From Above",
style='margin-top:-5px;margin-bottom:-5px; padding:1px; font-size:100%',
onclick = 'Shiny.onInputChange(\"commentFiller\", this.id)'
))]
datatable(outputData,escape = F,
callback = JS("table.rows().every(function(i, tab, row) {
var $this = $(this.node());
$this.attr('id', this.data()[0]);
$this.addClass('shiny-input-container');
});
Shiny.unbindAll(table.table().node());
Shiny.bindAll(table.table().node());"
)
)
}, server = F #this is important for making comment saving functionality work
)
observeEvent(input$commentFiller, {
outputData <- preppedData()[[1]]
selectedRow <- as.numeric(strsplit(input$commentFiller, "_")[[1]][2])
currentRow <- outputData[selectedRow,]
success <- FALSE
i <- 1
inputToUpdate <- NA
while (!success) {
priorRow <- outputData[selectedRow-i,]
currentRow <- outputData[selectedRow-i+1,]
currentRowResult <- regmatches(merge(currentRow,data$Data)$comments, regexec("sel\\s*(.*?)\\s*_", merge(currentRow,data$Data)$comments))[[1]][2]
inputToUpdate <- na.omit(c(inputToUpdate,paste0("sel",currentRowResult,"_")))
result <- regmatches(merge(priorRow,data$Data)$comments, regexec("sel\\s*(.*?)\\s*_", merge(priorRow,data$Data)$comments))[[1]][2]
value <- input[[paste0("sel",result,"_",counter-1)]]
i <- i+1
success <- value != ' '
}
rowsToUpdate <- outputData[(selectedRow-(i-2)):selectedRow,]
for(i in inputToUpdate){
updateSelectInput(session = session,inputId = paste0(i,counter-1),selected = value)
}
})
buttonInput <- function(FUN, len, id, ...) {
inputs <- character(len)
for (i in seq_len(len)) {
inputs[i] <- as.character(FUN(paste0(id, i), ...))
}
inputs
}
}
# Run the app ----
shinyApp(ui = ui, server = server)

R Shiny Dynamically add textinput and print ui output based on Userinput

I am trying to create a shiny application which will enable users to add text boxes, or add images and create a document from it. I am able to add one Textbox and display its contents but when I add another textbox, the contents are not displayed. I have used a link as a starting point.
Here is my sample code that I am trying to add more user input text boxes by clicking add button.
library(shiny)
library(shinyjqui)
ui <- shinyUI(fluidPage(
sidebarPanel(
actionButton("add_btn", "Add Textbox"),
actionButton("rm_btn", "Remove Textbox"),
textOutput("counter")
),
mainPanel(
jqui_sortable(
div(id = 'textboxes',
uiOutput("textbox_ui"),
textInput("caption", "Caption", "Insert Text"),
verbatimTextOutput("value")
)
)
)
))
server <- shinyServer(function(input, output, session) {
# Track the number of input boxes to render
counter <- reactiveValues(n = 0)
#Track the number of input boxes previously
prevcount <- reactiveValues(n = 0)
observeEvent(input$add_btn, {
counter$n <- counter$n + 1
prevcount$n <- counter$n - 1})
observeEvent(input$rm_btn, {
if (counter$n > 0) {
counter$n <- counter$n - 1
prevcount$n <- counter$n + 1
}
})
output$value <- renderText({ input$caption })
output$counter <- renderPrint(print(counter$n))
textboxes <- reactive({
n <- counter$n
if (n > 0) {
# If the no. of textboxes previously where more than zero, then
#save the text inputs in those text boxes
if(prevcount$n > 0){
vals = c()
if(prevcount$n > n){
lesscnt <- n
isInc <- FALSE
}else{
lesscnt <- prevcount$n
isInc <- TRUE
}
for(i in 1:lesscnt){
inpid = paste0("textin",i)
vals[i] = input[[inpid]]
}
if(isInc){
vals <- c(vals, "Insert Text")
}
lapply(seq_len(n), function(i) {
textInput(inputId = paste0("textin", i),
label = paste0("Subsection ", i), value = vals[i])
})
}else{
lapply(seq_len(n), function(i) {
textInput(inputId = paste0("textin", i),
label = paste0("Subsection ", i), value = "Insert text")
})
}
}
})
output$textbox_ui <- renderUI({ textboxes() })
})
shinyApp(ui, server)
Any help will be appreciated in this regard. If anyone can point me in how to dynamically capture output$value everytime a new box is added it would push me in the right direction.
Have you tried reactiveValuesToList function ?
Here you have an example that might help
AllInputs <- reactive({
x <- reactiveValuesToList(input) })
textboxes <- reactive({
n <- counter$n
if (n > 0) {
isolate({
lapply(seq_len(n), function(i) {
textInput(inputId = paste0("textin", i),
label = paste0("Textbox", i),
value = AllInputs()[[paste0("textin", i)]])
})
})
}
})

Shiny R renderPrint in loop usinf RenderUI only update the output

I am trying to dynamically render multiple text output from multiple text input. I tried to use this very helpfull example and this one too.
This conversation is also helpfull.
But when I try to adapt this examples on the following script, I have a problem of output update. Apparently, only the last element was read and updated. It's probably a reactivity problem but it seems to be difficult to associate reactive{()} and renderUI{()}functions.
rm(list = ls())
library(shiny)
creatDataElem <- function(ne, input) {
x1 <- lapply(1:ne, function(i) {
textInput(paste0("elemName", i),
label = h4(strong("Name of dataset element")),
value = "")
})
return(x1)
}
ui = (fluidPage(
sidebarLayout(
sidebarPanel(
sliderInput("elemNb",
"Number of elements", value = 1, min = 1,
max = 3)
,
conditionalPanel(
condition = "input.elemNb == 1",
creatDataElem(1)
),
conditionalPanel(
condition = "input.elemNb == 2",
creatDataElem(2)
),
conditionalPanel(
condition = "input.elemNb == 3",
creatDataElem(3)
)
),
mainPanel(
uiOutput("nameElem")
)
)
)
)
server = function(input, output, session) {
max_elem <- 3
# Name
output$nameElem <-renderUI({
nameElem_output_list <- lapply(1:input$elemNb, function(i) {
elemName <- paste0("elemName", i)
tags$div(class = "group-output",
verbatimTextOutput(elemName)
)
})
do.call(tagList, nameElem_output_list)
})
for (i in 1:max_elem) {
local({
force(i)
my_i <- i
elemName <- paste0("elemName", my_i)
output[[elemName]] <- renderPrint(input[[elemName]])
})
}
}
runApp(list(ui = ui, server = server))
The idea with a reactive({}) function is to add an independant object (a function in this case) like:
nameElem <- reactive({
if (input$goElem == 0) {
return()
} else {
isolate({
if (is.null(input$elemName)) {
return()
} else if (test(input$elemName)) {
return("TEST RESULT")
} else {
return(input$elemName)
}
})
}
})
and to use renderUI on this object (with an ActionButton).
So, if someone knows why the output does not return the good object...
I think one of your problems is that your creatDataElem function is such that when it is called with argument ne=3, the first and second textInput elements are created again (and their value "lost").
Anyway, I think one solution would be to create those textInput elements as an "uiOutput".
You'll find a possible solution below which (I think) does what you want.
Lise
rm(list = ls())
library(shiny)
ui = (fluidPage(
sidebarLayout(
sidebarPanel(
sliderInput("elemNb",
"Number of elements", value = 1, min = 1,
max = 3),
uiOutput("myUI")
),
mainPanel(
uiOutput("nameElem")
)
)
)
)
server = function(input, output, session) {
output$myUI=renderUI({
w=""
for (i in 1:input$elemNb){
w=paste0(w,
textInput(paste0("elemName",i),label='Name of dataset element'))
}
HTML(w)
})
output$nameElem <-renderUI({
elems=c("<div>")
for(i in 1:input$elemNb){
elems=paste(elems,"</div><div>",input[[paste0("elemName",i)]])
}
elems=paste0(elems,"</div>")
HTML(elems)
})
}
runApp(list(ui = ui, server = server))
Found a solution:
library(readr)
library(dplyr)
library(shiny)
df <- data.frame(symbol = 1:10)
uiOutput("myUI")
createUI <- function(dfID, symbol) {
div(class="flex-box",paste0(symbol, " - 10"))
}
output$myUI <- renderUI({
w <- lapply(seq_len(nrow(df)), function(i) {
createUI(i, df[i,"symbol"])
})
do.call(fluidPage,w)
})

Get selected rows of Rhandsontable

I am using rhandsontable in a Shiny App and I would like to know how to use the getSelected() method of Handsontable in this case, as I intend to apply changes on the data.frame.
thank you!
You can obtain the selected row, column, range, and cell values, as well as the edited cells using selectCallback=TRUE. You can edit a cell by double-clicking on it, and accept the changes by pressing "return" or "enter".
Minimal example:
library(shiny)
library(rhandsontable)
ui=fluidPage(
rHandsontableOutput('table'),
verbatimTextOutput('selected')
)
server=function(input,output,session)({
df=data.frame(N=c(1:10),L=LETTERS[1:10],M=LETTERS[11:20])
output$table=renderRHandsontable(
rhandsontable(df,selectCallback = TRUE,readOnly = FALSE)
)
output$selected=renderPrint({
cat('Selected Row:',input$table_select$select$r)
cat('\nSelected Column:',input$table_select$select$c)
cat('\nSelected Cell Value:',
input$table_select$data[[
input$table_select$select$r]][[input$table_select$select$c]])
cat('\nSelected Range: R',input$table_select$select$r,
'C',input$table_select$select$c,':R',input$table_select$select$r2,
'C',input$table_select$select$c2,sep="")
cat('\nChanged Cell Row Column:',input$table$changes$changes[[1]][[1]],
input$table$changes$changes[[1]][[2]])
cat('\nChanged Cell Old Value:',input$table$changes$changes[[1]][[3]])
cat('\nChanged Cell New Value:',input$table$changes$changes[[1]][[4]])
})
}) # end server
shinyApp(ui = ui, server = server)
While rhandsontable is a real good implementation of handsontable (credit goes to #jrowen), currently it does not include getSelected().
The event of a user altering any cell (including selecting / deselecting a checkbox) is tracked by shiny. This gives the opportunity to use checkboxes to let the user to select (or de-select) one or more rows.
Unfortunately the logic to understand what has been selected needs to be developed on the server side by your code.
The snippet of code below may give you some idea on how to manage it.
options(warn=-1)
library(rhandsontable)
library(shiny)
options(warn=-1)
quantity <- id <- 1:20
label <- paste0("lab","-",quantity)
pick <- FALSE
iris_ <- data.frame(id=id,pick=pick, quantity=quantity,label=label,iris[1:20,] ,stringsAsFactors = FALSE)
mtcars_ <- data.frame(id=id,pick=pick, quantity=quantity,label=label,mtcars[1:20,] ,stringsAsFactors = FALSE)
iris_$Species <- NULL # i.e. no factors
#---------------------------
ui <- fluidPage(
fluidRow(
column(6,rHandsontableOutput('demTb')),
column(3,uiOutput("demSli")),
column(3, radioButtons("inButtn", label=NULL, choices= c("iris","mtcars"), selected = "iris", inline = TRUE))
)
)
server <- function(session, input, output) {
selData <- ""
output$demSli <- renderUI({
if(is.null(input$demTb) ) return()
isolate({
df_ <- hot_to_r(input$demTb)
index <- which(df_$pick==T)
if(length(index)==0) return()
labs <- iris_$label[index]
pages <- "test"
iter <- length(labs)
buttn <- 1
valLabs <- sapply(1:iter, function(i) {
if(is.null(input[[paste0(pages,"d",labs[i],buttn)]] )) {
0
} else { as.numeric(input[[paste0(pages,"d",labs[i],buttn)]]) }
})
#
toRender <- lapply(1:iter, function(i) {
sliderInput(inputId = paste0(pages,"d",labs[i],buttn),
label = h6(paste0(labs[i],"")),
min = -100,
max = 100,
step = 1,
value = valLabs[i],
post="%",
ticks = FALSE, animate = FALSE)
})
})
return(toRender)
})
#--------------------
rds <- reactive({
# if( is.null(input$demTb) ) {
if( input$inButtn == "iris") {
if(selData == "" | selData == "mtcars") {
selData <<- "iris"
return(iris_) # first time for iris
}
} else {
if(selData == "iris" ) {
selData <<- "mtcars"
return(mtcars_) # first time for mtcars
}
}
df_ <- hot_to_r(input$demTb)
isolate({
index <- which(df_$pick==T)
if(length(index)==0) return(df_)
labs <- iris_$label[index]
pages <- "test"
iter <- length(labs)
buttn <- 1
}) # end isolate
valLabs <- sapply(1:iter, function(i) {
if(is.null(input[[paste0(pages,"d",labs[i],buttn)]] )) {
0
} else {
as.numeric(input[[paste0(pages,"d",labs[i],buttn)]])/100
}
})
dft_ <- data.frame(label=labs, multi=valLabs, stringsAsFactors = FALSE)
dft_ <- merge(iris_,dft_,by="label", all.x=T)
dft_$quantity <- sapply(1:length(dft_$quantity), function(z) {
if( is.na( dft_$multi[z]) ) {
dft_$quantity[z]
} else { iris_$quantity[z]*(1 + dft_$multi[z]) }
})
dft_[with(dft_,order(as.numeric(id))),]
df_[with(df_,order(as.numeric(id))),]
df_$quantity <- df_$quantity
return(df_)
})
output$demTb <- renderRHandsontable({
if(is.null(rds() )) return()
df_ <- rds()
df_ <- df_[with(df_,order(as.numeric(id))),]
rhandsontable(df_, readOnly = FALSE, rowHeaders= NULL, useTypes= TRUE) %>%
hot_table(highlightCol = TRUE, highlightRow = TRUE)
})
}
shinyApp(ui, server)

Resources