Независимая ось для каждого участка в pandas boxplot

1

Нижеприведенный код помогает получить подзаголовки с уникальными цветными прямоугольниками. Но все подзаголовки имеют общий набор осей 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()

Вот вывод вышеприведенного кода: Изображение 174551

Я пытаюсь иметь отдельные оси x и y для каждого подзаголовка... Изображение 174551

Теги:
pandas
dataframe
matplotlib
boxplot

3 ответа

2

Вам нужно создать фигуру и подзаголовки перед 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,
)
  • 0
    Спасибо за ответ ... ограничение макета для plt.subplots требует, чтобы количество блоков сетки было равно необходимым субплотам. Можете ли вы предложить относительно простой способ размещения 13 участков в макете 2xn? И если я использую аргумент макета в df.boxplot, то ось остается общей.
1

Вы можете снова установить метки метки, например, через

plt.setp(ax.get_xticklabels(), visible=True)

Это не делает оси независимыми, хотя они все еще связаны друг с другом, но похоже, что вы спрашиваете о видимости, а не об общем поведении здесь.

  • 0
    Спасибо за ответ ... но я имел в виду иметь независимые оси с независимыми диапазонами для всех из них (особенно yaxis, где ylims должны быть отдельными для каждого подзаговора). Ограниченные диапазоны препятствуют просмотру блоков с более низким диапазоном данных, но с более высоким диапазоном оси.
  • 0
    В этом случае обратитесь к другому ответу.
0

Если вы действительно думаете, что необходимо разделить оси после создания массива 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()

Получившийся сюжет выглядит следующим образом:

Изображение 174551

Объяснение:

Сначала вам нужно сообщить каждому экземпляру 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 ответ, на мой взгляд, лучший подход.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню