I am creating a shiny app that dynamically creates a set of input boxes, the input from those boxes is then used to further create another set of input boxes.
First I get input from the "number of questions" text box and dynamically add that number of "question panels" to the ui (example below).
Issue
The issue is that the generated objects are always attached to the output, and I can't figure out how to grab new user input from them. How could I get this input, and then generate a second round of "answer" input boxes?
ui.R
shinyUI(fluidPage(
titlePanel("RSurvey"),
numericInput("questionCountText", label = h3("Number of Questions"), value = 1),
uiOutput("questionSet")
))
server.R
shinyServer(
function(input, output) {
output[['questionSet']] <- renderUI({
outputHtml = ""
count = input$questionCountText
if(count > 0) {
for(i in 1:input$questionCountText) {
outputHtml = paste0(outputHtml, questionPanel(i))
}
}
HTML(outputHtml)
})
}
)
questionPanel = function(i)
{
return(wellPanel(div(style="display:inline-block", textInput("questionText", label = h4(paste0("Question ", i)), "Enter your question")),
numericInput1("answerCountText", label = h4("Number of Answers"), value = 3, onchange="onTextChanged(this.value)")))
}
numericInput1 = function (inputId, label, value = "", ...)
{
div(style="display:inline-block",
tags$label(label, `for` = inputId),
tags$input(id = inputId, type = "numeric", value = value, ...))
}
Hello try this for example :
#ui
ui <- fluidPage(
titlePanel("RSurvey"),
numericInput("questionCountText", label = h3("Number of Questions"), value = 1),
uiOutput("questionSet"),
verbatimTextOutput(outputId = "answers")
)
#server
server <- function(input, output) {
output[['questionSet']] <- renderUI({
outputHtml = ""
count = input$questionCountText
if(count > 0) {
for(i in 1:input$questionCountText) {
outputHtml = paste0(outputHtml, questionPanel(i))
}
}
HTML(outputHtml)
})
output$answers <- renderPrint({
invisible(
sapply(
X = seq_len(input$questionCountText),
FUN = function(i) {
cat(paste0("Question", i, "\n", input[[paste0("questionText", i)]], "\n", input[[paste0("answerCountText", i)]], "\n"))
}
)
)
})
}
#app
shinyApp(ui = ui, server = server)
#utils
questionPanel = function(i) {
wellPanel(
div(
style="display:inline-block",
textInput2(inputId = paste0("questionText", i), label = h4(paste0("Question ", i)), placeholder = "Enter your question")
),
numericInput1(inputId = paste0("answerCountText", i), label = h4("Number of Answers"), value = 3, onchange="onTextChanged(this.value)")
)
}
numericInput1 = function (inputId, label, value = "", ...) {
div(style="display:inline-block", class = "form-group shiny-input-container",
tags$label(label, `for` = inputId),
tags$input(id = inputId, type = "number", value = value, ...))
}
`%AND%` <- shiny:::`%AND%`
textInput2 <- function (inputId, label, value = "", placeholder = NULL, width = NULL)
{
if (is.null(placeholder)) {
div(class = "form-group shiny-input-container", style = if (!is.null(width))
paste0("width: ", validateCssUnit(width), ";"), label %AND%
tags$label(label, `for` = inputId), tags$input(id = inputId,
type = "text", class = "form-control", value = value))
} else {
div(class = "form-group shiny-input-container", style = if (!is.null(width))
paste0("width: ", validateCssUnit(width), ";"), label %AND%
tags$label(label, `for` = inputId), tags$input(id = inputId, placeholder = placeholder,
type = "text", class = "form-control", value = value))
}
Related
The below example code for selectizeGroupUI() works great for my needs. However by default when first invoking it selects and shows the entire dataset, before the user applies any filters.
My problem is the dataset I'm using this for is very large and takes some time to load. Is there a way to limit the initial dataset view to a subset of the data frame (in this example, manufacturer = Audi), and the user clicks another to-be-added button in order to show the complete dataset?
Example code:
library(shiny)
library(shinyWidgets)
data("mpg", package = "ggplot2")
ui <- fluidPage(
fluidRow(
column(
width = 10, offset = 1,
tags$h3("Filter data with selectize group"),
panel(
checkboxGroupInput(
inputId = "vars",
label = "Variables to use:",
choices = c("manufacturer", "model", "trans", "class"),
selected = c("manufacturer", "model", "trans", "class"),
inline = TRUE
),
selectizeGroupUI(
id = "my-filters",
params = list(
manufacturer = list(inputId = "manufacturer", title = "Manufacturer:"),
model = list(inputId = "model", title = "Model:"),
trans = list(inputId = "trans", title = "Trans:"),
class = list(inputId = "class", title = "Class:")
)
),
status = "primary"
),
DT::dataTableOutput(outputId = "table")
)
)
)
server <- function(input, output, session) {
vars_r <- reactive({
input$vars
})
res_mod <- callModule(
module = selectizeGroupServer,
id = "my-filters",
data = mpg,
vars = vars_r
)
output$table <- DT::renderDataTable({
req(res_mod())
res_mod()
})
}
shinyApp(ui, server)
Since we are dealing with a module (and the inputs are not directly accessible), I modified the function selectizeGroupServer To include an updater for manufacturer input. The new function is called selectizeGroupServer_custom
observe({
updateSelectInput(inputId = 'manufacturer', choices = unique(rv$data$manufacturer), selected = 'audi')
})
new module:
selectizeGroupServer_modified <-
function(input, output, session, data, vars)
{
`%inT%` <- function(x, table) {
if (!is.null(table) && ! "" %in% table) {
x %in% table
} else {
rep_len(TRUE, length(x))
}
}
ns <- session$ns
shinyWidgets:::toggleDisplayServer(session = session, id = ns("reset_all"),
display = "none")
rv <- reactiveValues(data = NULL, vars = NULL)
observe({
if (is.reactive(data)) {
rv$data <- data()
}
else {#this will be the first data
rv$data <- as.data.frame(data)
}
if (is.reactive(vars)) { #this will be the data type for vars
rv$vars <- vars()
}
else {
rv$vars <- vars
}
for (var in names(rv$data)) {
if (var %in% rv$vars) {
shinyWidgets:::toggleDisplayServer(session = session, id = ns(paste0("container-",
var)), display = "table-cell")
}
else {
shinyWidgets:::toggleDisplayServer(session = session, id = ns(paste0("container-",
var)), display = "none")
}
}
})
observe({
lapply(X = rv$vars, FUN = function(x) {
vals <- sort(unique(rv$data[[x]]))
updateSelectizeInput(session = session, inputId = x,
choices = vals, server = TRUE)
#CODE INSERTED HERE
if (x == 'manufacturer') {
updateSelectizeInput(session = session, inputId = x,
choices = vals, server = TRUE, selected = 'manufacturer')
}
})
})
observeEvent(input$reset_all, {
lapply(X = rv$vars, FUN = function(x) {
vals <- sort(unique(rv$data[[x]]))
updateSelectizeInput(session = session, inputId = x,
choices = vals, server = TRUE)
})
})
observe({
vars <- rv$vars
lapply(X = vars, FUN = function(x) {
ovars <- vars[vars != x]
observeEvent(input[[x]], {
data <- rv$data
indicator <- lapply(X = vars, FUN = function(x) {
data[[x]] %inT% input[[x]]
})
indicator <- Reduce(f = `&`, x = indicator)
data <- data[indicator, ]
if (all(indicator)) {
shinyWidgets:::toggleDisplayServer(session = session, id = ns("reset_all"),
display = "none")
}
else {
shinyWidgets:::toggleDisplayServer(session = session, id = ns("reset_all"),
display = "block")
}
for (i in ovars) {
if (is.null(input[[i]])) {
updateSelectizeInput(session = session, inputId = i,
choices = sort(unique(data[[i]])), server = TRUE)
}
}
if (is.null(input[[x]])) {
updateSelectizeInput(session = session, inputId = x,
choices = sort(unique(data[[x]])), server = TRUE)
}
}, ignoreNULL = FALSE, ignoreInit = TRUE)
})
})
observe({
updateSelectInput(inputId = 'manufacturer', choices = unique(rv$data$manufacturer), selected = 'audi')
})
return(reactive({
data <- rv$data
vars <- rv$vars
indicator <- lapply(X = vars, FUN = function(x) {
`%inT%`(data[[x]], input[[x]])
})
indicator <- Reduce(f = `&`, x = indicator)
data <- data[indicator, ]
return(data)
}))
}
app:
library(shiny)
library(shinyWidgets)
data("mpg", package = "ggplot2")
ui <- fluidPage(
fluidRow(
column(
width = 10, offset = 1,
tags$h3("Filter data with selectize group"),
panel(
checkboxGroupInput(
inputId = "vars",
label = "Variables to use:",
choices = c("manufacturer", "model", "trans", "class"),
selected = c("manufacturer", "model", "trans", "class"),
inline = TRUE
),
selectizeGroupUI(
id = "my-filters",
params = list(
manufacturer = list(inputId = "manufacturer", title = "Manufacturer:"),
model = list(inputId = "model", title = "Model:"),
trans = list(inputId = "trans", title = "Trans:"),
class = list(inputId = "class", title = "Class:")
)
),
status = "primary"
),
DT::dataTableOutput(outputId = "table")
)
)
)
server <- function(input, output, session) {
vars_r <- reactive({
input$vars
})
res_mod <- callModule(
module = selectizeGroupServer_modified,
id = "my-filters",
data = mpg,
vars = vars_r
)
output$table <- DT::renderDataTable({
res_mod()
})
}
shinyApp(ui, server)
EDIT:
If we want to have a button that says "show all data", we can modify selectizeGroupUI. The new name will be selectizeGroupUI_custom
Modules and App code:
library(shiny)
library(shinyWidgets)
# SERVER MODULE -----------------------------------------------------------
selectizeGroupServer_modified <-
function(input, output, session, data, vars) {
`%inT%` <- function(x, table) {
if (!is.null(table) && !"" %in% table) {
x %in% table
} else {
rep_len(TRUE, length(x))
}
}
ns <- session$ns
shinyWidgets:::toggleDisplayServer(
session = session, id = ns("reset_all"),
display = "none"
)
rv <- reactiveValues(data = NULL, vars = NULL)
observe({
if (is.reactive(data)) {
rv$data <- data()
} else { # this will be the first data
rv$data <- as.data.frame(data)
}
if (is.reactive(vars)) { # this will be the data type for vars
rv$vars <- vars()
} else {
rv$vars <- vars
}
for (var in names(rv$data)) {
if (var %in% rv$vars) {
shinyWidgets:::toggleDisplayServer(session = session, id = ns(paste0(
"container-",
var
)), display = "table-cell")
} else {
shinyWidgets:::toggleDisplayServer(session = session, id = ns(paste0(
"container-",
var
)), display = "none")
}
}
})
observe({
lapply(X = rv$vars, FUN = function(x) {
vals <- sort(unique(rv$data[[x]]))
updateSelectizeInput(
session = session, inputId = x,
choices = vals, server = TRUE
)
})
})
observeEvent(input$reset_all, {
lapply(X = rv$vars, FUN = function(x) {
vals <- sort(unique(rv$data[[x]]))
updateSelectizeInput(
session = session, inputId = x,
choices = vals, server = TRUE
)
})
})
observe({
vars <- rv$vars
lapply(X = vars, FUN = function(x) {
ovars <- vars[vars != x]
observeEvent(input[[x]],
{
data <- rv$data
indicator <- lapply(X = vars, FUN = function(x) {
data[[x]] %inT% input[[x]]
})
indicator <- Reduce(f = `&`, x = indicator)
data <- data[indicator, ]
if (all(indicator)) {
shinyWidgets:::toggleDisplayServer(
session = session, id = ns("reset_all"),
display = "none"
)
} else {
shinyWidgets:::toggleDisplayServer(
session = session, id = ns("reset_all"),
display = "block"
)
}
for (i in ovars) {
if (is.null(input[[i]])) {
updateSelectizeInput(
session = session, inputId = i,
choices = sort(unique(data[[i]])), server = TRUE
)
}
}
if (is.null(input[[x]])) {
updateSelectizeInput(
session = session, inputId = x,
choices = sort(unique(data[[x]])), server = TRUE
)
}
},
ignoreNULL = FALSE,
ignoreInit = TRUE
)
})
})
observe({
updateSelectInput(inputId = "manufacturer", choices = unique(rv$data$manufacturer), selected = "audi")
})
return(reactive({
data <- rv$data
vars <- rv$vars
indicator <- lapply(X = vars, FUN = function(x) {
`%inT%`(data[[x]], input[[x]])
})
indicator <- Reduce(f = `&`, x = indicator)
data <- data[indicator, ]
return(data)
}))
}
# UI MODULE ---------------------------------------------------------------
selectizeGroupUI_custom <-
function(id, params, label = NULL, btn_label = "Reset filters", inline = TRUE) {
ns <- NS(id)
if (inline) {
selectizeGroupTag <- tagList(
##### NEW LOCATION FOR THE BUTTON #####
actionButton(
inputId = ns("reset_all"), label = btn_label,
style = "float: left;"
##### NEW LOCATION FOR THE BUTTON #####
),
tags$b(label), tags$div(
class = "btn-group-justified selectize-group",
role = "group", `data-toggle` = "buttons", lapply(
X = seq_along(params),
FUN = function(x) {
input <- params[[x]]
tagSelect <- tags$div(
class = "btn-group",
id = ns(paste0("container-", input$inputId)),
selectizeInput(
inputId = ns(input$inputId),
label = input$title, choices = input$choices,
selected = input$selected, multiple = ifelse(is.null(input$multiple),
TRUE, input$multiple
), width = "100%",
options = list(
placeholder = input$placeholder,
plugins = list("remove_button"), onInitialize = I("function() { this.setValue(\"\"); }")
)
)
)
return(tagSelect)
}
)
)
)
} else {
selectizeGroupTag <- tagList(tags$b(label), lapply(
X = seq_along(params),
FUN = function(x) {
input <- params[[x]]
tagSelect <- selectizeInput(
inputId = ns(input$inputId),
label = input$title, choices = input$choices,
selected = input$selected, multiple = ifelse(is.null(input$multiple),
TRUE, input$multiple
), width = "100%", options = list(
placeholder = input$placeholder,
plugins = list("remove_button"), onInitialize = I("function() { this.setValue(\"\"); }")
)
)
return(tagSelect)
}
), actionLink(
inputId = ns("reset_all"), label = btn_label,
icon = icon("remove"), style = "float: right;"
))
}
tagList(
singleton(tagList(tags$link(
rel = "stylesheet", type = "text/css",
href = "shinyWidgets/modules/styles-modules.css"
), shinyWidgets:::toggleDisplayUi())),
selectizeGroupTag
)
}
# APP ---------------------------------------------------------------------
data("mpg", package = "ggplot2")
ui <- fluidPage(
fluidRow(
column(
width = 10, offset = 1,
tags$h3("Filter data with selectize group"),
panel(
checkboxGroupInput(
inputId = "vars",
label = "Variables to use:",
choices = c("manufacturer", "model", "trans", "class"),
selected = c("manufacturer", "model", "trans", "class"),
inline = TRUE
),
selectizeGroupUI_custom(
id = "my-filters",
params = list(
manufacturer = list(inputId = "manufacturer", title = "Manufacturer:"),
model = list(inputId = "model", title = "Model:"),
trans = list(inputId = "trans", title = "Trans:"),
class = list(inputId = "class", title = "Class:")
), btn_label = "Show all data"
),
status = "primary"
),
DT::dataTableOutput(outputId = "table")
)
)
)
########### SERVER###########
server <- function(input, output, session) {
vars_r <- reactive({
input$vars
})
res_mod <- callModule(
module = selectizeGroupServer_modified,
id = "my-filters",
data = mpg,
vars = vars_r
)
output$table <- DT::renderDataTable({
res_mod()
})
}
shinyApp(ui, server)
In shinywidgets::pickerInput you can pass a named list of data (here, nms) to pickerInput to create headings and choices from the list.
For example:
library(shiny)
library(shinyWidgets)
nms = list('Consumers' = c('a', 'b'),
'Firms' = c('c', 'd'))
ui <- fluidPage(
pickerInput(
inputId = "somevalue",
label = "A label",
choices = nms,
selected = 'a',
multiple=T
),
verbatimTextOutput("value")
)
server <- function(input, output) {
output$value <- renderPrint(input$somevalue)
}
shinyApp(ui, server)
I wish to replicate this heading/choices functionality using shinyWidgets::awesomeCheckboxGroup. Previously I posted this question seeking an answer and was advised that Map could do this. However, Map creates two input objects; I do not require this. The user's choices all need to be fed into a single input object.
Is it possible to create headings in awesomeCheckboxGroup while retaining a single input object?
I looked at the source code and modified awesomeCheckboxGroup and the underlying function generateAwesomeOptions to make it work. Now we can use named lists, which will create sub labels, and unnamed vectors, which will produce the normal checkboxes. We could still optimize the code a bit, and I am also not sure how the labels should look like. But basically you can give them a special class attribute and then use CSS to change the appearance of the labels.
library(shiny)
library(shinyWidgets)
generateAwesomeOptions2 <- function (inputId, choices, selected, inline, status, flag = FALSE) {
# if input is a list, flag will be set to `TRUE` by the calling function
if (flag) {
options <- mapply(choices, names(choices), FUN = function(lchoices, lname) {
lchoices <- shinyWidgets:::choicesWithNames(lchoices)
tags$div(
tags$label(lname, style = "margin-bottom: 10px;"),
mapply(lchoices, names(lchoices), FUN = function(value, name) {
inputTag <- tags$input(type = "checkbox", name = inputId,
value = value, id = paste0(inputId, value))
if (value %in% selected)
inputTag$attribs$checked <- "checked"
if (inline) {
tags$div(class = paste0("awesome-checkbox checkbox-inline checkbox-",
status), inputTag, tags$label(name, `for` = paste0(inputId,
value)))
}
# flag is not set `TRUE` this will create the normal checkboxes
else {
tags$div(class = paste0("awesome-checkbox checkbox-",
status), inputTag, tags$label(name, `for` = paste0(inputId,
value)))
}
}, SIMPLIFY = FALSE, USE.NAMES = FALSE)
)
}, SIMPLIFY = FALSE, USE.NAMES = FALSE)} else {
options <- mapply(choices, names(choices), FUN = function(value,
name) {
inputTag <- tags$input(type = "checkbox", name = inputId,
value = value, id = paste0(inputId, value))
if (value %in% selected)
inputTag$attribs$checked <- "checked"
if (inline) {
tags$div(class = paste0("awesome-checkbox checkbox-inline checkbox-",
status), inputTag, tags$label(name, `for` = paste0(inputId,
value)))
}
else {
tags$div(class = paste0("awesome-checkbox checkbox-",
status), inputTag, tags$label(name, `for` = paste0(inputId,
value)))
}
}, SIMPLIFY = FALSE, USE.NAMES = FALSE)
}
tags$div(class = "shiny-options-group", options)
}
awesomeCheckboxGroup2 <- function (inputId, label, choices, selected = NULL, inline = FALSE,
status = "primary", width = NULL) {
if(!is.list(choices)) {
choices <- shinyWidgets:::choicesWithNames(choices)
selected <- shiny::restoreInput(id = inputId, default = selected)
if (!is.null(selected))
selected <- shinyWidgets:::validateSelected(selected, choices, inputId)
options <- generateAwesomeOptions2(inputId, choices, selected,
inline, status = status)
} else {
choices2 <- unlist(unname(choices))
choices2 <- shinyWidgets:::choicesWithNames(choices2)
selected <- shiny::restoreInput(id = inputId, default = selected)
if (!is.null(selected))
selected <- shinyWidgets:::validateSelected(selected, choices2, inputId)
options <- generateAwesomeOptions2(inputId, choices, selected,
inline, status = status, flag = TRUE)
}
divClass <- "form-group shiny-input-container shiny-input-checkboxgroup awesome-bootstrap-checkbox"
if (inline)
divClass <- paste(divClass, "shiny-input-container-inline")
awesomeTag <- tags$div(id = inputId, style = if (!is.null(width))
paste0("width: ", validateCssUnit(width), ";"), class = divClass,
tags$label(label, `for` = inputId, style = "margin-bottom: 10px;"),
options)
shinyWidgets:::attachShinyWidgetsDep(awesomeTag, "awesome")
}
nms = list('Consumers' = c('a', 'b'),
'Firms' = c('c', 'd'))
nms1 = c("Test", "Test2")
ui <- fluidPage(
awesomeCheckboxGroup2(
inputId = "somevalue",
label = "Make a choice:",
choices = nms
),
verbatimTextOutput("value")
)
server <- function(input, output) {
output$value <- renderPrint(input$somevalue)
}
shinyApp(ui, server)
This code reads in the data, find unique values of a column (Location) and puts these values as options in the dropdown menu. My goal is to customize my data based on values that are chosen in the dropdown menu. My data looks like below:
I tried to view the data but I found it is not working properly. What should I do?
Update 1: The problem is in data()$Location == input$Locationscheck but I don't know how to fix it.
library(shiny)
dropdownButton <- function(label = "", status = c("default", "primary", "success", "info", "warning", "danger"), ..., width = NULL) {
status <- match.arg(status)
# dropdown button content
html_ul <- list(
class = "dropdown-menu",
style = if (!is.null(width))
paste0("width: ", validateCssUnit(width), ";"),
lapply(X = list(...), FUN = tags$li, style = "margin-left: 10px; margin-right: 10px;")
)
# dropdown button apparence
html_button <- list(
class = paste0("btn btn-", status," dropdown-toggle"),
type = "button",
`data-toggle` = "dropdown"
)
html_button <- c(html_button, list(label))
html_button <- c(html_button, list(tags$span(class = "caret")))
# final result
tags$div(
class = "dropdown",
do.call(tags$button, html_button),
do.call(tags$ul, html_ul),
tags$script(
"$('.dropdown-menu').click(function(e) {
e.stopPropagation();
});")
)
}
ui <- fluidPage(
fileInput(inputId = "uploadedcsv","", accept = '.csv'),
dropdownButton(label = "Choose the locations",status = "default",
width = 250,actionButton(inputId = "allLocations", label = "(Un)select all"),
checkboxGroupInput(inputId = "Locationscheck",label = "Choose",choices = "")),
actionButton('Run', label = "Run!")
)
server <- function(input, output, session) {
data <- reactive({
infile <- input$uploadedcsv
if (is.null(infile))
return(NULL)
read.csv(infile$datapath, header = TRUE, sep = ",")
})
observe({
locationnames <- unique(data()$Location)
updateCheckboxGroupInput(session, "Locationscheck",
choices = locationnames,
selected = locationnames)
### selecting and de-selecting in step 2 ###
observeEvent(input$allLocations, {
if (is.null(input$Locationscheck)) {
updateCheckboxGroupInput(session = session,
inputId = "Locationscheck",
selected = locationnames)
} else {
updateCheckboxGroupInput(session = session,
inputId = "Locationscheck",
selected = "")
}
})
### End of selecting and de-selecting ###
observeEvent(input$Run, {
Newdata <- data()[data()$Location == input$Locationscheck,]
View(data())
View(Newdata)
})
})
}
shinyApp(ui = ui, server = server)
The problem in the code data()$Location == input$Locationscheck is that it only considers first element in the input$Locationscheck vector and gives you the result as the values that are matched(eg: Location1) . You should use which(data()[data()$Location %in% input$Locationscheck,]) instead. which gives the indexes and %in% compares data()$Locationwith all the values in the input$Locationscheck vector.
I have modified your code and further added a table to illustrate the working:
library(shiny)
dropdownButton <- function(label = "", status = c("default", "primary", "success", "info", "warning", "danger"), ..., width = NULL) {
status <- match.arg(status)
# dropdown button content
html_ul <- list(
class = "dropdown-menu",
style = if (!is.null(width))
paste0("width: ", validateCssUnit(width), ";"),
lapply(X = list(...), FUN = tags$li, style = "margin-left: 10px; margin-right: 10px;")
)
# dropdown button apparence
html_button <- list(
class = paste0("btn btn-", status," dropdown-toggle"),
type = "button",
`data-toggle` = "dropdown"
)
html_button <- c(html_button, list(label))
html_button <- c(html_button, list(tags$span(class = "caret")))
# final result
tags$div(
class = "dropdown",
do.call(tags$button, html_button),
do.call(tags$ul, html_ul),
tags$script(
"$('.dropdown-menu').click(function(e) {
e.stopPropagation();
});")
)
}
ui <- fluidPage(
fileInput(inputId = "uploadedcsv","", accept = '.csv'),
dropdownButton(label = "Choose the locations",status = "default",
width = 250,actionButton(inputId = "allLocations", label = "(Un)select all"),
checkboxGroupInput(inputId = "Locationscheck",label = "Choose",choices = "")),
actionButton('Run', label = "Run!"),
tableOutput('table')
)
server <- function(input, output, session) {
data <- reactive({
infile <- input$uploadedcsv
if (is.null(infile))
return(NULL)
read.csv(infile$datapath, header = TRUE, sep = ",", stringsAsFactors = FALSE)
})
observe({
locationnames <- unique(data()$Location)
updateCheckboxGroupInput(session, "Locationscheck",
choices = locationnames,
selected = locationnames)
### selecting and de-selecting in step 2 ###
observeEvent(input$allLocations, {
if (is.null(input$Locationscheck)) {
updateCheckboxGroupInput(session = session,
inputId = "Locationscheck",
selected = locationnames)
} else {
updateCheckboxGroupInput(session = session,
inputId = "Locationscheck",
selected = "")
}
})
### End of selecting and de-selecting ###
observeEvent(input$Run, {
# Newdata <- data()[data()$Location == input$Locationscheck,]
Newdata <- data()[which(data()$Location %in% input$Locationscheck),]
# # View(data())
# View(Newdata)
output$table <- renderTable({
Newdata
})
})
})
}
shinyApp(ui = ui, server = server)
I suggest you useisolate when you access the value so that the reactive event is not triggered again and again, something like this Newdata <- isolate(data())[which(isolate(data())$Location %in% input$Locationscheck),]
Hope it helps!
The following attempts to put Shiny fileInput() and textInput() side by side.
A simple server.R file:
shinyServer(function(input, output) {} )
And the following ui.R:
# Custom function(s) to get file- and text-Input side by side
# Based on: <http://stackoverflow.com/a/21132918/1172302>
# options(shiny.error=browser)
# Globals
display.inline.block <- "display:inline-block"
class.input.small = "input-small"
FileInputId <- "SampleFile"
FileInputLabel <- "Sample"
TextInputId <- "SampleLabel"
TextInputLabel <- "Label"
TextInputLabelDefault <- "Sample Label"
# helper functions
fileInput.custom <- function (inputId, label, ...)
{
tagList(tags$label(label, `for` = inputId),
tags$input(id = inputId, type = "file", ...)
)
}
textInput.custom <- function (inputId, label, value = "",...)
{
tagList(tags$label(label, `for` = inputId),
tags$input(id = inputId, type = "text", value = value,...)
)
}
filetextInput <- function (fileId, fileLabel, textId, textLabel, textValue, divstyle, ...)
{
# sample file
div(style = divstyle,
fileInput.custom(inputId = fileId,
label = fileLabel,
class = class.input.small))
# label for sample, to be used in plot(s)
div(style = divstyle,
textInput.custom(inputId = textId,
label = textLabel,
value = textValue,
class = class.input.small))
}
# Shiny UI
shinyUI(
fluidPage(
# sample input
div(style = display.inline.block,
fileInput.custom(inputId = FileInputId,
label = FileInputLabel)
),
# label for sample
div(style = display.inline.block,
textInput.custom(inputId = TextInputId,
label = TextInputLabel,
value = TextInputLabelDefault)
),
hr(),
filetextInput(
fileId = FileInputId,
fileLabel = FileInputLabel,
textId = TextInputId,
textLabel = TextInputLabel,
textValue = TextInputLabelDefault,
divstyle = display.inline.block)
)
)
The above results in:
As shown in the screenshot, it works using two separate divs. Why doesn't it work in the case of the filetextInput() function?
Functions return the last evaluated value, so in your case the first part is lost. E.g. :
function(){
"a"
"b"
}
returns "b"
so you don't want that. Use a div or a tagList.
filetextInput <- function (fileId, fileLabel, textId, textLabel, textValue, divstyle, ...)
{
div(
# sample file
div(style = divstyle,
fileInput.custom(inputId = fileId,
label = fileLabel,
class = class.input.small)
),
# label for sample, to be used in plot(s)
div(style = divstyle,
textInput.custom(inputId = textId,
label = textLabel,
value = textValue,
class = class.input.small)
)
)
}
Is it possible to make a sliderInput that shows the values in decreasing order (from left to right; eg. 5 4 3 2 1)?
runApp(
list(
ui = fluidPage(
sliderInput("test","", min=5, max=1, value = 3, step=1)
),
server = function(input,output) {}
)
)
EDIT 2017-10-13: This function is now available in package shinyWidgets (with a different name : sliderTextInput()).
Hi you can write your own slider function like this (it's a little dirty...) :
sliderValues <- function (inputId, label, values, from, to = NULL, width = NULL) {
sliderProps <- shiny:::dropNulls(list(class = "js-range-slider",
id = inputId,
`data-type` = if (!is.null(to)) "double",
`data-from` = which(values == from) - 1,
`data-to` = if (!is.null(to)) which(values == to) - 1,
`data-grid` = TRUE,
`data-values` = paste(values, collapse = ", ")
))
sliderProps <- lapply(sliderProps, function(x) {
if (identical(x, TRUE))
"true"
else if (identical(x, FALSE))
"false"
else x
})
sliderTag <- div(class = "form-group shiny-input-container",
style = if (!is.null(width))
paste0("width: ", validateCssUnit(width), ";"),
if (!is.null(label))
shiny:::controlLabel(inputId, label), do.call(tags$input,
sliderProps))
dep <- list(htmltools::htmlDependency("ionrangeslider", "2.0.12", c(href = "shared/ionrangeslider"),
script = "js/ion.rangeSlider.min.js",
stylesheet = c("css/ion.rangeSlider.css",
"css/ion.rangeSlider.skinShiny.css")))
htmltools::attachDependencies(sliderTag, dep)
}
The point to do this is to use the values attribute from ionrangeslider (see section Using custom values array here)
The downside is the value of the input you retrieve server-side isn't the value of the slider but the index of the value (starting from 0).
You can use this function like this :
library("shiny")
runApp(
list(
ui = fluidPage(
# you have to pass the values you want in the slider directly to th function
sliderValues(inputId = "test", label = "", from = 5, values = 5:1),
verbatimTextOutput(outputId = "slidervalue")
),
server = function(input,output) {
output$slidervalue <- renderPrint({
# Careful ! : input$test isn't the expected value !!!
(5:1)[input$test + 1]
})
}
)
)
And bonus : it works with characters vectors too :
runApp(
list(
ui = fluidPage(
sliderValues(inputId = "test", label = "", from = "g", to = "o", values = letters),
verbatimTextOutput(outputId = "slidervalue")
),
server = function(input,output) {
output$slidervalue <- renderPrint({
# Careful ! : input$test isn't the expected value !!!
letters[input$test + 1]
})
}
)
)