Issue with using reset (shinyJS function) and click together and then observing the clicked button - shinyjs

Problem statement: on click of a button (say reset), we need to reset some controls and then programmatically click another button (in this case update) and perform some logic and render appropriately.
In the below example, I do the following
On click of the reset button, I am resetting the picker input using the reset function and then calling click on "update" button.
Expected
on click of reset, both the text should be NULL
What Happens is :
The first one is NUll, the second one is the last value
I Would like to understand the reason behind it. Interestingly when we debug, it works as expected. Is there a workaround to achieve something like this?
library(shiny)
library(shinyWidgets)
library(shinyjs)
options(shiny.reactlog=TRUE)
# if (interactive()) {
# library(shiny)
shinyApp(
ui = fluidPage(
useShinyjs(),
div(
id = "form",
pickerInput(
inputId = "letter",
label = "Select max two option below:",
choices = c("A", "B", "C", "D"),
multiple = TRUE,
selected = NULL,
options = list(`actions-box` = TRUE)
),
verbatimTextOutput("selected_value"),
verbatimTextOutput("reset_value"),
),
actionButton("reset", "Reset"),
actionButton("update", "Update"),
),
server = function(input, output) {
msg <- "temp reactive"
msg_reactive <- reactiveValues(text = msg)
output$reset_value <- renderPrint(msg_reactive$text)
output$selected_value <- renderPrint(input$letter)
observeEvent(input$reset, {
reset("letter")
click("update")
})
observeEvent(input$update,{
## some logic , currently just setting it to current value of drop down letters
## I assume click on line number 52 triggers the control to come here
## but still values in input$letter are older onces and not NULL
## if I use a browser and then executes it works , Not sure where I am falling short
msg_reactive[['text']] <- input$letter
})
}
)
# }

Related

GAS: copy one data validation (dropdown) in N number of rows and set unique value in each dropdown

