Using modals to display drill-through plots in Shiny modules

I am attempting to create a drill-through ggplot/ggiraph plot inside of modules, and would like to use a modal to display the resulting plot.

I have a basic example that almost works, but only for the first time I select a value on the plot. After that, the modal does not display a plot. I say it “almost” works because the plot does display in the modal, but it displays without the interactivity that it should have using ggiraph.

Any thoughts on how to display the plot in response to subsequent selections would be greatly appreciated.

library(shiny)
library(tidyverse)
library(ggiraph)

# Modal module UI
modalModuleUI <- function(id) {
  ns <- NS(id)
  tagList(
    ggiraphOutput(ns("mainplot"))
  )
}


plotModal <- function(session) {
  ns <- session$ns
  modalDialog(
    p("Cylinder Plot"),
   ggiraphOutput(ns("modalplot"))
  )
}


# Modal module server
modalModule <- function(input, output, session) {
  
  output$mainplot <-renderggiraph({
    
    p <- ggplot(mpg, aes( x = class, tooltip = class,
                          data_id = class ) ) +
      geom_bar_interactive()
    ggiraph(code = print(p), selection_type = "single")

  }) 
  
  output$modalplot <- renderggiraph({
   selected_class <-  input$mainplot_selected
   # selected_class <-  compact
   df <- mpg %>% 
     filter(class == selected_class)
   
   p <- ggplot(df, aes(x = cyl, tooltip = class))+
     geom_bar_interactive()
   
   ggiraph(code = print(p), selection_type = "single")
   
  })
  
  # open modal on plot click
  observeEvent(input$mainplot_selected,
               ignoreNULL = TRUE,  
               ignoreInit = TRUE,
               showModal(plotModal(session))
  )
  

}



# Main app UI
ui <- fluidPage(modalModuleUI("foo"))

# Main app server
server <- function(input, output, session) {
  callModule(modalModule, "foo")
}

