R 灵活布局中的动态打印数:减少打印数时出错

R 灵活布局中的动态打印数:减少打印数时出错,r,ggplot2,plot,shiny,R,Ggplot2,Plot,Shiny,我正在尝试设计一种新的方法,在一个闪亮的页面中创建一个可变数量的绘图,到目前为止它的方向是正确的,但是当我减少绘图数量时,我会在控制台中不断打印以下错误 警告:[]中出错:下标超出边界[无堆栈跟踪] 可用] 这与现在不再需要的绘图出错有关,但我不知道如何消除这个错误 设计基于: 我试图阻止我的应用程序打印任何错误,我想知道(也要学习)如何消除以下应用程序中的越界错误: 目前,在插入实际绘图进行测试之前,仅使用虚拟绘图 故意不使用网格排列解决方案,因为: 我计划在每个绘图上方添加按钮,用于选项、删

我正在尝试设计一种新的方法,在一个闪亮的页面中创建一个可变数量的绘图,到目前为止它的方向是正确的,但是当我减少绘图数量时,我会在控制台中不断打印以下错误

警告:[]中出错:下标超出边界[无堆栈跟踪] 可用]

这与现在不再需要的绘图出错有关,但我不知道如何消除这个错误

设计基于:

我试图阻止我的应用程序打印任何错误,我想知道(也要学习)如何消除以下应用程序中的越界错误:

目前,在插入实际绘图进行测试之前,仅使用虚拟
绘图

