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!