每行有不同的 y 轴,但列和行分面图表中的行向 y 轴相等

问题描述 投票:0回答:3

这是我经常遇到的问题。我有一个带有列和行面的图形。我已经使用

fig.update_yaxes(matches=None)
取消了 y 轴的链接。然而,虽然这对于缩放第 1 行和第 2 行之间的轴很有用,因为它们存在于完全不同的域中,但它破坏了在列方面之间进行比较的能力。您可以在下图中看到这个问题:

Example

所以我的问题是,如何在每行的所有列面上具有相同的 y 轴,而第 1 行和第 2 行具有不同的 y 轴?

python plotly
3个回答
0
投票

为了确保

row-wise matching
,您必须为第一行指定以下内容:

fig.layout.yaxis.matches = 'y'
fig.layout.yaxis2.matches = 'y'
fig.layout.yaxis3.matches = 'y'

这是第二个:

fig.layout.yaxis4.matches = 'y4'
fig.layout.yaxis5.matches = 'y4'
fig.layout.yaxis6.matches = 'y4'

如您所见,所有 y 轴都与每个相应行的第一个 y 轴相关。

对于那些想尝试一下的人,这里有一个基于 facet 图

的示例

完整代码:

import plotly.express as px
df = px.data.gapminder()
fig = px.scatter(df, x='gdpPercap', y='lifeExp', color='continent', size='pop',
                facet_col='year', facet_col_wrap=4)

fig.layout.yaxis.matches = 'y'
fig.layout.yaxis2.matches = 'y'
fig.layout.yaxis3.matches = 'y'
fig.layout.yaxis4.matches = 'y'

fig.layout.yaxis5.matches = 'y5'
fig.layout.yaxis7.matches = 'y5'
fig.layout.yaxis6.matches = 'y5'
fig.layout.yaxis8.matches = 'y5'

fig.layout.yaxis9.matches = 'y9'
fig.layout.yaxis10.matches = 'y9'
fig.layout.yaxis11.matches = 'y9'
fig.layout.yaxis12.matches = 'y9'

fig.show()

0
投票
nrows = df.row_var.nunique() # or find a way to get number of rows from fig object.. 
for i in range(0,nrows):
    fig.update_yaxes(showticklabels=True, matches=f'y{i+1}', col=i+1)

https://github.com/plotly/plotly_express/issues/147#issuecomment-537814046


0
投票

由于我经常遇到这种需求,所以我将不同的解决方案压缩为一个函数并为大家记录下来,使其可以在(代码)框中使用(Python>=3.10):

from typing import List, Tuple, TypeAlias

import plotly.express as px
import plotly.graph_objects as go
from plotly._subplots import SubplotRef
grid_ref_: TypeAlias = List[List[Tuple[SubplotRef]]]


def realign_subplot_axes(
    fig: go.Figure,
    x_axes: bool | dict = False,
    y_axes: bool | dict = False
) -> None:
    """For a given plotly figure, allow all x-axes (column-wise) and/or y-axes (row-wise) to have
    their own ranges. The function operates in-place, modifying the figure without returning it.

    Args:
        fig: The plotly figure to be modified.
        x_axes, y_axes:
            If True, the respective axes will be realigned.
            If a dictionary, they will additionally be updated with the specified settings.

    Examples:

        realign_subplot_axes(fig, y_axes=True)
        realign_subplot_axes(fig, x_axes=dict(showticklabels=True))
    """
    if not (x_axes or y_axes):
        return
    subplot_rows: grid_ref_ = fig._grid_ref  # a list of lists, indicative of the grid dimensions
    n_cols: int = len(subplot_rows[0])       # needed in either case
    if x_axes:
        x_settings = x_axes if isinstance(x_axes, dict) else {}
        for col in range(1, n_cols+1):
            # set the layout.xaxis.matches property of all subplots in the same column to the
            # x-axis name of the first subplot in that column. 'x1' is accepted for 'x' (the very first).
            fig.update_xaxes(x_settings, col=col, matches=f"x{col}")
    if y_axes:
        y_settings = y_axes if isinstance(y_axes, dict) else None
        n_rows = len(subplot_rows)
        for row in range(1, n_rows+1):
            # set the layout.yaxis.matches property of all subplots in the same row to the
            # y-axis name of the first subplot in that row. Y-axis names are numbered row-wise,
            # such that the first y-axis in the second row is 'y3' (if there are 2 columns).
            first_y = (row-1) * n_cols + 1
            fig.update_yaxes(y_settings, row=row, matches=f"y{first_y}")


df = px.data.tips()
fig = px.scatter(
    df,
    x="total_bill",
    y="tip",
    color='time',
    facet_col="sex",
    facet_row="day"
)
fig.write_image("default.png")
realign_subplot_axes(fig, y_axes=True)
fig.write_image("y_axes.png")
realign_subplot_axes(fig, x_axes=dict(showticklabels=True))
fig.write_image("both_axes.png")

default.png 所有绘图共享相同的范围 y_axes.png 行共享 y 轴范围 both_axes.png 列共享 x 轴范围并显示所有 x 刻度

© www.soinside.com 2019 - 2024. All rights reserved.