【问题标题】:Plotly: How to show more than 2 x-axes titles/ranges on the same subplot?Plotly:如何在同一个子图上显示 2 个以上的 x 轴标题/范围?
【发布时间】:2021-03-11 09:05:32
【问题描述】:

我正在使用 Plotly 并制作具有共享 y 轴和不同 x 轴的散点图子图。我尝试使用图形对象 (fig['layout'][data index]) 语法来显示多个堆叠的 x 轴及其各自的范围。通过将“顶部”和“底部”分配给图形布局的侧面属性,我只成功地显示了每个子图的两个 xaxes 和范围。下图中右起第 2 列应显示系列 T5、T6 和 T7 的标题/范围,但仅显示 T5 和 T7 的标题和范围。

是否可以在 Plotly 的同一个子图上显示 2 个以上的 x 轴标题/范围? For an implemented example, Matplotlib supports showing multiple stacked axes

感谢 Vestland,关键是使用图形布局的位置属性并缩放 y 轴以正确适应调整。请参阅下面的 [monstrosity],了解基于 Vestland 示例代码的多轴的完整实现。

【问题讨论】:

    标签: python plot plotly data-visualization plotly-python


    【解决方案1】:

    您需要精确组合 make_subplots(rows=1, cols=2)add_traces()fig.update_layout(xaxis=dict(domain=...)

    1. 使用fig=make_subplots(rows=1, cols=2) 设置“常规”子图,并按照here 的描述包含两条轨迹。

    2. 使用fig.add_trace(go.Scatter([...[, xaxis="x3"))添加第三条带有自己的 xaxis 的轨迹

    3. 然后,调整子图 1 为 xaxis3 腾出空间,使用:fig.update_layout(xaxis3=dict(anchor="free", overlaying="x1", position=0.0))

    4. 使用fig.update_layout([...], yaxis2=dict(domain=[0.1, 1]))进行一些最终调整

    您必须考虑domain 的原因是因为point 3 中的position 属性不能为负数,并且您必须以某种方式为双x 轴腾出空间。结果如下:

    情节

    完整代码:

    from plotly.subplots import make_subplots
    import plotly.graph_objects as go
    
    # initial subplot with two traces
    fig = make_subplots(rows=1, cols=2)
    
    fig.add_trace(
        go.Scatter(x=[1, 2, 3], y=[4, 5, 6]),
        row=1, col=1
    )
    
    fig.add_trace(
        go.Scatter(x=[20, 30, 40], y=[50, 60, 70]),
        row=1, col=2
    )
    
    fig.update_layout(height=600, width=800,
                      title_text="Subplots with shared x-axes")
    
    # extra data where xaxis3 is shared with subplot 1
    fig.add_trace(go.Scatter(
        x=[11, 12, 13],
        y=[6, 5, 4],
        name="xaxis3 data",
        xaxis="x3"
    ))
    
    # some adjustmentns for xaxis3
    fig.update_layout(xaxis3=dict(
            title="xaxis3 title",
            titlefont=dict(
                color="#9467bd"
            ),
            tickfont=dict(
                color="#9467bd"
            ),
            anchor="free",
            overlaying="x1",
            side="right",
            position=0.0
        ))
    
    # extra data where xaxis4 is shared with subplot 2
    fig.add_trace(go.Scatter(
        x=[50, 60, 70],
        y=[60, 60, 60],
        name="xaxis4 data",
        xaxis="x4",
        yaxis = 'y2'
    ))
    
    # some adjustments for xaxis4
    fig.update_layout(xaxis4=dict(
            title="xaxis4 title",
            titlefont=dict(
                color="#9467bd"
            ),
            tickfont=dict(
                color="#9467bd"
            ),
            anchor="free",
            overlaying="x2",
            side="right",
            position=0.0
        ))
    
    # make room to display double x-axes
    fig.update_layout(yaxis1=dict(domain=[0.1, 1]),
                      yaxis2=dict(domain=[0.1, 1]),
                     )
    
    # not critical, but just to put a little air in there
    fig.update_layout(xaxis1=dict(domain=[0.0, 0.4]),
                      xaxis2=dict(domain=[0.6, 1]),
                     )
    
    fig.show()
    

    编辑:收紧标题和范围之间的空间。

    一种方法是使用fig.update_layout(title=dict())改变标题本身的位置:

    fig.update_layout(
        title={
            'text': "Plot Title",
            'y':0.88,
            'x':0.42,
            'xanchor': 'left',
            'yanchor': 'top'})
    

    情节 2

    情节 2 的完整代码

    from plotly.subplots import make_subplots
    import plotly.graph_objects as go
    
    # initial subplot with two traces
    fig = make_subplots(rows=1, cols=2)
    
    fig.add_trace(
        go.Scatter(x=[1, 2, 3], y=[4, 5, 6]),
        row=1, col=1
    )
    
    fig.add_trace(
        go.Scatter(x=[20, 30, 40], y=[50, 60, 70]),
        row=1, col=2
    )
    
    fig.update_layout(height=600, width=800,
                      title_text="Subplots with shared x-axes")
    
    # extra data where xaxis3 is shared with subplot 1
    fig.add_trace(go.Scatter(
        x=[11, 12, 13],
        y=[6, 5, 4],
        name="xaxis3 data",
        xaxis="x3"
    ))
    
    # some adjustmentns for xaxis3
    fig.update_layout(xaxis3=dict(
            title="xaxis3 title",
            titlefont=dict(
                color="#9467bd"
            ),
            tickfont=dict(
                color="#9467bd"
            ),
            anchor="free",
            overlaying="x1",
            side="right",
            position=0.0
        ))
    
    # extra data where xaxis4 is shared with subplot 2
    fig.add_trace(go.Scatter(
        x=[50, 60, 70],
        y=[60, 60, 60],
        name="xaxis4 data",
        xaxis="x4",
        yaxis = 'y2'
    ))
    
    # some adjustments for xaxis4
    fig.update_layout(xaxis4=dict(
            title="xaxis4 title",
            titlefont=dict(
                color="#9467bd"
            ),
            tickfont=dict(
                color="#9467bd"
            ),
            anchor="free",
            overlaying="x2",
            side="right",
            position=0.0
        ))
    
    # make room to display double x-axes
    fig.update_layout(yaxis1=dict(domain=[0.1, 1]),
                      yaxis2=dict(domain=[0.1, 1]),
                     )
    
    # not critical, but just to put a little air in there
    fig.update_layout(xaxis1=dict(domain=[0.0, 0.4]),
                      xaxis2=dict(domain=[0.6, 1]),
                     )
    
    fig.update_layout(
        title={
            'text': "Plot Title",
            'y':0.88,
            'x':0.42,
            'xanchor': 'left',
            'yanchor': 'top'})
    
    fig.show()
    

    【讨论】:

    • 你真的是我的英雄。我从来不知道调整布局定位和各自的 y 轴域以适应标题/范围。你知道是否可以收紧标题和范围之间的空间?
    • @straydog 乐于助人!为了“收紧”标题和范围之间的空间,您可以更改标题本身的位置。看看我最近的编辑,看看是否适合你。
    【解决方案2】:

    这个问题有点棘手但可行。 There 是如何在单个图中创建多个轴的示例。 基本上,您使用twinx() 创建另一个轴,然后以这样的方式设置所有内容以使其完美结束。问题是 matplotlib 会自动将其他轴放在另一侧(所以在 x 轴的情况下是 'top',在 y 轴的情况下是 'right')。这就是为什么我们需要设置所有这些属性(在哪里显示轴、标签和刻度线应该放置在哪个方向)以及一些不错的东西,例如标签和刻度线的颜色。

    import matplotlib.pyplot as plt
    
    fig, ax1 = plt.subplots()
    fig.subplots_adjust(right=0.75)
    
    axs =[]
    axs.append( ax1 )
    for i in range(1,3):
        # creates another axes that shares the same y-axis 
        axs.append( ax1.twiny() ) 
    
    offest = 42
    for i,ax in enumerate(axs):
        # sets the ticks to be shown at the bottom
        ax.xaxis.tick_bottom()
        ax.tick_params(axis='x', direction='out',labelbottom=True)
        # places the nex axis (ticks and description) below the other axes
        ax.spines["bottom"].set_position(("outward", offest*i)) # additional offset
    
    
    line1, = axs[0].plot([0, 1, 2], [0, 1, 2], "b-", label="Line 1")
    line2, = axs[1].plot([0, 2, 4], [0, 3, 2], "r-", label="Line 2")
    line3, = axs[2].plot([0, 10, 60], [50, 30, 15], "g-", label="Line 3")
    lines = [line1,line2,line3]
    
    lim = [(0,2), (0,4),(2,65)]
    XLabel = ["Time","Distance","Height"]
    
    for i,ax in enumerate(axs):
        # set limits
        ax.set_xlim( lim[i] )
        # set label
        ax.set_xlabel( XLabel[i] )
        # set label position
        ax.xaxis.set_label_position("bottom")
        # set label color
        color = lines[i].get_color()
        ax.xaxis.label.set_color( color )
        # set tick color
        ax.tick_params(axis='x', colors=color)
    # set legend only in one axis (but with all lines)
    ax1.legend(lines, [l.get_label() for l in lines])
    
    plt.show()
    

    顺便说一句,由于(我的)方便,我使用了 matplotlib。这是我更喜欢的绘图库,但没有具体原因。

    【讨论】:

    • 感谢您使用 Matplotlib 解决双重绘图问题,但我遇到的主要问题是使用 Plotly 执行此操作。
    猜你喜欢
    • 2020-05-14
    • 2017-12-26
    • 2018-07-27
    • 2023-02-04
    • 2016-10-19
    • 2019-07-28
    • 1970-01-01
    • 2016-10-19
    • 2022-01-25
    相关资源
    最近更新 更多