简体   繁体   English

Plotly:如何在同一个子图上显示 2 个以上的 x 轴标题/范围?

[英]Plotly: How to show more than 2 x-axes titles/ranges on the same subplot?

I'm using Plotly and making scatter plot subplots with a shared y-axis and different x-axes.我正在使用 Plotly 并制作具有共享 y 轴和不同 x 轴的分散 plot 子图。 I have attempted to use the figure object (fig['layout'][data index]) syntax to show multiple stacked x-axes and their respective ranges.我尝试使用图 object (fig['layout'][data index]) 语法来显示多个堆叠的 x 轴及其各自的范围。 I have only been successful in showing two xaxes and ranges per subplot by assigning 'top' and 'bottom' to the side attribute of the figure layout.通过将“顶部”和“底部”分配给图形布局的侧面属性,我只成功地显示了每个子图的两个 xaxes 和范围。 The 2nd column from the right in figure below should show titles/ranges for series T5, T6, and T7 but only the title and range for T5 and T7 appear.下图中右起第 2 列应显示系列 T5、T6 和 T7 的标题/范围,但仅显示 T5 和 T7 的标题和范围。

Is it possible to show more than 2 x-axes title/ranges on the same subplot in Plotly?是否可以在 Plotly 的同一子图上显示超过 2 个 x 轴标题/范围? For an implemented example, Matplotlib supports showing multiple stacked axes 对于实现的示例,Matplotlib 支持显示多个堆叠轴

在此处输入图像描述

Thank you to Vestland, the key was using the position attribute of the figure's layout and scaling the y-axis to fit the adjustment properly.感谢 Vestland,关键是使用图形布局的 position 属性并缩放 y 轴以正确适应调整。 See the [monstrosity] below for a full implementation of multiple axes based on Vestland's sample code.有关基于 Vestland 示例代码的多轴的完整实现,请参见下面的 [monstrosity]。

在此处输入图像描述

You'll need a precise combination of make_subplots(rows=1, cols=2) , add_traces() and fig.update_layout(xaxis=dict(domain=...) :您需要精确组合make_subplots(rows=1, cols=2)add_traces()fig.update_layout(xaxis=dict(domain=...)

  1. Set up a "regular" subplot using fig=make_subplots(rows=1, cols=2) and include two traces as described here .使用fig=make_subplots(rows=1, cols=2)设置“常规”子图,并包括此处所述的两条迹线。

  2. Add a third trace with its own xaxis using fig.add_trace(go.Scatter([...[, xaxis="x3"))使用fig.add_trace(go.Scatter([...[, xaxis="x3"))添加第三条带有自己的 xaxis 的迹线

  3. Then, adjust subplot 1 to make room for xaxis3 using: fig.update_layout(xaxis3=dict(anchor="free", overlaying="x1", position=0.0))然后,使用以下命令调整 subplot 1 为xaxis3腾出空间: fig.update_layout(xaxis3=dict(anchor="free", overlaying="x1", position=0.0))

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

The reason why you'll have to take domain into account is because the position attribute in point 3 can't be negative, and you'll have to make room for the double x-axes somehow.您必须考虑domain的原因是因为第point 3中的position属性不能为负数,并且您必须以某种方式为双 x 轴腾出空间。 Here's the result:结果如下:

Plot Plot

在此处输入图像描述

Complete code:完整代码:

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()

Edit: Tighten the space between title and range.编辑:收紧标题和范围之间的空间。

One approach is to change the position of the title itself using fig.update_layout(title=dict()) :一种方法是使用fig.update_layout(title=dict())更改标题本身的 position :

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

Plot 2 Plot 2

在此处输入图像描述

Complete code for Plot 2 Plot 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()

The question is a bit tricky but feasible.这个问题有点棘手但可行。 There is an example of how to create multiple axes in a single plot. 一个如何在单个 plot 中创建多个轴的示例。 Basically, you create another axis with twinx() and then set everything in such a way that it ends up nicely.基本上,您使用twinx()创建另一个轴,然后将所有内容设置为完美结束。 The problem is that matplotlib automatically places other axes on the opposite side (so 'top' in case of the x-axis and 'right' in the case of the y-axis).问题是matplotlib 会自动将其他轴放置在另一侧(在 x 轴的情况下为'top' ,在 y 轴的情况下为'right' )。 This is why we need to set all these properties (where to show the axis, in which direction should the label and the ticks being placed) and a few nice things, such as the color of the label and the ticks.这就是为什么我们需要设置所有这些属性(在哪里显示轴,label 和放置的刻度应该在哪个方向)和一些好东西,例如 label 和刻度的颜色。

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()

输出图片

BTW, I used matplotlib due to (my) convenience.顺便说一句,由于(我的)方便,我使用了 matplotlib It is the plotting library that I prefer but for no specific reason.这是我更喜欢的绘图库,但没有具体原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM