Динамическое изменение графиков на основе пользовательского ввода в Shiny
Я пытаюсь создать блестящее приложение, которое генерирует графики на основе выбора пользователем подмножества загруженного фрейма данных. Например, у меня есть следующий набор данных:
library(shiny)
library(data.table)
df <- rbind(
data.table( cat = rep('X', 40), grp = rep(LETTERS[1:4], each=10), x = rep(1:10, times=4), y = rnorm(40) ),
data.table( cat = rep('Y', 30), grp = rep(LETTERS[1:3], each=10), x = rep(1:10, times=3), y = rnorm(30) ),
data.table( cat = rep('Z', 20), grp = rep(LETTERS[4:6], each=10), x = rep(1:10, times=2), y = rnorm(20) )
)
На основании значения для cat
что пользователь выбирает в пользовательском интерфейсе, я хочу, чтобы блестящий производить графики для каждого значения grp
, Таким образом, если пользователь выбирает "X", то будет создано 4 графика; если они выбирают "Y", их будет три, а если они выбирают "Z", их будет 3.
Я также хочу указать, как генерируется каждый график на основе значения grp
, Так что если grp
A,D или E I хотят, чтобы он производил линейный график, в противном случае он должен создавать график рассеяния (только если это grp
имеет это значение, конечно).
Ниже приведен код для моего (сломанного) блестящего приложения:
server <- function(input, output) {
rv <- reactiveValues(
i = NULL,
df = NULL
)
observe({ rv$i <- input$i })
observe({ rv$df <- df[cat == rv$i] })
output$test <- renderUI({
plotList <- lapply( LETTERS[1:6], function(x) plotOutput(x) )
do.call( tagList, unlist(plotList, recursive=FALSE))
})
for(i in LETTERS[1:6]){
local({
my_i <- i
output[[my_i]] <- renderPlot({
if( my_i %in% c('A','D','E')) {
with(rv$df[grp == my_i], plot(x,y, type='l'))
} else {
with(rv$df[grp == my_i], plot(x,y))
}
})
})
}
}
ui <- fluidPage(
titlePanel('Title'),
sidebarLayout(
sidebarPanel(
helpText('Select the Category you would like to view.'),
selectInput('i', 'Category', c('X','Y','Z'), selectize=TRUE)
),
mainPanel(
uiOutput('test')
)
)
)
shinyApp(ui, server)
1 ответ
Воспроизводимый пример можно найти внизу.
Несколько подсказок:
1) Использование реактивных контекстов:
В вашем цикле for в нижней части кода сервера вы используете реактивную переменную rv
так что вам придется запускать код в реактивном контенте. Так что заверните это в observe()
,
2) Создайте список выходов:
Если я не ошибаюсь, вы использовали часть кода в этом ответе: динамически добавляйте графики на веб-страницу, используя глянцевый.
Это хорошая отправная точка. Для части списка тегов может быть проще упростить:
output$test <- renderUI({
lapply(unique(rv$df$grp), plotOutput)
})
Вы также можете добавить tagList()
, но это не обязательно здесь,...
3) Исправление данных выборки:
Вы можете обновить переменную df:
data.table(cat = rep('Z', 20), grp = rep(LETTERS[4:6], each=10),
x = rep(1:10, times=2), y = rnorm(20) )
Здесь у вас есть три буквы, так что вы можете изменить его на LETTERS[5:6]
или обновите другие номера.
Полный воспроизводимый пример:
library(shiny)
library(data.table)
df <- rbind(
data.table( cat = rep('X', 40), grp = rep(LETTERS[1:4], each=10), x = rep(1:10, times=4), y = rnorm(40) ),
data.table( cat = rep('Y', 30), grp = rep(LETTERS[1:3], each=10), x = rep(1:10, times=3), y = rnorm(30) ),
data.table( cat = rep('Z', 30), grp = rep(LETTERS[4:6], each=10), x = rep(1:10, times=3), y = rnorm(30) )
)
server <- function(input, output) {
rv <- reactiveValues(
i = NULL,
df = NULL
)
observe({ rv$i <- input$i })
observe({ rv$df <- df[cat == rv$i] })
observe({
for(letter in unique(rv$df$grp)){
local({
let <- letter
output[[let]] <- renderPlot({
if( let %in% c('A','D','E')) {
with(rv$df[grp == let], plot(x, y, type='l'))
} else {
with(rv$df[grp == let], plot(x,y))
}
})
})
}
})
output$test <- renderUI({
lapply(unique(rv$df$grp), plotOutput)
})
}
ui <- fluidPage(
titlePanel('Title'),
sidebarLayout(
sidebarPanel(
helpText('Select the Category you would like to view.'),
selectInput('i', 'Category', c('X','Y','Z'), selectize=TRUE)
),
mainPanel(
uiOutput('test')
)
)
)
shinyApp(ui, server)