Динамическое количество участков в гибкой разметке: ошибка при уменьшении количества участков - PullRequest
0 голосов
/ 27 апреля 2019

Я пытаюсь разработать новый способ создания переменного числа графиков на блестящей странице, и пока он движется в правильном направлении, но когда я уменьшаю количество графиков, я продолжаю печатать следующую ошибку в консоли

Предупреждение: ошибка в [[: нижний индекс за пределами [нет трассировки стека] имеется]

Это связано с тем, что что-то идет не так для графиков, которые больше не нужны, но я не могу найти, как избавиться от этой ошибки.

дизайн основан на: ТА вопрос

Я пытаюсь не допустить, чтобы мое приложение печатало какие-либо ошибки, и я задаюсь вопросом (а также научиться), как избавиться от ошибки «за пределами» в этом следующем приложении:

В настоящее время используется только фиктивная plots, прежде чем я вставлю свои действительные графики для тестирования

ПРЕДУПРЕЖДЕНИЕ, не использующее сеточные решения, потому что: Я планирую добавить кнопки над каждым графиком для параметров, удаления, сохранения и т. Д. - Я хочу, чтобы каждый plot масштабировался с svgpanzoom (невозможно с grid.arrange ggplot2, насколько я знаю

enter image description here требуют (блестящий)

ui <- shinyUI(fluidPage(
  uiOutput('plot_quantity_MSP_RawPlot'),
  uiOutput('plots')
))

server <- shinyServer(function(input, output) {
  values <- reactiveValues()


  output[['plot_quantity_MSP_RawPlot']] <- renderUI({ selectInput(inputId = item.name, label= 'Nr of plots',
                                                choices = 1:9,
                                                selected = 6)})




  observe({
    req(input$plot_quantity_MSP_RawPlot)
    values$plots <-
    lapply(1:input$plot_quantity_MSP_RawPlot, function(i){
    plot(runif(50),main=sprintf('Plot nr #%d',i))
    p <- recordPlot()
    plot.new()
    p
  })
  # values$plots <- plots
  })

  observe({
    req(input$plot_quantity_MSP_RawPlot)
    n <- input$plot_quantity_MSP_RawPlot
  values$n.col <- if(n == 1) {
    1
  } else if (n %in% c(2,4)) {
    2
  } else if (n %in% c(3,5,6,9)) {
    3
  } else {
    4
  }
  })

  output$plots <- renderUI({
  req(values$plots)
  col.width <- round(12/values$n.col) # Calculate bootstrap column width
  n.row <- ceiling(length(values$plots)/values$n.col) # calculate number of rows
  cnter <<- 0 # Counter variable

  # Create row with columns
  rows  <- lapply(1:n.row,function(row.num){
    cols  <- lapply(1:values$n.col, function(i) {
      cnter    <<- cnter + 1
      if(cnter <= input$plot_quantity_MSP_RawPlot) {
      plotname <- paste("plot", cnter, sep="")
      column(col.width, plotOutput(plotname, height = 280, width = 350))
      } else {
        column(col.width, br())
        }
    })
    fluidRow( do.call(tagList, cols), style = "width:1200px" )
  })
      do.call(tagList, rows)
  })

observe({
req(values$plots)
for (i in 1:length(values$plots)) {
  local({
    n <- i # Make local variable
    plotname <- paste("plot", n , sep="")
    output[[plotname]] <- renderPlot({
      suppressWarnings(values$plots[[n]])
    })
  })
}
})
})

shinyApp(ui=ui,server=server)

Ответы [ 2 ]

1 голос
/ 28 апреля 2019

Немного скорректировал ответ Алекса, чтобы немного улучшить автоматическую компоновку.

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')
    })
    })
  })
}

)
1 голос
/ 27 апреля 2019

Вам не нужен отдельный observe, поэтому я переписал код без него, основываясь на приведенном здесь примере - https://gist.github.com/wch/5436415/. Вы можете настроить количество столбцов, используя n_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)
...