0

I want to create a shiny app that displays a variable (dynamic) number of ggplots, and I want to be able to rearrange (drag-and-drop) those ggplots. I looked at the manuals for the sortable package (sortable reference) and (sortable_js reference) but it is not clear how I should go about implementing this functionality in a shiny app.R file.

Here's a first attempt based on this post and this post but it doesn't work:


library(shiny)
library(tidyverse)
library(sortable)

# ui ---- 
ui <- fluidPage(

    # Application title
    titlePanel("the ggplot sorting app"),

    fluidRow(
      column(12, 
             uiOutput("plotCollection"))
    )
)

# server ---- 
server <- function(input, output) {
  plot_data <- mtcars
  
  output$plotCollection <- renderUI({
    n = nrow(plot_data)
    
    plot_output_list <- lapply(X=1:n, FUN=function(i) {
      plotOutput(paste0("plot", i), height = 80)
    })
    sortable_js(do.call(function(...) div(id="plotCollection", ...), plot_output_list))
  })
  
  # observers ---- 
  
  # generate multiple separate plots so they can be dragged-and-dropped
  observe({
    for(idx in 1:nrow(plot_data)) {
      local({
        local_id <- idx
        
        data_plot <- plot_data %>%
          slice(local_id)
        
        output[[paste0("plot", local_id)]] <- renderPlot({
          ggplot(data = data_plot, mapping = aes(x=disp, y=wt)) + 
            geom_point() + 
            labs(title = row.names(data_plot))
        })
      })
    }
  })
}

# Run the application 
shinyApp(ui = ui, server = server)


Brian D
  • 2,570
  • 1
  • 24
  • 43

1 Answers1

0

I sorted out (pun intended) that the sortable_js() call needed to be moved to the ui section, and the plots needed to be placed into a tagList. With those small changes, I now have a working example which can be saved as app.R and run as a standalone app.

The for() loop that generates the plots will take quite some time with a large number of plots and probably could be optimized further:

library(shiny)
library(tidyverse)
library(sortable)

# ui ---- 
ui <- fluidPage(
    titlePanel("the ggplot sorting app"),

    fluidRow(
      column(12, 
             uiOutput("plotCollection"),
             sortable_js("plotCollection"))
    )
)

# server ---- 
server <- function(input, output) {
  plot_data <- mtcars
  
  output$plotCollection <- renderUI({
    n = nrow(plot_data)
    
    plot_output_list <- lapply(X=1:n, FUN=function(i) {
      plotOutput(paste0("plot", i), height = 80)
    })
    do.call(tagList, plot_output_list)
  })
  
  # observers ---- 
  
  # generate multiple separate plots so they can be dragged-and-dropped
  # see: 
  observe({
    for(idx in 1:nrow(plot_data)) {
      local({
        local_id <- idx
        
        data_plot <- plot_data %>%
          slice(local_id)
        
        output[[paste0("plot", local_id)]] <- renderPlot({
          ggplot(data = data_plot, mapping = aes(x=disp, y=wt)) + 
            geom_point() + 
            labs(title = row.names(data_plot))
        })
      })
    }
  })
}

# Run the application 
shinyApp(ui = ui, server = server)

Brian D
  • 2,570
  • 1
  • 24
  • 43