Fabuła: Jak wyświetlić więcej niż 2 tytuły / zakresy na osi X na tym samym wykresie pomocniczym?
Używam Plotly i tworzę pod-wykresy punktowe ze wspólną osią Y i różnymi osiami x. Próbowałem użyć składni obiektu figury (fig [„układ”] [indeks danych]), aby pokazać wiele ułożonych w stos osi x i ich odpowiednich zakresów. Udało mi się pokazać tylko dwie osie i zakresy na podplot, przypisując „góra” i „dół” do atrybutu bocznego układu rysunku. Druga kolumna od prawej na poniższym rysunku powinna pokazywać tytuły / zakresy dla serii T5, T6 i T7, ale pojawią się tylko tytuł i zakres dla T5 i T7.
Czy można wyświetlić więcej niż 2 tytuły / zakresy na osi x na tym samym podplotu w Plotly? Dla zaimplementowanego przykładu Matplotlib obsługuje wyświetlanie wielu ułożonych osi

Dziękuję firmie Vestland, kluczem było użycie atrybutu pozycji układu figury i przeskalowanie osi Y w celu prawidłowego dopasowania regulacji. Zobacz [monstrosity] poniżej, aby uzyskać pełną implementację wielu osi w oparciu o przykładowy kod Vestland.

Odpowiedzi
Musisz precyzyjnej kombinacji make_subplots(rows=1, cols=2)
, add_traces()
i fig.update_layout(xaxis=dict(domain=...)
:
Skonfiguruj „zwykły” wykres pomocniczy, używając
fig=make_subplots(rows=1, cols=2)
i dołącz dwa ślady, jak opisano tutaj .Dodaj trzeci ślad z własną oś x, używając
fig.add_trace(go.Scatter([...[, xaxis="x3"))
Następnie dostosuj wykres pomocniczy 1, aby zrobić miejsce na
xaxis3
użycie:fig.update_layout(xaxis3=dict(anchor="free", overlaying="x1", position=0.0))
Dokonaj ostatecznych poprawek za pomocą
fig.update_layout([...], yaxis2=dict(domain=[0.1, 1]))
Powodem, dla którego musisz wziąć domain
pod uwagę, jest to, że position
atrybut w point 3
nie może być ujemny i będziesz musiał w jakiś sposób zrobić miejsce na podwójne osie x. Oto wynik:
Wątek

Kompletny kod:
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()
Edycja: zmniejsz odstęp między tytułem a zakresem.
Jednym ze sposobów jest zmiana pozycji samego tytułu za pomocą fig.update_layout(title=dict())
:
fig.update_layout(
title={
'text': "Plot Title",
'y':0.88,
'x':0.42,
'xanchor': 'left',
'yanchor': 'top'})
Działka 2

Pełny kod dla działki 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()
Pytanie jest nieco podchwytliwe, ale wykonalne. Istnieje przykład tworzenia wielu osi na jednym wykresie. Zasadniczo tworzysz kolejną oś, twinx()
a następnie ustawiasz wszystko w taki sposób, aby ładnie się skończyło. Problem w tym, że matplotlib automatycznie umieszcza inne osie po przeciwnej stronie (czyli 'top'
w przypadku osi X i 'right'
Y). Dlatego musimy ustawić wszystkie te właściwości (gdzie pokazać oś, w jakim kierunku powinna być umieszczona etykieta i znaczniki) oraz kilka fajnych rzeczy, takich jak kolor etykiety i znaczników.
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, użyłem matplotlib ze względu na (moją) wygodę. Preferuję bibliotekę kreślarską, ale bez konkretnego powodu.