Я работаю с пакетом в R под названием shinymaterial, который позволяет мне создавать приложения R Shiny с элементами материального дизайна. Один элемент, который мне нужно использовать, - это группа флажков, основанная на данных, загруженных пользователем. Однако в пакете shinymaterial еще не реализован флажок группы, только отдельные флажки. К сожалению, он замаскировал использование стандартных блестящих групп флажков R в процессе, поэтому я не могу просто вернуться к ним.
Мое лучшее решение - написать функцию, которая может программно генерировать серию отдельных флажков на основе входного вектора меток. Что я должен использовать для этого? или есть совершенно другой подход, который мог бы работать вместо этого?
Моя попытка решения - написать функцию, которая строит строку, содержащую команды для нескольких отдельных флажков (в основном с использованием paste0 и цикла for). Я планировал просто преобразовать эту строку в выражение, а затем преобразовать ее в eval. Однако, когда я это сделал (пример кода ниже), веб-страница Shiny просто отображает текст команды, а не выполняет ее как элемент пользовательского интерфейса.
materialCheckboxGroupGen <- function(idBase, choices, initials, color) {
#' Generate a group input made from several material_checkbox elements
#'
#' Generate shinymaterial checkboxGroupInput expression Use `eval` to run the expression in your app.
#' @param idBase String. Serves as a base for the inputId of the checkboxes; each checkbox's inputId will start with idBase and have a number appended.
#' @param choices A character vector containing the labels for each checkbox to be made, respectively.
#' @param initials A logical vector indicating the initial value for each checkbox to be made, respectively. Defaults to all FALSE, unchecked.
#' @param color A character vector containing the color for each checkbox to be made, respectively. \emph{This input requires using color hex codes, rather than the word form. E.g., "#ef5350", rather than "red lighten-1".}
#Setup
nBoxes <- length(choices)
if (missing(initials)) initials <- rep(FALSE, length.out = nBoxes)
command <- NULL
#Color will be recycled if it is not long enough
if (length(color) != nBoxes) {
color <- rep(x = color, length.out = nBoxes)
warning("Length of color input not the same as number of choices. Color vector recycled to match.")
}
#Loop to generate commands
for (i in 1:nBoxes) {
#Set up all the arguments
id <- paste0("\"", idBase, as.character(i), "\"")
lab <- paste0("\"", choices[i], "\"")
init <- as.character(initials[i])
col <- paste0("\"", color[i], "\"")
#Add a comma before all but the first checkbox
if (i != 1) command <- paste0(command, ", ")
#Add a new checkbox command to the end of the string
command <- paste0(command,
"material_checkbox(input_id = ", id,
", label = ", lab,
", initial_value = ", init,
", color = ", col,
")")
}
return(command)
}
#Example
materialCheckboxGroupGen(idBase = "testing", choices = c("Choice 1", "Choice 2", "Choice 3"), color = "#ef5350")
# [1] "material_checkbox(input_id = \"testing1\", label = \"Choice 1\", initial_value = FALSE, color = \"#ef5350\"), material_checkbox(input_id = \"testing2\", label = \"Choice 2\", initial_value = FALSE, color = \"#ef5350\"), material_checkbox(input_id = \"testing3\", label = \"Choice 3\", initial_value = FALSE, color = \"#ef5350\")"
#Bugs
#Merely wrapping the output of this function in eval(expression()) just renders the text of the output in the Shiny page, rather than executing it to create checkbox elements
Вот небольшой рабочий пример использования этой функции, показывающий, что вместо этого она отображает текст команды, а не флажки:
require(shiny)
require(shinymaterial)
ui <- material_page(
title = "Material Checkbox Groups",
material_row(
material_column(
width = 12,
material_card(
title = "Example",
eval(expression(materialCheckboxGroupGen(idBase = "testing", choices = c("Choice A", "Choice B", "Choice C"), color = "#EF5350")))
)
)
)
)
server <- function(input, output) {}
shinyApp(ui = ui, server = server)
Я подозреваю, что может быть альтернативный способ сделать это, возможно, с участием quote и substitute, как указано в этот ответ по соответствующему вопросу, но я не совсем знаком с этими командами.





Конструкция eval(parse(...)) работает нормально. Пусть вывод materialCheckboxGroupGen будет вектором (как объект out ниже), затем используйте eval(parse(...)). Вот минимальный рабочий пример:
library(shiny)
library(shinymaterial)
out <- c('material_checkbox(input_id = \"testing1\",
label = \"Foo\",
initial_value = FALSE,
color = \"#ef5350\")',
'material_checkbox(input_id = \"testing2\",
label = \"Bar\",
initial_value = FALSE,
color = \"#ef5350\")')
ui <- material_page(
title = "shinymaterial",
tags$br(),
material_row(
material_column(
width = 2,
material_card(
title = "",
depth = 4,
lapply(out, function(x) eval(parse(text = x)))
)
),
material_column(
width = 9,
material_card(
title = "Output here",
depth = 4
)
)
)
)
server <- function(input, output) {
NULL
}
shinyApp(ui, server)
Это дает вам
Дополнение. Обратите внимание, что в вашем приложении нет необходимости использовать конструкцию eval(parse(...)). Вот альтернативная реализация.
make_checkboxgroup - это функция, которая принимает вектор символов (например, c("foo", "bar") и возвращает список значений material_checkbox.
make_checkboxgroup <- function(x) {
lapply(seq_along(x), function(i) {
material_checkbox(input_id = paste0("var", i), label = x[i])
})
}
В объекте ui мы динамически генерируем флажки, указанные в этом примере, в виде строки меток, разделенных запятыми, предоставленных пользователем. На главной панели динамически отображается состояние каждого текстового поля.
ui <- material_page(
title = "shinymaterial",
tags$br(),
material_row(
material_column(
width = 3,
material_text_box("string", "Variables"),
uiOutput("checkboxes")
),
material_column(
width = 9,
material_card(
title = "Output here",
depth = 4,
htmlOutput("checkbox_status")
)
)
)
)
В server мы используем do.call(material_card, ...) для создания флажков. Мы используем renderUI для генерации вывода на главной панели.
server <- function(input, output) {
output$checkboxes <- renderUI({
X <- strsplit(input$string, ",")[[1]]
do.call(material_card, c(make_checkboxgroup(X), title = "", depth = 4))
})
output$checkbox_status <- renderUI({
X <- strsplit(input$string, ",")[[1]]
status <- sapply(paste0("var", seq_along(X)), function(i) input[[i]])
HTML(paste(X, status, collapse = '<br/>'))
})
}
shinyApp(ui, server)
Пример вывода:
Спасибо! Это отлично сработало! Чтобы упростить вызов, я также поместил lapply (output, function (x) eval (parse (text = x))) в качестве объекта, возвращаемого моей функцией materialCheckboxGroupGen.
(RE: Приложение) Я хотел бы проголосовать за ваш ответ во второй раз. Это гораздо более элегантное решение основной проблемы, с которой я столкнулся. Спасибо!
Я сделал это за тебя @twieg;)
Я бы посоветовал изменить заголовок вопроса на «Программное создание флажков в shinymaterial», поскольку это кажется более близким к цели вашего вопроса. См. Мой обновленный ответ о подходе, не основанном на
eval.