Felix Grossmann
Felix Grossmann

Reputation: 1314

One zeroline for two y axis in plotly

enter image description here

This graph is generated with the following code:

library(tidyverse)
library(plotly)

df <- data.frame(
      DEP = c("ABC", "DEF", "GHI")
      , VALUE = c(100, 110, 120)
      , LINE = c(-0.1, 0.7, 0.9)
    )

xAxis <- list(
  title = ""
  , tickangle = 0
  , tickfont = list(size = 10)
)

yAxis <- list(
  side = "left"
  , showgrid = TRUE
  , zeroline = TRUE
  , title = ""
)

yAxis2 <- list(
  side = "right"
  , autotick = FALSE
  , ticks = "outside"
  , tick0 = 0
  , dtick = 0.1
  , showgrid = TRUE
  , zeroline = TRUE
  , overlaying = "y"
)

plot_ly(data = df, x = ~DEP) %>%
  add_trace(data = df, x = ~DEP, y = ~VALUE, name = 'VALUE', type = "bar", yaxis = "y", textposition = "auto") %>%
  add_trace(data = df, x = ~DEP, y = ~LINE, name = 'LINE', mode = "lines", type = "scatter",
            line = list(width = 4), yaxis = "y2") %>%
  layout(
    margin = list(r=50, b = 150)
    , xaxis = xAxis
    , yaxis = yAxis
    , yaxis2 = yAxis2
    , showlegend = FALSE
  )

I would like to change the graph so that the zeroline of the left y axis is shifted to the zeroline of the right y axis. Consequently the bars should be shifted too:

enter image description here

Upvotes: 5

Views: 3776

Answers (1)

Maximilian Peters
Maximilian Peters

Reputation: 31649

As far as I know there is no way of directly doing it in Plotly. But you could set the range for both axes manually.

For your bars add the following line to its layout:

range = c(max(df$VALUE) / max(df$LINE) * min(df$LINE), max(df$VALUE))

and for your lines:

range = c(min(df$LINE), max(df$LINE))

which would give the followin graph. enter image description here

An easier approach would be to set the lower limit to 0 which truncates the line graph.

In the code below an additional variable axis_buffer was added to avoid that the range is exactly the lower and upper limit of your values.

For the sake of visual clarity I would remove some of the grid lines or try normalizing your data and adding the raw data to your hover info.

library('plotly')
df <- data.frame(
  DEP = c("ABC", "DEF", "GHI")
  , VALUE = c(100, 110, 120)
  , LINE = c(-0.1, 0.7, 0.9)
)

axis_buffer <- 1.1

xAxis <- list(
  title = ""
  , tickangle = 0
  , tickfont = list(size = 10)
)

yAxis <- list(
  side = "left"
  , showgrid = TRUE
  , zeroline = TRUE
  , title = ""
  , range = c(max(df$VALUE) / max(df$LINE) * min(df$LINE) * axis_buffer, max(df$VALUE) * axis_buffer)
)

yAxis2 <- list(
  side = "right"
  , autotick = FALSE
  , ticks = "outside"
  , tick0 = 0
  , dtick = 0.1
  , showgrid = TRUE
  , zeroline = TRUE
  , overlaying = "y"
  , range = c(min(df$LINE) * axis_buffer, max(df$LINE) * axis_buffer)
)

plot_ly(data = df, x = ~DEP) %>%
  add_trace(data = df, x = ~DEP, y = ~VALUE, name = 'VALUE', type = "bar", yaxis = "y", textposition = "auto") %>%
  add_trace(data = df, x = ~DEP, y = ~LINE, name = 'LINE', mode = "lines", type = "scatter",
            line = list(width = 4), yaxis = "y2") %>%
  layout(
    margin = list(r=50, b = 150)
    , xaxis = xAxis
    , yaxis = yAxis
    , yaxis2 = yAxis2
    , showlegend = FALSE
  )

Upvotes: 7

Related Questions