Unable to edit plotly_build when it's a reactive object in a R Shiny

I am trying to access the plotly_build of a reactive plot to manually edit the default plotly components to further customize my plot. I am able to do this in a plain .R script to test the functionality of the edits to the build, but I’ve been unsuccessful in getting it to work in an R Shiny that I am creating that involves a reactive plot.

The tab on the Shiny that is is on involves a selectizeInput() for a feature that the user choose, which the Shiny uses to filter a data frame and produce a plot accordingly. That being said, the graphing became a bit messy on both the ggplot and plotly side (using ggplotly to transform to plotly). I ultimately customized the ggplot as much as I could, but through plotly_build(), I manually accessed the plotly components to edit things like the legend labels and title.

In testing outside of the Shiny, I was able to create this plot by manually changing the filter feature. Within the Shiny, however, since there is a user input that drives the reactive plot, this created a huge cascade of issues.

Here is a simplified sample of my attempt at it:

library(shiny)
library(dplyr)
library(readr)
library(ggplot2)
library(plotly)
library(scales)
library(kableExtra)

ui <- fluidPage(

    # Application title
    titlePanel("DASHBOARD TITLE"),

    mainPanel(
       tabsetPanel(
          tabPanel("DATA PLOTS", 
                   selectizeInput("srvr", label = "Name", choices=NULL, options = list(placeholder = 'Search for a Name')),
                   plotlyOutput("entrance_exit_npl_plotly"))
        )
      )
)

server <- function(input, output, session) {

  entrance_exit_table_npl <- readRDS(file='path/filename.rds')

  updateSelectizeInput(session, 'srvr', choices = c(unique(entrance_exit_table_npl$ENTITYNM)), selected = 'DEFAULT OPTION',server = TRUE)

  # Storing user input$srvr
  selected_srvr <- reactive({as.character(input$srvr)})

  # Filtering based on user input
  servicer_data_npl <- reactive({
    filter(entrance_exit_table_npl, ENTITYNM==selected_srvr()) %>% 
      group_by(P_ENTITY, LN_CURR_ACVY_STRT_DT) %>% 
      select(contains("upb"))})

  # Creating ggplot object and attempt to capture plotly_build
  plot_servicer_build <- reactive({
    plotly_build(
        ggplot(servicer_data_npl(), aes(LN_CURR_ACVY_STRT_DT)) + 
        geom_line(aes(y=new_npl_entrance_upb, color = 'green', linetype = 'dotted')) +
        geom_line(aes(y=from_rpl_entrance_upb, color = 'green',linetype = 'dashed')) +
        geom_line(aes(y=total_entrance_upb, color = 'green', linetype = 'solid')) +
        geom_line(aes(y=npl_liqd_exit_upb, color = 'red', linetype = 'dotted')) +
        geom_line(aes(y=to_rpl_exit_upb, color = 'red', linetype = 'dashed')) +
        geom_line(aes(y=total_npl_exit_upb, color = 'red', linetype = 'solid')) +
        geom_line(aes(y=total_npl_upb, color = 'blue', linetype = 'dotdash')) +
        scale_y_continuous("UPB (Millions)",
                           labels = unit_format(unit = "M", big.mark = ",")) +
        scale_x_date("Activity Month",
                     breaks = date_breaks("1 month"),
                     date_labels = "%b-%Y",
                     expand = c(0,0)) +
        theme(plot.title = element_text(hjust = 0.5),
              axis.text.x = element_text(angle = 45)) +
        ggtitle(paste(selected_srvr(),"NPL Entrance and Exits")) +
        scale_color_identity(guide='legend') +
        scale_linetype_identity(guide='legend')
   )
 })

  # Editing plotly build. What I would like to happen, but will not work. This could also use the $ notation for subsetting, but this is how I did it to the plotly_build() list object outside of the Shiny. First, editing legend entry names, and second, removing the title of the legend.
    # plot_servicer_build[["x"]][["data"]][[1]][["name"]] <- "Entry Name 1"
    # plot_servicer_build[["x"]][["data"]][[2]][["name"]] <- "Entry Name 2"
    # plot_servicer_build[["x"]][["data"]][[3]][["name"]] <- "Entry Name 3"
    # plot_servicer_build[["x"]][["data"]][[4]][["name"]] <- "Entry Name 4"
    # plot_servicer_build[["x"]][["data"]][[5]][["name"]] <- "Entry Name 5"
    # plot_servicer_build[["x"]][["data"]][[6]][["name"]] <- "Entry Name 6"
    # plot_servicer_build[["x"]][["data"]][[7]][["name"]] <- "Entry Name 7"

    # plot_servicer_build[["x"]][["layout"]][["annotations"]][[1]][["text"]] <- " "

  # This was an attempt to subset a data frame resulting from a reactive function. I figured it wouldn't work, but I had seen stackoverflow posts where this was possible!
    # plot_servicer_build()$x$layout$annotations[[1]]$text <- " "

  # Output plotly rendering of graph and edit hover info
  output$entrance_exit_npl_plotly <- renderPlotly(
      ggplotly(plot_servicer_build()) %>% 
        style(hovertemplate = "Date: %{x} <br>UPB: $%{y}M"))
}

shinyApp(ui = ui, server = server)

A few problems I’ve come across:

  • I cannot add any other lines of code not attached to the chain present within renderPlotly() the same way a lot of posts I saw in my research showed. Mine requires commas between every command add, and that wouldn’t help:
  • I cannot manage to access the plotly_build() list object at all
  • Subsetting a reactive object seems quite difficult.

This is the error I got when trying the initial syntax of subsetting via the [[]], which is what I am able to do outside of Shiny (sans reactivity):

Warning: Error in $: object of type 'closure' is not subsettable

When I try the second method of subsetting plot_servicer_build():

Error in plot_servicer()$x$layout$annotations[[1]]$text <- " " : 
  invalid (NULL) left side of assignment

There have been a couple of other errors along the way!

Is there anyone who has suggestions for how I could make those edits to the plotly_build of a reactive object?! I’ve spent so much time on this and I feel like I’m getting closer as I try some of the slightly promising methods on the internet for similar tasks (i.e. plotyProxy()), and I’m super determined to get this to work, especially because I know the code works outside the scope of a reactive plot in a Shiny! I welcome all and any of your thoughts. I apologize for not supplying the dataset, but it’s proprietary so I have to be cautious.

Versions:

  • RStudio: 1.2.5001.3
  • Plotly: 4.9.0 dev
  • Shiny: 1.3.2
  • ggplot2: 3.1.1
  • R: 3.6.0

Thanks!