Plotly: Comment afficher plus de 2 titres / plages d'axes x sur la même sous-parcelle?

Nov 28 2020

J'utilise Plotly et je crée des sous-graphiques de nuage de points avec un axe y partagé et différents axes x. J'ai essayé d'utiliser la syntaxe de l'objet figure (fig ['layout'] [data index]) pour afficher plusieurs axes x empilés et leurs plages respectives. J'ai seulement réussi à montrer deux xaxes et plages par sous-graphique en attribuant «haut» et «bas» à l'attribut latéral de la mise en page de la figure. La deuxième colonne à partir de la droite de la figure ci-dessous doit afficher les titres / plages pour les séries T5, T6 et T7, mais seuls le titre et la plage pour T5 et T7 apparaissent.

Est-il possible d'afficher plus de 2 titres / plages d'axes x sur la même sous-parcelle dans Plotly? Pour un exemple implémenté, Matplotlib prend en charge l'affichage de plusieurs axes empilés

Merci à Vestland, la clé était d'utiliser l'attribut de position de la mise en page de la figure et de mettre à l'échelle l'axe des y pour s'adapter correctement à l'ajustement. Voir la [monstruosité] ci-dessous pour une implémentation complète de plusieurs axes basés sur l'exemple de code de Vestland.

Réponses

2 vestland Nov 29 2020 at 22:47

Vous aurez besoin d'une combinaison précise de make_subplots(rows=1, cols=2), add_traces()et fig.update_layout(xaxis=dict(domain=...):

  1. Configurez un sous-tracé «régulier» en utilisant fig=make_subplots(rows=1, cols=2)et incluez deux traces comme décrit ici .

  2. Ajoutez une troisième trace avec sa propre xaxis en utilisant fig.add_trace(go.Scatter([...[, xaxis="x3"))

  3. Ensuite, ajustez la sous-parcelle 1 pour faire de la place pour xaxis3utiliser:fig.update_layout(xaxis3=dict(anchor="free", overlaying="x1", position=0.0))

  4. Faites quelques ajustements finaux en utilisant fig.update_layout([...], yaxis2=dict(domain=[0.1, 1]))

La raison pour laquelle vous devrez prendre domainen compte est que l' positionattribut dans point 3ne peut pas être négatif et que vous devrez faire de la place pour les doubles axes x. Voici le résultat:

Terrain

Code complet:

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

Modifier: resserrez l'espace entre le titre et la plage.

Une approche consiste à changer la position du titre lui-même en utilisant fig.update_layout(title=dict()):

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

Parcelle 2

Code complet pour 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()
1 max Nov 30 2020 at 08:30

La question est un peu délicate mais faisable. Il existe un exemple de création de plusieurs axes dans un même tracé. Fondamentalement, vous créez un autre axe avec twinx(), puis définissez tout de manière à ce que cela se termine bien. Le problème est que matplotlib place automatiquement les autres axes du côté opposé (donc 'top'dans le cas de l'axe des x et 'right'dans le cas de l'axe des y). C'est pourquoi nous devons définir toutes ces propriétés (où afficher l'axe, dans quelle direction l'étiquette et les coches doivent-elles être placées) et quelques jolies choses, telles que la couleur de l'étiquette et les coches.

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, j'ai utilisé matplotlib en raison de (ma) commodité. C'est la bibliothèque de traçage que je préfère mais sans raison spécifique.