shinyApp(ui, server)
```r

Does it work without modules? I'd recommend starting with a simpler case to figure out if the problem is with the module or with the modal.

Hmm. Good idea.
Turns out that I get the exact same behavior in a non-modularized shiny app.

I did some additional exploring in the non-modularized version. Found that if I converted the modal's ggiraph plot to a ggplot that the plot displayed without issues.

Appears that the primary issue is with displaying ggiraph in a modal. Any thoughts on why a ggplot would display as expected, but a ggiraph plot only displays the first time around?

I've pasted both versions (with ggiraph and with ggplot below).

App with ggiraph in modal. No module

library(shiny)
library(tidyverse)
library(ggiraph)

#function for calling the modal
plotModal <- function(session) {
  modalDialog(
    textOutput("modalText"),
   ggiraphOutput("modalplot")
  )
}


# Main app UI
ui <- fluidPage( ggiraphOutput("mainplot"))

# Main app server
server <- function(input, output, session) {
  
  #create main plot
  output$mainplot <-renderggiraph({
    
    p <- ggplot(mpg, aes( x = class, tooltip = class,
                          data_id = class ) ) +
      geom_bar_interactive()
    ggiraph(code = print(p), selection_type = "single")
    
  }) 
  
  #Create the drill-through plot
  output$modalplot <- renderggiraph({
    selected_class <-  input$mainplot_selected
    # selected_class <-  compact
    df <- mpg %>% 
      filter(class == selected_class)
    
    p <- ggplot(df, aes(x = cyl, tooltip = class))+
      geom_bar_interactive()
    
    ggiraph(code = print(p), selection_type = "single")
    
  })
  
  output$modalText <- renderText({
    selected_class <- input$mainplot_selected
    paste("You have selected", selected_class, ".")
  })
  
  # open modal on plot click using _selected
  observeEvent(input$mainplot_selected,
               ignoreNULL = TRUE,  
               ignoreInit = TRUE,
               showModal(plotModal(session))
  )
  
}

shinyApp(ui, server)

Version 2
App with ggplot in modal. No module This one works as expected.

library(shiny)
library(tidyverse)
library(ggiraph)

#function for calling the modal
plotModal <- function(session) {
  modalDialog(
    textOutput("modalText"),
   plotOutput("modalplot")
  )
}


# Main app UI
ui <- fluidPage( ggiraphOutput("mainplot"))

# Main app server
server <- function(input, output, session) {
  
  #create main plot
  output$mainplot <-renderggiraph({
    
    p <- ggplot(mpg, aes( x = class, tooltip = class,
                          data_id = class ) ) +
      geom_bar_interactive()
    ggiraph(code = print(p), selection_type = "single")
    
  }) 
  
  #Create the drill-through plot
  output$modalplot <- renderPlot({
    selected_class <-  input$mainplot_selected
    # selected_class <-  compact
    df <- mpg %>% 
      filter(class == selected_class)
    
    p <- ggplot(df, aes(x = cyl, tooltip = class))+
      geom_bar()
    
    p
  })
  
  output$modalText <- renderText({
    selected_class <- input$mainplot_selected
    paste("You have selected", selected_class, ".")
  })
  
  # open modal on plot click using _selected
  observeEvent(input$mainplot_selected,
               ignoreNULL = TRUE,  
               ignoreInit = TRUE,
               showModal(plotModal(session))
  )
  
}

shinyApp(ui, server)

Can you have a go at making your reprex a bit simpler still? Then I can take a look tomorrow.

Sure. I'll simplify a bit more.

Ok. I think this is about as simple as I can make it.
(edit) Thanks to David Gohel (author of ggiraph), I have a partial solution. The github/dev version of ggiraph has solved the issue of the modal plots failing to display after the first click.

I've added the call for the dev version of ggiraph in the reprex.

I'm still not getting interactivity in the modal plot (the class of automobile should display on mouseover).

library(shiny)
library(tidyverse)
devtools::install_github('davidgohel/ggiraph')
library(ggiraph)

# Main app UI
ui <- fluidPage( ggiraphOutput("mainplot"))

# Main app server
server <- function(input, output, session) {
  
  #create main plot
  output$mainplot <-renderggiraph({
    p <- ggplot(mpg, aes( x = class, tooltip = class,
                          data_id = class ) ) +
      geom_bar_interactive()
    ggiraph(code = print(p), selection_type = "single")
  }) 
  
  #Create the drill-through plot
  output$modalplot <- renderggiraph({
    df <- mpg %>% 
      filter(class == input$mainplot_selected)
    p <- ggplot(df, aes(x = cyl, tooltip = class))+
      geom_bar_interactive()
    ggiraph(code = print(p), selection_type = "single")
  })
  
  # open modal on plot click using _selected
  observeEvent(input$mainplot_selected,
               ignoreInit = TRUE,
               showModal(
                 modalDialog(ggiraphOutput("modalplot")
               ))
  )
}

shinyApp(ui, server)

The following is the solution from David Gohel (https://github.com/davidgohel/ggiraph/issues/150). Many thanks, David.

The code below is solving this. The modal is using a css property named z-index greater than the default one set by girafe ; it has to be set to a greater value than the modal one with girafe_options(z, opts_tooltip(zindex = 9999)) . Note I updated the code with girafe instead of ggiraph .

library(shiny)
library(tidyverse)
library(ggiraph)

#function for calling the modal
plotModal <- function(session) {
  modalDialog(
    textOutput("modalText"),
    ggiraphOutput("modalplot")
  )
}

# Main app UI
ui <- fluidPage( ggiraphOutput("mainplot"))

# Main app server
server <- function(input, output, session) {
  
  #create main plot
  output$mainplot <-renderggiraph({
    p <- ggplot(mpg, aes( x = class, tooltip = class,
                          data_id = class ) ) +
      geom_bar_interactive()
    ggiraph(code = print(p), selection_type = "single")
  }) 
  
  #Create the drill-through plot
  output$modalplot <- renderggiraph({
    selected_class <-  input$mainplot_selected
    # selected_class <-  compact
    df <- mpg %>% 
      filter(class == selected_class)
    
    p <- ggplot(df, aes(x = cyl, tooltip = class))+
      geom_bar_interactive()
    z <- girafe(code = print(p))
    girafe_options(z, opts_tooltip(zindex = 9999))
  })
  
  output$modalText <- renderText({
    selected_class <- input$mainplot_selected
    paste("You have selected", selected_class, ".")
  })
  
  # open modal on plot click using _selected
  observeEvent(input$mainplot_selected,
               ignoreNULL = TRUE,  
               ignoreInit = TRUE,
               showModal(plotModal(session))
  )
}

print(shinyApp(ui, server))
1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.