plotly / plotly/plotly.R

Overlaying subplots when using plotProxy()/plotlyProxyInvoke() in Shiny App

Open
#2,054 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
R
Stars
2.7k
Forks
641
PR merge metrics
No merged PRs in 30d

Description

I was hoping to extend the plotly.R "relayout" shiny example found here to incorporate a subplot of 3 figures with a range slider down the bottom. Here is what I tried:

library(shiny)
library(plotly)

ui <- fluidPage(
  plotlyOutput("plot")
  )

server <- function(input, output, session) {
  
  p <- txhousing %>%
    group_by(city) %>%
    plot_ly(
      x = ~ date,
      y = ~ median,
      mode = 'lines',
      type = 'scatter',
      source = 'myplot'
    ) %>%
    rangeslider(thickness = 0.05)
  
  output$plot <- renderPlotly({
    
    # Just duplicating plots for this example
    
    subplot(p, p, p, shareX = T, nrows = 3) %>%
      layout(height = 720)
    
  })
  
  observeEvent(event_data("plotly_relayout", source = "myplot"), {
    d <- event_data("plotly_relayout", source = "myplot")
    # unfortunately, the data structure emitted is different depending on 
    # whether the relayout is triggered from the rangeslider or the plot
    xmin <- if (length(d[["xaxis.range[0]"]])) d[["xaxis.range[0]"]] else d[["xaxis.range"]][1]
    xmax <- if (length(d[["xaxis.range[1]"]])) d[["xaxis.range[1]"]] else d[["xaxis.range"]][2]
    if (is.null(xmin) || is.null(xmax)) return(NULL)
    
    # compute the y-range based on the new x-range
    idx <- with(txhousing, xmin <= date & date <= xmax)
    yrng <- extendrange(txhousing$median[idx])
   
    plotlyProxy("plot", session) %>%
      plotlyProxyInvoke("relayout", list(yaxis = list(range = yrng)))

  })

}

shinyApp(ui, server)

Below is a preview of the plotly output before using the rangeslider:

image

And here is the resulting plotly output after I use the rangeslider:

image

I have also tried replacing:

plotlyProxy("plot", session) %>%
      plotlyProxyInvoke("relayout", list(yaxis = list(range = yrng)))

With this instead:

  plotlyProxy("plot", session) %>%
     plotlyProxyInvoke("relayout", list(yaxis = list(range = yrng), 
                                        yaxis2 = list(range = yrng),
                                        yaxis3 = list(range = yrng)))

...just in case I was able to independently control the individual y-axes of the subplot. However, this didn't work either. The
original example works great for the single plot; it is when I try adding in the subplots that things get whacky.

I was wondering if anyone else can confirm this plotting behaviour? Any suggestions for a workaround?

Thanks in advance! :)

[UPDATE]

I managed to find a workaround. The issue seemed to be that when calling the plotProxy()/plotProxyInvoke() functions the subplot domains got garbled :-S. However, if I explicitly set the domains for each y-axis (roughly breaking the vertical real-estate in thirds) in then everything displays as it should:

plotlyProxy("plot", session) %>%
      plotlyProxyInvoke("relayout", list(yaxis = list(range = yrng, domain = p$x$layout$yaxis$domain),
                                         yaxis2 = list(range = yrng, domain = p$x$layout$yaxis2$domain),
                                         yaxis3 = list(range = yrng, domain = p$x$layout$yaxis3$domain)))

where the object p is the original plot_ly obj that I am able to access on the server side.

Any idea why the calling plotProxy()/plotProxyInvoke() seems to garble the original y-axis domains? The workaround does solve the problem, just feels a bit clunky to have to do that each time the rangeslider updates.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with inst/examples/shiny/proxy_relayout/app.R, then reproduce the three-panel subplot example using subplot(), plotlyProxy(), and plotlyProxyInvoke("relayout"). Investigate why relayout changes the subplot y-axis domains, including the yaxis, yaxis2, and yaxis3 cases. Done means the rangeslider updates the y-ranges without requiring callers to restore each axis domain manually.

Written by the indexing model from the issue text.

Assessment

Tech stack
r
Domain
data-visualization
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.