1

How can I reproduce the following graph in plotly

library(dplyr)
library(ggplot2)

tibble(x =1:10, y = 1:10) %>% 
        ggplot(aes(x,y)) +
        geom_line() + 
        scale_y_continuous(sec.axis = ~.*2)

I tried the following code based on this answer here

library(dplyr)
library(plotly)

tibble(x =1:10, y = 1:10) %>% 
      mutate(y2 = y*2) %>% 
      plot_ly() %>%  
      add_lines(x =~x, y =~y) %>% 
      add_lines(x= ~x, y=~y2, 
                yaxis = "y2", color = I("transparent"), 
                hoverinfo='skip', showlegend=FALSE) %>% 
      layout(yaxis2 = list(side = "right", overlaying = "y", showgrid = FALSE), 
             margin = list(r = 50))

While at first glance it appears to work, it only provides a partial solution, since if I interactively try to change the scale of the main (left) y axis on the produced graph (by dragging it up or down), the right axis does not move with the graph (because it is linked only to the second invisible graph). This of course is not acceptable as it does not allow using any of interactive features of plotly reliably which is the reason I wanted to use it to begin with instead of ggplot.

Edit: Just realized that this plotly solution does not seem to work at all in the case of non linear transformation between the axes (while ggplot handles it beautifully).

M--
  • 25,431
  • 8
  • 61
  • 93
Sasha
  • 5,783
  • 8
  • 33
  • 37

1 Answers1

2

You just need to set up dtick and tick0 for plotly to have the same graph as ggplot2 one. See below;

library(plotly)
library(dplyr)

tibble(x =1:10, y = 1:10) %>% 
  mutate(y2 = y*2) -> df1

n0 <- 4
y0 <- max(df1$y)/n0
x0 <- max(df1$x)/n0

df1 %>% 
 plot_ly(data = . , x = ~x, y = ~y,
         type = "scatter", mode = "lines", width = 800, 
         color = I("red"), name = "") %>%
  
   add_trace(x = ~x, y = ~y2, yaxis = "y2", 
             color = I("red"), name = "") %>%
  
   layout(yaxis = list(showline = FALSE, side = "left",
                       title = "", color = "red", 
                       dtick = y0, tick0 = y0, fixedrange=TRUE),
          
          yaxis2 = list(showline = FALSE, side = "right", overlaying = "y", position = 1,
                        title = "", anchor = "free", color = "blue",
                        dtick = 2*y0, tick0 = 2*y0, fixedrange=TRUE),
          
          xaxis = list(showline = FALSE, zeroline = FALSE, title = "",
                       dtick = x0, tick0 = x0),
          
          showlegend = FALSE,
          margin = list(l = 50, r = 50, b = 50, t = 50, pad = 4)
  )

Created on 2020-06-19 by the reprex package (v0.3.0)

M--
  • 25,431
  • 8
  • 61
  • 93
  • This only aligns the ticks in the initially generated graph, but does not solve my problem as you can still move either of the axes independently, arbitrarily changing the relationship between the axes. (Also in your code, by setting a color to the second trace, you will see two lines if you move one of the axes, therefore I set the color to "transparent") – Sasha Jun 20 '20 at 01:57
  • @Sasha I overcome that issue with `fixedrange=TRUE` and adding `margin` arguments to keep the both y-axis labels visible at all zooms. If you want to be able to still zoom in on y-axis and keep both axes the same, then you need to consider shiny apps. Using shiny, you can update the other axis based on the one user is changing. Read about `plotlyProxy`. – M-- Jun 21 '20 at 18:30