Нижеприведенный код помогает получить подзаголовки с уникальными цветными прямоугольниками. Но все подзаголовки имеют общий набор осей x и y. Я с нетерпением ожидал наличия независимой оси для каждого подзаголовка:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import PathPatch
df = pd.DataFrame(np.random.rand(140, 4), columns=['A', 'B', 'C', 'D'])
df['models'] = pd.Series(np.repeat(['model1','model2', 'model3', 'model4', 'model5', 'model6', 'model7'], 20))
bp_dict = df.boxplot(
by="models",layout=(2,2),figsize=(6,4),
return_type='both',
patch_artist = True,
)
colors = ['b', 'y', 'm', 'c', 'g', 'b', 'r', 'k', ]
for row_key, (ax,row) in bp_dict.iteritems():
ax.set_xlabel('')
for i,box in enumerate(row['boxes']):
box.set_facecolor(colors[i])
plt.show()
Вот вывод вышеприведенного кода:
Я пытаюсь иметь отдельные оси x и y для каждого подзаголовка...
Вам нужно создать фигуру и подзаголовки перед df.boxplot()
и передать это как аргумент df.boxplot()
. Это также означает, что вы можете удалить layout=(2,2)
аргумента layout=(2,2)
:
fig, axes = plt.subplots(2,2,sharex=False,sharey=False)
Затем используйте:
bp_dict = df.boxplot(
by="models", ax=axes, figsize=(6,4),
return_type='both',
patch_artist = True,
)
Вы можете снова установить метки метки, например, через
plt.setp(ax.get_xticklabels(), visible=True)
Это не делает оси независимыми, хотя они все еще связаны друг с другом, но похоже, что вы спрашиваете о видимости, а не об общем поведении здесь.
Если вы действительно думаете, что необходимо разделить оси после создания массива boxplot
, вы можете это сделать, но вы должны делать все "вручную". matplotlib
время спустя просматривая stackoverflow и просматривая matplotlib
документации matplotlib
я придумал следующее решение, чтобы разделить yaxes
экземпляров Axes
, для xaxes
вам нужно было бы пойти аналогично:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import PathPatch
from matplotlib.ticker import AutoLocator, AutoMinorLocator
##using differently scaled data for the different random series:
df = pd.DataFrame(
np.asarray([
np.random.rand(140),
2*np.random.rand(140),
4*np.random.rand(140),
8*np.random.rand(140),
]).T,
columns=['A', 'B', 'C', 'D']
)
df['models'] = pd.Series(np.repeat([
'model1','model2', 'model3', 'model4', 'model5', 'model6', 'model7'
], 20))
##creating the boxplot array:
bp_dict = df.boxplot(
by="models",layout = (2,2),figsize=(6,8),
return_type='both',
patch_artist = True,
rot = 45,
)
colors = ['b', 'y', 'm', 'c', 'g', 'b', 'r', 'k', ]
##adjusting the Axes instances to your needs
for row_key, (ax,row) in bp_dict.items():
ax.set_xlabel('')
##removing shared axes:
grouper = ax.get_shared_y_axes()
shared_ys = [a for a in grouper]
for ax_list in shared_ys:
for ax2 in ax_list:
grouper.remove(ax2)
##setting limits:
ax.axis('auto')
ax.relim() #<-- maybe not necessary
##adjusting tick positions:
ax.yaxis.set_major_locator(AutoLocator())
ax.yaxis.set_minor_locator(AutoMinorLocator())
##making tick labels visible:
plt.setp(ax.get_yticklabels(), visible=True)
for i,box in enumerate(row['boxes']):
box.set_facecolor(colors[i])
plt.show()
Получившийся сюжет выглядит следующим образом:
Объяснение:
Сначала вам нужно сообщить каждому экземпляру Axes
что он не должен делиться своими yaxis
с любым другим экземпляром Axis
. Это сообщение Axes.get_shared_y_axes()
меня к тому, как это сделать. Axes.get_shared_y_axes()
возвращает объект Grouper, который содержит ссылки на все другие экземпляры Axes
с которыми текущие Axes
должны делиться своим xaxis
. Цикл через эти экземпляры и вызов Grouper.remove
делает фактическое разделение.
Когда yaxis
не разделен, y
ограничения и y
тики необходимо отрегулировать. Первый может быть достигнут с помощью ax.axis('auto')
и ax.relim()
(не уверен, нужна ли вторая команда). ax.yaxis.set_major_locator()
можно отрегулировать, используя ax.yaxis.set_major_locator()
и ax.yaxis.set_minor_locator()
с соответствующими локаторами. Наконец, метки меток можно сделать видимыми с помощью plt.setp(ax.get_yticklabels(), visible=True)
(см. Здесь).
Учитывая все это, @DavidG ответ, на мой взгляд, лучший подход.