在Shiny中展示动态UI元素并实现按行排布的问题咨询
解决方案
你可以通过以下两种常用方法实现指定每行动态绘图数量、自动换行的效果:
方法1:使用Shiny原生栅格系统
Shiny基于Bootstrap栅格布局,一行总宽度为12列,只需给每个plotOutput套对应宽度的column容器即可:
比如要实现每行3张图,每个图占4列(12/3=4),修改renderUI部分的代码即可:
output$plots <- renderUI({ plot_and_radio_output_list <- lapply(1:input$n, function(i) { plotname <- paste("plot", i, sep="") column(4, plotOutput(plotname, height = 280)) }) do.call(tagList, plot_and_radio_output_list) })
如果要每行2张图,把column(4, ...)改成column(6, ...)即可,以此类推。
方法2:使用CSS Flex布局(更灵活)
如果需要自定义间距、更灵活的适配规则,可以用flex布局给包裹容器加样式:
output$plots <- renderUI({ plot_and_radio_output_list <- lapply(1:input$n, function(i) { plotname <- paste("plot", i, sep="") div(plotOutput(plotname, height = 280, width = 250), style = "margin: 10px;") }) # 给外层容器加flex布局样式,自动换行 div(do.call(tagList, plot_and_radio_output_list), style = "display: flex; flex-wrap: wrap;") })
如果要固定每行数量,比如每行4个,给每个图的div加flex: 0 0 22%;(留一点空隙放间距)即可。
修改后的完整可运行代码(以flex布局为例)
library(shiny) max_plots <- 50 server <- function(input, output) { output$plots <- renderUI({ plot_and_radio_output_list <- lapply(1:input$n, function(i) { plotname <- paste("plot", i, sep="") div( plotOutput(plotname, height = 280, width = 250), style = "margin: 10px;" ) }) div( do.call(tagList, plot_and_radio_output_list), style = "display: flex; flex-wrap: wrap;" ) }) for (i in 1:max_plots) { local({ my_i <- i plotname <- paste("plot", my_i, sep="") output[[plotname]] <- renderPlot({ plot(1:my_i, 1:my_i, xlim = c(1, max_plots), ylim = c(1, max_plots), main = paste("1:", my_i, ". n is ", input$n, sep = "") ) }) }) } } ui <- pageWithSidebar( headerPanel("Dynamic number of plots"), sidebarPanel( sliderInput("n", "Number of plots", value=1, min=1, max=5) ), mainPanel( uiOutput("plots") ) ) shinyApp(ui, server)
内容的提问来源于stack exchange,提问作者Abdelouahed BEN MHAMED
相关产品推荐
相关产品推荐

