这有点棘手,因为Ploly使用下面的公式计算默认的yAxis范围:[y_min-padding, y_max+padding]
where padding=(y_max-y_min)/16
.
通常,这将意味着yaxis1
和yaxis2
的零不一定对齐(而且很可能不对齐).但是,我们可以通过计算0在yaxis1上的相对位置来求解yaxis2的填充.例如:
y1_min, y1_max = df_overview['col 2'].min(), df_overview['col 2'].max()
y1_padding = (y1_max - y1_min)/16
y1_range = [y1_min - y1_padding, y1_max + y1_padding]
y1_relative_zero = (0 - y1_range[0]) / (y1_range[1] - y1_range[0])
y1_relative_zero = 0.08200108720519005
意味着y1轴上的0大约是最小值和最大值之间的8.2%.现在我们可以计算第二个yAxis上的必要填充,以确保0也是y2数据的最小和最大之间的相同百分比.
我们需要以下方程式的解:
(0 - y2_range_min) / (y2_range_max - y2_range_min) = y1_relative_zero
在y2_range_min = y2_min - y2_padding
和y2_range_max = y2_max + y2_padding
之间.
我不会深入讨论所有细节,因为它正在重新安排变量,但以下是解决方案:
y2_padding = (y1_relative_zero * (y2_max - y2_min) + y2_min) / (1 - 2*y1_relative_zero)
把所有这些放在一起:
import pandas as pd
from plotly.subplots import make_subplots
import plotly.graph_objects as go
data = {'col 1': [-6, 18.6, 106.35, 111],
'col 2': [-787.5, 976.5, 11246, 25682]}
df_overview = pd.DataFrame(data)
df_overview.index = ['A', 'B', 'C', 'D']
colors = ['#FF0000', '#0000FF'] # red, blue
columns = ['col 1', 'col 2']
fig = make_subplots(specs=[[{"secondary_y": True}]])
for i, col in enumerate(columns):
fig.add_trace(
go.Bar(x=df_overview.index, y=df_overview[col], name=col, marker_color=colors[i], offsetgroup=i,),
secondary_y=(i == 0)
)
fig.update_layout(
barmode='group',
font_size=14,
hovermode="x unified",
)
y1_min, y1_max = df_overview['col 2'].min(), df_overview['col 2'].max()
y1_padding = (y1_max - y1_min)/16
y1_range = [y1_min - y1_padding, y1_max + y1_padding]
y1_relative_zero = (0 - y1_range[0]) / (y1_range[1] - y1_range[0])
y2_min, y2_max = df_overview['col 1'].min(), df_overview['col 1'].max()
## we solve the following equation:
# (0 - y2_range_min) / (y2_range_max - y2_range_min) = y1_relative_zero
# (0 - (y2_min - y2_padding)) / ((y2_max - y2_min) + 2*y2_padding) = y1_relative_zero
# y1_relative_zero * ((y2_max - y2_min) + 2*y2_padding) = (y2_padding - y2_min)
# y1_relative_zero * (y2_max - y2_min) + (y1_relative_zero*2*y2_padding) = (y2_padding - y2_min)
# (y2_padding - y2_min) - (y1_relative_zero*2*y2_padding) = y1_relative_zero * (y2_max - y2_min)
# y2_padding(1 - 2*y1_relative_zero) - y2_min = y1_relative_zero * (y2_max - y2_min)
y2_padding = (y1_relative_zero * (y2_max - y2_min) + y2_min) / (1 - 2*y1_relative_zero)
y2_range = [y2_min - y2_padding, y2_max + y2_padding]
fig.update_yaxes(range=y1_range, secondary_y=False)
fig.update_yaxes(range=y2_range, secondary_y=True)
fig.show()