Edited for clarity and to add images
Using Google Apps Script, how can I:
copy a range from Section 2 sheet (G11:H11, with a checkbox & dropdown) into range G12:G25 N number of times (based on the number of non-empty rows in MASTER DROPDOWN sheet under same header title as 'Section 2'!A2) and then,
set a different value in each dropdown (each unique value listed in MASTER DROPDOWN sheet under the correct header).
For example, first image is "MASTER DROPDOWN" sheet.
This second image is "Section 2" sheet. The user can add or delete items on the list using the buttons on the right side of the page.
And this last image is "Section 2" sheet. I cannot understand how to write the code for this... When user presses "Reset list" button, I want to copy checkbox and dropdown menu (from G11:H11) N number of times (N=3 based on number of items from MASTER DROPDOWN under Section 2). In each dropdown, I want to set value with each item from the original list in the MASTER DROPDOWN sheet. This process should be dynamic and work on Section 1 and Section 3 sheet (not in worksheet currently).
Any advice on the script verbage to search/learn about this type of functionality, or some direction on the script for this is much appreciated. Here's a link to my code that I have so far...
https://docs.google.com/spreadsheets/d/1ZdlJdhA0ZJOIwLA9dw5-y5v1FyLfRSywjmQ543EwMFQ/edit?usp=sharing
function newListAlert (){
var ui = SpreadsheetApp.getUi();
var response = ui.alert("Are you sure you want to delete your current list and create a new one?",ui.ButtonSet.YES_NO);
if(response == ui.Button.YES) {
newList();
} else {
}
}
function newList() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var range = ss.getRange("G11:H25");
var options = {contentsOnly: true, validationsOnly: true};
//clear current list
range.clear(options);
//add new item to list in first row of range
addNewItem();
//copy new datavalidation row above based on number of non-empty rows in MASTER DROPDOWN with same header as active sheet (-1)
var datass = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("MASTER DROPDOWN");
var range = ss.getRange("A2");
if (range.getCell(1,1)){
var section = datass.getRange(1,1,1,datass.getLastColumn()).getValues();
var sectionIndex = section[0].indexOf(range.getValue()) + 1;
var validationRange = datass.getRange(4,sectionIndex,19);//19 columns: checklist has a maximum of 18 rows (+ 1 for "select option")
}
}
In your situation, how about modifying newList() as follows?
Modified script:
function newList() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var sheetName = sheet.getSheetName();
sheet.getRange("G11:H25").clear({ contentsOnly: true, validationsOnly: true });
var srcSheet = ss.getSheetByName("MASTER DROPDOWN");
var values = srcSheet.getDataRange().getValues();
var obj = values[0].map((_, c) => values.map(r => r[c])).reduce((o, [h, , , ...v], i) => {
if (h != "") {
v = v.filter(String);
v.shift();
o[h] = { values: v, range: srcSheet.getRange(4, i + 1, v.length + 1) };
}
return o;
}, {});
if (obj[sheetName]) {
var validationRule = SpreadsheetApp.newDataValidation()
.setAllowInvalid(false)
.setHelpText('Select an option from the menu. To add more options to the dropdown list, go to MASTER DROPDOWN tab.')
.requireValueInRange(obj[sheetName].range, true)
.build();
var d = obj[sheetName].values.map(_ => [validationRule]);
var v = obj[sheetName].values.map(e => [e]);
sheet.getRange(sheet.getLastRow() + 1, 8, obj[sheetName].values.length).setDataValidations(d).setValues(v).offset(0, -1).insertCheckboxes();
}
}
When this script is run, the values for DataValidations are retrieved from the sheet "MASTER DROPDOWN", and using the sheet name, the dataValidation rules are created, and put to the column "H". And also, the checkboxes are put to the column "G" of the same rows of the dataValidations.
In this case, for example, when you add a new sheet of "Section 1" and run newList(), the dropdown list including "Engineering" and "Design" is put to the column "H" and the checkboxes are also put to the column "G".
Note:
In this modification, the sheet name like "Section 2" is used for searching the column of "MASTER DROPDOWN" sheet. So please be careful about this.
And, from your current script, the last row is used for putting to the dropdown list and checkboxes. So when you want to modify this, please modify the above script.
This sample script is for your sample Spreadsheet. So when your actual Spreadsheet is changed, this script might not be able to be used. Please be careful this.
References:
setDataValidations(rules)
insertCheckboxes()

plot.CA() renders in shiny app locally but not when app is deployed

