Plotly: ¿Cómo mostrar más de 2 títulos / rangos de ejes x en la misma subparcela?
Estoy usando Plotly y hago subtramas de gráficos de dispersión con un eje y compartido y diferentes ejes x. He intentado utilizar la sintaxis del objeto figure (fig ['layout'] [data index]) para mostrar varios ejes x apilados y sus respectivos rangos. Solo he tenido éxito en mostrar dos ejes x y rangos por subparcela asignando 'superior' e 'inferior' al atributo lateral del diseño de la figura. La segunda columna de la derecha en la figura siguiente debe mostrar títulos / rangos para las series T5, T6 y T7, pero solo aparecen el título y el rango para T5 y T7.
¿Es posible mostrar más de 2 títulos / rangos de ejes x en la misma subparcela en Plotly? Para un ejemplo implementado, Matplotlib admite mostrar múltiples ejes apilados

Gracias a Vestland, la clave fue usar el atributo de posición del diseño de la figura y escalar el eje y para ajustar el ajuste correctamente. Vea la [monstruosidad] a continuación para una implementación completa de múltiples ejes basada en el código de muestra de Vestland.

Respuestas
Usted necesitará una combinación precisa de make_subplots(rows=1, cols=2)
, add_traces()
y fig.update_layout(xaxis=dict(domain=...)
:
Configure una subtrama "regular" utilizando
fig=make_subplots(rows=1, cols=2)
e incluya dos trazas como se describe aquí .Agregue un tercer trazo con su propio eje x usando
fig.add_trace(go.Scatter([...[, xaxis="x3"))
Luego, ajuste la subparcela 1 para dejar espacio para
xaxis3
usar:fig.update_layout(xaxis3=dict(anchor="free", overlaying="x1", position=0.0))
Haga algunos ajustes finales usando
fig.update_layout([...], yaxis2=dict(domain=[0.1, 1]))
La razón por la que tendrás que tener domain
en cuenta es porque el position
atributo en point 3
no puede ser negativo y tendrás que dejar espacio para los ejes x dobles de alguna manera. Aquí está el resultado:
Trama

Código completo:
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()
Editar: ajusta el espacio entre el título y el rango.
Un enfoque es cambiar la posición del título usando fig.update_layout(title=dict())
:
fig.update_layout(
title={
'text': "Plot Title",
'y':0.88,
'x':0.42,
'xanchor': 'left',
'yanchor': 'top'})
Parcela 2

Código completo para la parcela 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()
La pregunta es un poco complicada pero factible. Hay un ejemplo de cómo crear varios ejes en un solo gráfico. Básicamente, crea otro eje con twinx()
y luego configura todo de tal manera que termina bien. El problema es que matplotlib coloca automáticamente otros ejes en el lado opuesto (así 'top'
en el caso del eje xy 'right'
en el caso del eje y). Es por eso que necesitamos establecer todas estas propiedades (dónde mostrar el eje, en qué dirección se deben colocar la etiqueta y los ticks) y algunas cosas interesantes, como el color de la etiqueta y los ticks.
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()

Por cierto, usé matplotlib debido a (mi) conveniencia. Es la biblioteca de trazado que prefiero, pero sin ninguna razón específica.