Search code examples
rplotlyaxispan

Pan x axis only, zoom still allowed for y axis


After looking around I can't seem to find a way to disable dragging of y axis in pan mode, while also allowing to zoom both axes.

Anyone figured this one out yet ?

The data is positional positive integer count data, so I want to keep zoom on Y as a normalization option for regions with large extremes.

I checked through r plotly API tutorial and issues on Github, I also checked through the code of r plotly and Google. All I could find was this link to plotly.js, discussing it: https://github.com/plotly/plotly.js/issues/887 Does this mean there is no workaround ?


Solution

  • If you combine the ability to identify whether you're panning or zooming, along with relayout, you can create this effect.

    I created some arbitrary data to demonstrate how this works. I used the function htmlwidgets::onRender to add the Plotly event listener.

    In my example, I've preset the plot to the dragmode 'pan'. I've also changed the y-axis to be fixed in place. To zoom or changing back to panning, you will use the mode bar.

    The onRender function creates an event listener for plotly_relayout. When you select an item in the modebar, you're causing a relayout event. Additionally, when you change whether the y-axis is fixed in place or not, that is also a relayout event.

    To distinguish whether this is a relayout event that is triggered by a selection in the modebar, I used if(... == "dragmode"

    More precisely: if(evd.includes('dragmode') which acts similar to R's str_detect().

    If this is a modebar triggered event, then the fixed range status is changed based on whether you are panning or zooming.

    library(plotly)
    
    dfp <- data.frame(x = 1:100, y = rep(1:25, 4))
    
    plot_ly(dfp, x = ~x, y = ~y, mode = "lines", type = "scatter") %>% 
      layout(dragmode = "pan", yaxis = list(fixedrange = TRUE)) %>% 
      htmlwidgets::onRender(
        "function(el, x) {
          el.on('plotly_relayout', function(ed) {
            evd = JSON.stringify(ed);
            if(evd.includes('dragmode')) {
              Plotly.relayout(el.id, {'yaxis.fixedrange': evd.includes('pan')});
            }
          })
        }")
    

    I wanted to point out that if you pan after you've zoomed, you restrict the y-axis to whatever is shown at that point in time. To fully reset the plot, you need to select zoom in the mode bar (even if you don't plan on using it) to change the y-axis back to an unfixed range.

    enter image description here

    After panning:

    enter image description here

    After selecting zoom, home, than selecting a zoom range (dragging on the plot):

    enter image description here