I have created a Shiny app that takes user input and creates a CA plot. It works just fine when I run the app locally, but for some reason when I deploy the dashboard, the image of the plot won't appear. I can see in the logs that the data uploading and reformatting into a proper data frame is working just fine, but the plot itself is failing to render.
Does anyone know why this might be? I posted my code below (you'll see some print() lines in my code that was used for debugging). Any help would be greatly appreciated!
#PERCEPTUAL MAPPING DASHBOARD
library(FactoMineR)
library(factoextra)
library(SensoMineR)
library(shinythemes)
library(ca)
ui <- fluidPage(theme = shinytheme("darkly"),
# Application title
titlePanel("Perceptual Map Dashboard"),
sidebarLayout(
# Sidebar with a slider and selection inputs
sidebarPanel(
#Excel doc row and column names
numericInput(inputId="startcol",label="Input start column of CSV file:",value="", min=1,max=10000),
numericInput(inputId="endcol",label="Input end column of CSV file:",value="", min=1,max=10000),
#Inputing brands and emotions
br(),
numericInput(inputId = "rownums",label = "How many emotions/characteristics are you evaluating?",value = "", min = 1,max = 10000),
br(),
h6("Note: Please enter brands and emotions/characteristics in the order that they appear in the excel document exported from Survey Gizmo."),
textInput ( 'brands', 'List the brands included in your perceptual map (separated by commas):', value=""),
textInput ( 'emotions', 'List the emotions/characteristics included in your perceptual map (separated by commas):', value=""),
#Removing brands and emotions
#Select graph type
textInput(inputId="plottitle",label="Title your graph:"),
#Upload Excel Grid
fileInput(inputId = 'data', 'Upload CSV File',
accept=c('.csv')),
actionButton("go","Create Map")
),
# Visual Output
mainPanel(
wellPanel(h4('Visual'),
h5("Once your visual appears, just right click it to save it as a .png file.")),
plotOutput(outputId = "plot", width = "100%", height=500)
# downloadButton("downloadPlot", "Download Visual")
)
)
)
server <- function(input,output){
K <- eventReactive(input$go,{
x <- read.csv(input$data$datapath, header = F)
x[!is.na(x)] <- 1
x[is.na(x)] <- 0
x<-x[,as.numeric(input$startcol):as.numeric(input$endcol)]
column.sums<-colSums(x)
print(column.sums)
pmd.matrix<-matrix(column.sums, byrow = T, nrow=as.numeric(input$rownums))
pmd.df2<-as.data.frame(pmd.matrix)
colnames(pmd.df2) = unlist(strsplit(as.character(input$brands),","))
print(pmd.df2)
row.names(pmd.df2)= unlist(strsplit(as.character(input$emotions),","))
print(pmd.df2)
pmd.df2[-nrow(pmd.df2),]
print(pmd.df2)
fit <- CA(pmd.df2, graph=F)
return(fit)
})
p <- eventReactive(input$go,{
input$plottitle
})
output$plot<- renderPlot({
plot.CA(K(), col.row = "blue", col.col="black", cex=1, new.plot=T,
title=p())
})
}
shinyApp(ui = ui, server = server)
What I suggest to you is to check whether this issue is specific to your plot or if plot.CA is not working with shiny in general. Try to "deploy" (apparently, you don't use a webserver?) the following app
library(FactoMineR)
library(shiny)
data(children)
res.ca <- CA(children, col.sup = 6:8, row.sup = 15:18)
shinyApp(
fluidPage(plotOutput("plot")),
function(input, output, sesison) {
output$plot <- renderPlot({
plot.CA(res.ca)
})
}
)
If this does work, there might be something wrong with your model or maybe there are name collusions between the ca package and the FactorMineR package.
If this does not work, try the following instead
## use same data/libraries as above
myfile <- tempfile(fileext = ".png")
shinyApp(
fluidPage(imageOutput("plot")),
function(input, output, sesison) {
output$plot <- renderImage({
png(file = myfile)
plot.CA(res.ca)
dev.off()
list(src = myfile)
}, deleteFile = FALSE)
}
)
And see
Whether the app works now
Whether myfile gets created and contains reasonable contents.

To allow multi select in Rhandsontable column dropdown

I am trying to build a application in R shiny, where I am using a handsontable to take inputs from users. One column in my handsontable is having dropdowns where I need multiple selection from the user.
For example in my below sample code, I want to allow user to select multiple values in 'big' column (i.e. user should be able to select A,B,C for first row and likewise for other rows)
library(shiny)
library(rhandsontable)
shinyApp(
ui = fluidPage(
fluidRow(
column(12,
sliderInput('input', label = "Rows",
min = 1, max = nrow(iris), value = 10)
),
column(12
,
rHandsontableOutput('table')
)
)
),
server = function(input, output) {
DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
small = letters[1:10],
dt = seq(from = Sys.Date(), by = "days", length.out = 10),
stringsAsFactors = FALSE)
# try updating big to a value not in the dropdown
output$table <- renderRHandsontable(
rhandsontable(DF, rowHeaders = NULL, width = 550, height = 300) %>%
hot_col(col = "big", type = "dropdown", source = LETTERS) %>%
hot_col(col = "small", type = "autocomplete", source = letters,
strict = FALSE)
)
}
)
Let me know if anyone has faced the same problem and resolved the same.
Your question is a bit confusing for me, you want that the slider reacts to how many selected options do the user put or...?
Then I don't know why you put max = nrow(iris) if you are not using the iris dataframe, that makes no sense.
Finally if you want to have a reactive UI so when the user put something, the ui change, you will need this:
1- The reactive function for server:
`outSli <- reactive({
##here you put your action
})`
2- The observe function for server to change the ui slider:
`observe({
##here you put the outSli() that contains your action or algorithm and then you update the slider
updateSliderInput(session, "input", label = NULL, value = NULL,
min = NULL, max = NULL, step = NULL)
##all those NULLs is what you change with your outSli()
})`
I hope it helps.

Accessing Dynamic Data from Drop down box in Shiny

I am creating a shiny dashboard wherein I need to dynamically update information based on an option in a drop down box.
My question is 1. can this be done, and if so: how?
I have created my drop down menu, which works fine, from there I want to same something along the lines of "if outlet xyz is picked, update charts with unique information"
Code thus far:
output$Box1 = renderUI(
selectInput("Outlets",
"Select an Outlet",
c("Start Typing Outlet
Name",as.character(unique(outlets$Outlets))),
"selectoutlet"))
once the outlet has been selected, I want the data in my R script to only update for that one outlet.
As You havent supplied reproducible example, here is the code with mtcars dataset:
library(shiny)
library(dplyr)
library(ggplot2)
ui= fluidPage(
sidebarLayout(
sidebarPanel(
selectInput(inputId= "cyl", label= "cyl",
choices= unique(mtcars$cyl),
selected= sort(unique(mtcars$cyl))[1],
multiple=F)
),
mainPanel(
plotOutput("plot")
)
)
)
server= function(input, output,session) {
df_filtered <-reactive({
data <- mtcars %>% {if (is.null(input$cyl)) . else filter(., cyl %in% input$cyl)} # here is the reactive dataset which You can further use it in table or in the plot
print(data)
data
})
output$plot <- renderPlot({
ggplot(data = df_filtered(), aes(x=cyl,y=mpg)) + geom_point(size=5) # as You can see i have used data = df_filtered()
})
}
shinyApp(ui, server)
Have a look at the comments in the code to get some better idea how it works.

observeEvent (and eventReactive) not performing as expected

I am having problems making a reactive app to show the map of a given state. I want the app to react ONLY WHEN I click "Show map", but for some reason with the following code, after the first click on "Show map", the output changes whenever I change the input (state), whether or not I click the button again.
library(shiny)
ui <- fluidPage(
titlePanel("Show map of a given state"),
sidebarLayout(
sidebarPanel(
textInput("state", label = "State", value = "CA", placeholder = "California or CA"),
actionButton("showU","Show map")
),
mainPanel(
conditionalPanel(
condition = "input.showU > 0",
h3(textOutput("state")),
uiOutput("url")
)
)
)
)
server <- function(input, output){
observeEvent(input$showU,{
output$state <- renderText(paste("Map of", input$state, ":"))
output$url <-renderUI({a(href=paste("https://www.google.com/maps/place/", input$state, sep=""),"Show in Google Map",target="_blank")})
})
#output$state <- eventReactive(input$showU, renderText(paste("Map of", input$state, ":")))
#output$url <- eventReactive(input$showU, renderUI({a(href=paste("https://www.google.com/maps/place/", input$state, sep=""),"Show in Google Map",target="_blank")}))
}
shinyApp(ui,server)
I thought observeEvent or eventReactive (the code that's commented out; doesn't work either) is supposed to delay reaction until I click the action button but it's not doing that. Can anybody help me figure out what is wrong here? Thank you!
It's because you call input$xxx within renderYYY. You can use isolate():
observeEvent(input$showU,{
output$state <- renderText(paste("Map of", isolate(input$state), ":"))
output$url <-renderUI({a(href=paste("https://www.google.com/maps/place/", isolate(input$state), sep=""),"Show in Google Map",target="_blank")})
})

Resources