Сюжет: как отобразить более двух заголовков / диапазонов по осям x на одном подзаголовке?
Я использую Plotly и делаю подзаголовки точечной диаграммы с общей осью y и разными осями x. Я попытался использовать синтаксис объекта figure (fig ['layout'] [data index]) для отображения нескольких сложенных осей x и их соответствующих диапазонов. Мне удалось показать только две оси x и диапазоны для каждого подзаголовка, назначив атрибуты «верх» и «низ» боковому атрибуту макета рисунка. Во втором столбце справа на рисунке ниже должны отображаться заголовки / диапазоны для серий T5, T6 и T7, но отображаются только заголовок и диапазон для T5 и T7.
Можно ли отобразить более двух заголовков / диапазонов осей x на одном подзаголовке в Plotly? Для реализованного примера Matplotlib поддерживает отображение нескольких составных осей
Спасибо Vestland, ключевым моментом было использование атрибута position макета фигуры и масштабирование оси Y для правильного соответствия корректировке. См. [Monstrosity] ниже для полной реализации нескольких осей на основе примера кода Vestland.
Ответы
Вам необходимо точное сочетание make_subplots(rows=1, cols=2), add_traces()и fig.update_layout(xaxis=dict(domain=...):
Создайте «обычный» подзаголовок, используя
fig=make_subplots(rows=1, cols=2)две трассировки, как описано здесь .Добавьте третью трассу с собственной осью x, используя
fig.add_trace(go.Scatter([...[, xaxis="x3"))Затем настройте подзаговор 1, чтобы освободить место для
xaxis3использования:fig.update_layout(xaxis3=dict(anchor="free", overlaying="x1", position=0.0))Внесите некоторые окончательные корректировки, используя
fig.update_layout([...], yaxis2=dict(domain=[0.1, 1]))
Причина, по которой вам придется принять domainво внимание, заключается в том, что positionатрибут в point 3не может быть отрицательным, и вам нужно как-то освободить место для двойных осей x. Вот результат:
участок
Полный код:
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()
Изменить: сократить расстояние между заголовком и диапазоном.
Один из подходов - изменить положение самого заголовка, используя fig.update_layout(title=dict()):
fig.update_layout(
title={
'text': "Plot Title",
'y':0.88,
'x':0.42,
'xanchor': 'left',
'yanchor': 'top'})
Сюжет 2
Полный код для участка 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()
Вопрос немного сложный, но выполнимый. Вот пример того, как создать несколько осей на одном графике. По сути, вы создаете еще одну ось, twinx()а затем настраиваете все таким образом, чтобы все получилось красиво. Проблема в том, что matplotlib автоматически размещает другие оси на противоположной стороне (так 'top'в случае оси x и 'right'в случае оси y). Вот почему нам нужно установить все эти свойства (где показывать ось, в каком направлении должны размещаться метка и метки) и несколько приятных вещей, таких как цвет метки и меток.
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()
Кстати, я использовал matplotlib из-за (моего) удобства. Я предпочитаю эту библиотеку для построения графиков, но без особой причины.