Fabuła: Jak wyświetlić więcej niż 2 tytuły / zakresy na osi X na tym samym wykresie pomocniczym?

Nov 28 2020

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

2 vestland Nov 29 2020 at 22:47

Musisz precyzyjnej kombinacji make_subplots(rows=1, cols=2), add_traces()i fig.update_layout(xaxis=dict(domain=...):

  1. Skonfiguruj „zwykły” wykres pomocniczy, używając fig=make_subplots(rows=1, cols=2)i dołącz dwa ślady, jak opisano tutaj .

  2. Dodaj trzeci ślad z własną oś x, używając fig.add_trace(go.Scatter([...[, xaxis="x3"))

  3. Następnie dostosuj wykres pomocniczy 1, aby zrobić miejsce na xaxis3użycie:fig.update_layout(xaxis3=dict(anchor="free", overlaying="x1", position=0.0))

  4. Dokonaj ostatecznych poprawek za pomocą fig.update_layout([...], yaxis2=dict(domain=[0.1, 1]))

Powodem, dla którego musisz wziąć domainpod uwagę, jest to, że positionatrybut w point 3nie 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()
1 max Nov 30 2020 at 08:30

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.