故意不使用网格排列解决方案,因为: 我计划在每个绘图上方添加按钮,用于选项、删除、保存等 -我想让每个
绘图
都可以用
svgpanzoom
缩放(用
网格是不可能的。据我所知,排列
ggplot2

需要(有光泽)


ui您不需要单独的
observe
,因此我根据这里的一个示例重新编写了没有它的代码-。您可以使用
n\u cols

  max_plots <- 10;
    n_cols = 3;

    server <- function(input, output) {
      output$plots <- renderUI({
        plot_output_list <- list()
        for(i in 1:ceiling(input$n/n_cols)) { 
          cols_ <- list();
          for(j in 1:round((input$n/n_cols - (i - 1))*n_cols)) {
            cols_ <- append(cols_,list(column(width = floor(12/n_cols), offset = 0, plotOutput(paste0("plot", (i-1)*n_cols+j)))));
          }
          plot_output_list <- append(plot_output_list, list(fluidRow(cols_, style = "width:1200px" )));
        }
        do.call(tagList, plot_output_list)
      })

      for (i in 1:max_plots) {
        local({
          my_i <- i; plotname <- paste0("plot", my_i)
          output[[plotname]] <- renderPlot({
            plot(1:my_i, 1:my_i, main = paste0("1:", my_i)
            )
          })
        })
      }
    }
    ui<- pageWithSidebar(
      headerPanel("Dynamic number of plots"),
      sidebarPanel(sliderInput("n", "Number of plots", value=1, min=1, max=max_plots)),
      mainPanel(uiOutput("plots")
      )
    )

    shinyApp(ui=ui,server=server)

max\u plots您不需要单独的
observe
,因此我根据这里的一个示例重新编写了没有它的代码-。您可以使用
n\u cols

  max_plots <- 10;
    n_cols = 3;

    server <- function(input, output) {
      output$plots <- renderUI({
        plot_output_list <- list()
        for(i in 1:ceiling(input$n/n_cols)) { 
          cols_ <- list();
          for(j in 1:round((input$n/n_cols - (i - 1))*n_cols)) {
            cols_ <- append(cols_,list(column(width = floor(12/n_cols), offset = 0, plotOutput(paste0("plot", (i-1)*n_cols+j)))));
          }
          plot_output_list <- append(plot_output_list, list(fluidRow(cols_, style = "width:1200px" )));
        }
        do.call(tagList, plot_output_list)
      })

      for (i in 1:max_plots) {
        local({
          my_i <- i; plotname <- paste0("plot", my_i)
          output[[plotname]] <- renderPlot({
            plot(1:my_i, 1:my_i, main = paste0("1:", my_i)
            )
          })
        })
      }
    }
    ui<- pageWithSidebar(
      headerPanel("Dynamic number of plots"),
      sidebarPanel(sliderInput("n", "Number of plots", value=1, min=1, max=max_plots)),
      mainPanel(uiOutput("plots")
      )
    )

    shinyApp(ui=ui,server=server)

max_plots稍微调整了Alex的答案,以稍微改进自动布局

max_plots <- 12;

shinyApp(
  ui<- pageWithSidebar(
    headerPanel("Dynamic number of plots"),
    sidebarPanel(width = 2, sliderInput("n", "Number of plots", value=1, min=1, max=max_plots),
                 h4("Clicked points"),
                 verbatimTextOutput("click_info"),
                 h4('click points to see info'),
                 h4('select area to zoom'),
                 h4('Double click to unzoom')
    ),
    mainPanel(uiOutput("plots")
    )
  ),
server <- function(input, output) {

  ranges <- reactiveValues()
  values <- reactiveValues()


  output$plots <- renderUI({
    plot_output_list <- list()
    n <- input$n

    n_cols <- if(n == 1) {
      1
    } else if (n %in% c(2,4)) {
      2
    } else if (n %in% c(3,5,6,9)) {
      3
    } else {
      4
    }
    Pwidth <- 900/n_cols
    Pheigth <- 600/ceiling(n/n_cols) # calculate number of rows

    for(i in 1:ceiling(input$n/n_cols)) { 
      cols_ <- list();
      for(j in 1:round((input$n/n_cols - (i - 1))*n_cols)) {
        # print((i-1)*n_cols+j)
        n <- (i-1)*n_cols+j
        cols_ <- append(cols_,list(column(width = floor(12/n_cols), offset = 0, 
                                          # uiOutput(paste('Button', n, sep = '')),  ## problem part
                                          plotOutput(paste0("plot", (i-1)*n_cols+j), width = Pwidth, height = Pheigth,
                                                     dblclick =  paste0("plot", (i-1)*n_cols+j, '_dblclick'),
                        click = paste0("plot", (i-1)*n_cols+j, '_click'),
                        brush = brushOpts(
                          id =  paste0("plot", (i-1)*n_cols+j, '_brush'),
                          resetOnNew = TRUE
                        ))
                        )));
      }
      plot_output_list <- append(plot_output_list, list(fluidRow(cols_, style = "width:1000px" )));
    }
    do.call(tagList, plot_output_list)
  })

  observe({
  lapply(1:input$n, function(i){

      plotname <- paste0("plot", i)
      output[[plotname]] <- renderPlot({
          ggplot(mtcars, aes(wt, mpg, color = as.factor(cyl))) + geom_point() +
          coord_cartesian(xlim =ranges[[paste('plot', i, 'x', sep = '')]], 
                          ylim = ranges[[paste('plot', i, 'y', sep = '')]], 
                          # expand = FALSE
                          ) +
          theme_classic() +
          theme(legend.text=element_text(size=12), 
                legend.title=element_blank()) 
        })
      })

  })
  # }



  output$click_info <- renderPrint({
    nearPoints(mtcars, input$plot1_click, addDist = TRUE)
  })


    # When a double-click happens, check if there's a brush on the plot.
    # If so, zoom to the brush bounds; if not, reset the zoom.

  lapply(1:max_plots, function(i){
    observeEvent(input[[paste('plot', i, '_dblclick', sep = '')]], {
                 brush <- input[[paste('plot', i, '_brush', sep = '')]]
                 if (is.null(brush)) {

                   ranges[[paste('plot', i, 'x', sep = '')]] <- NULL
                   ranges[[paste('plot', i, 'y', sep = '')]] <- NULL
                   values[[paste('brushedPoints', i, sep = '')]] <- NULL 
                 }
  })
})

  lapply(1:max_plots, function(i){
    observeEvent(input[[paste('plot', i, '_brush', sep = '')]], {
      brush <- input[[paste('plot', i, '_brush', sep = '')]]
      if (!is.null(brush)) {
        ranges[[paste('plot', i, 'x', sep = '')]] <- c(brush$xmin, brush$xmax)
        ranges[[paste('plot', i, 'y', sep = '')]] <- c(brush$ymin, brush$ymax)
        values[[paste('brushedPoints', i, sep = '')]] <- nrow(brushedPoints(mtcars[mtcars$cyl == 4],  input[[paste('plot', i, '_brush', sep = '')]]))
       }
    })
  })





  observe({
    lapply(1:input$n, function(i){

    output[[paste0('Button', i)]] <- renderUI({
      actionButton(inputId = paste0('button', i), label = 'x')
    })
    })
  })
}

)

max_plots稍微调整了Alex的答案,以稍微改进自动布局

max_plots <- 12;

shinyApp(
  ui<- pageWithSidebar(
    headerPanel("Dynamic number of plots"),
    sidebarPanel(width = 2, sliderInput("n", "Number of plots", value=1, min=1, max=max_plots),
                 h4("Clicked points"),
                 verbatimTextOutput("click_info"),
                 h4('click points to see info'),
                 h4('select area to zoom'),
                 h4('Double click to unzoom')
    ),
    mainPanel(uiOutput("plots")
    )
  ),
server <- function(input, output) {

  ranges <- reactiveValues()
  values <- reactiveValues()


  output$plots <- renderUI({
    plot_output_list <- list()
    n <- input$n

    n_cols <- if(n == 1) {
      1
    } else if (n %in% c(2,4)) {
      2
    } else if (n %in% c(3,5,6,9)) {
      3
    } else {
      4
    }
    Pwidth <- 900/n_cols
    Pheigth <- 600/ceiling(n/n_cols) # calculate number of rows

    for(i in 1:ceiling(input$n/n_cols)) { 
      cols_ <- list();
      for(j in 1:round((input$n/n_cols - (i - 1))*n_cols)) {
        # print((i-1)*n_cols+j)
        n <- (i-1)*n_cols+j
        cols_ <- append(cols_,list(column(width = floor(12/n_cols), offset = 0, 
                                          # uiOutput(paste('Button', n, sep = '')),  ## problem part
                                          plotOutput(paste0("plot", (i-1)*n_cols+j), width = Pwidth, height = Pheigth,
                                                     dblclick =  paste0("plot", (i-1)*n_cols+j, '_dblclick'),
                        click = paste0("plot", (i-1)*n_cols+j, '_click'),
                        brush = brushOpts(
                          id =  paste0("plot", (i-1)*n_cols+j, '_brush'),
                          resetOnNew = TRUE
                        ))
                        )));
      }
      plot_output_list <- append(plot_output_list, list(fluidRow(cols_, style = "width:1000px" )));
    }
    do.call(tagList, plot_output_list)
  })

  observe({
  lapply(1:input$n, function(i){

      plotname <- paste0("plot", i)
      output[[plotname]] <- renderPlot({
          ggplot(mtcars, aes(wt, mpg, color = as.factor(cyl))) + geom_point() +
          coord_cartesian(xlim =ranges[[paste('plot', i, 'x', sep = '')]], 
                          ylim = ranges[[paste('plot', i, 'y', sep = '')]], 
                          # expand = FALSE
                          ) +
          theme_classic() +
          theme(legend.text=element_text(size=12), 
                legend.title=element_blank()) 
        })
      })

  })
  # }



  output$click_info <- renderPrint({
    nearPoints(mtcars, input$plot1_click, addDist = TRUE)
  })


    # When a double-click happens, check if there's a brush on the plot.
    # If so, zoom to the brush bounds; if not, reset the zoom.

  lapply(1:max_plots, function(i){
    observeEvent(input[[paste('plot', i, '_dblclick', sep = '')]], {
                 brush <- input[[paste('plot', i, '_brush', sep = '')]]
                 if (is.null(brush)) {

                   ranges[[paste('plot', i, 'x', sep = '')]] <- NULL
                   ranges[[paste('plot', i, 'y', sep = '')]] <- NULL
                   values[[paste('brushedPoints', i, sep = '')]] <- NULL 
                 }
  })
})

  lapply(1:max_plots, function(i){
    observeEvent(input[[paste('plot', i, '_brush', sep = '')]], {
      brush <- input[[paste('plot', i, '_brush', sep = '')]]
      if (!is.null(brush)) {
        ranges[[paste('plot', i, 'x', sep = '')]] <- c(brush$xmin, brush$xmax)
        ranges[[paste('plot', i, 'y', sep = '')]] <- c(brush$ymin, brush$ymax)
        values[[paste('brushedPoints', i, sep = '')]] <- nrow(brushedPoints(mtcars[mtcars$cyl == 4],  input[[paste('plot', i, '_brush', sep = '')]]))
       }
    })
  })





  observe({
    lapply(1:input$n, function(i){

    output[[paste0('Button', i)]] <- renderUI({
      actionButton(inputId = paste0('button', i), label = 'x')
    })
    })
  })
}

)

max\u绘图嗯,我想我明白你为什么重写了几乎整个应用程序,但我通常不建议这样回答,因为如果你将解决方案隐藏在一个完整的代码转换之下,它可能不符合OPs最初的需要。然而,我确实找到了答案,并对你的答案做了一些更改,以使其正常工作。一件事是t您的答案不能以这种方式生成一个2*3的网格,因此我重新引入了代码来设置列的nr,就像我在问题中所做的那样。我将发布第二个答案来显示修改后的版本。谢谢Alex!亲爱的@Mark,如果您设置n_cols=3(我在我的答案中已经更改了它)你应该得到一个很好的2*3网格,不是吗?请看这里的屏幕截图:是的,但如果绘图的数量是8或4,它需要4列。别担心,我已经让它工作了。在我将我的代码版本发布到这里之前,我仍然在做一些编辑,但我仍然坚持在每个绘图上方放置额外的元素(请参阅更新的答案),当出现第二行绘图时,代码就会中断…嗯,我想我可以理解为什么你几乎重写了整个应用程序,但我通常不建议以这种方式回答,因为如果你将解决方案隐藏在完整的代码转换下,它可能不符合OPs的原始需要。不过,我确实找到了答案,并对你的应用程序进行了一些更改答案是这样的。有一点是,你的答案不能以这种方式生成一个漂亮的2*3网格,因此我重新引入了设置列数的代码,就像我在问题中所做的那样。我将发布第二个答案以显示修改后的版本。谢谢Alex!亲爱的@Mark,如果你设置n_cols=3(我在我的答案中更改了它)你应该得到一个很好的2*3网格,不是吗?请看这里的屏幕截图:是的,但如果绘图的数量是8或4,它需要4列。别担心,我已经让它工作了。在我将我的代码版本发布到这里之前,我仍然在做一些编辑,但我仍然坚持在每个绘图上方放置额外的元素(请参阅更新的答案),当出现第二行绘图时,代码将中断。。。