Как отсортировать значения блочной диаграммы в порядке возрастания (по медианным значениям)? - PullRequest
0 голосов
/ 20 ноября 2018

Это мои панды DataFrame:

Area            Gender  Quantity
XXX             Men     115
XXX             Men     105    
XXX             Men     114
YYY             Men     100
YYY             Men     90    
YYY             Men     95
YYY             Men     101
XXX             Women   120    
XXX             Women   122
XXX             Women   115
XXX             Women   117    
YYY             Women   91
YYY             Women   90
YYY             Women   90

Вот так я и создал коробочный график.

import seaboard as sns
import matplotlib.pyplot as pat

fig, ax = plt.subplots(figsize=(15,11))
ax = sns.boxplot(x="Area", y="Quantity", hue="Gender", data=df, palette="Set3")

Я хочу отсортировать группы Area по медиане Quantityв порядке возрастания.Как я могу это сделать?

1 Ответ

0 голосов
/ 20 ноября 2018

Это невозможно сразу с текущими версиями seaborn (<= 0.9.0).Лучшее, что вы можете сделать в данный момент, это установить <code>hue_order (например: ['Woman', 'Men']), но он также будет применен ко всем группам, что не то, что вы хотите.

Кроме того, расширениеboxplot() не так просто, потому что seaborn не раскрывает классы, отвечающие за построение в официальном API.См. здесь точку входа в boxplot() (постоянная ссылка на мастер-версию seaborn по состоянию на 20.10.2018, git hash: 84ca6c6).

Если вы не боитесь работать с внутреннимМорские объекты, вы можете создать свою собственную версию sorted_boxplot().Возможно, самый простой способ добиться порядка - изменить следующую строку в _BoxPlotter.draw_boxplot() (постоянная ссылка, git: 84ca6c6):

# Original
center = i + offsets[j]

# Fix:
ordered_offsets = ...
center = i + ordered_offsets[j]

center относится к положениюboxplot, i - это индекс группы, а j - это индекс текущего hue.Я проверил это, выведя из _BoxPlotter и переопределив draw_boxplot(), см. Ниже некоторый код.

PS: Было бы замечательно, если бы кто-то более подробно остановился на этом, чтобы предложить запрос на извлечение морского происхождения.Эта функция, безусловно, полезна.


У меня работает следующее (python 3.6, seaborn 0.9.0):

import numpy as np
import seaborn as sns
from seaborn.categorical import _BoxPlotter
from seaborn.utils import remove_na

class SortedBoxPlotter(_BoxPlotter):
    def __init__(self, *args, **kwargs):
        super(SortedBoxPlotter, self).__init__(*args, **kwargs)

    def draw_boxplot(self, ax, kws):
        '''
        Below code has been copied partly from seaborn.categorical.py
        and is reproduced only for educational purposes.
        '''
        if self.plot_hues is None:
            # Sorting by hue doesn't apply here. Just
            return super(SortedBoxPlotter, self).draw_boxplot(ax, kws)

        vert = self.orient == "v"
        props = {}
        for obj in ["box", "whisker", "cap", "median", "flier"]:
            props[obj] = kws.pop(obj + "props", {})

        for i, group_data in enumerate(self.plot_data):

            # ==> Sort offsets by median
            offsets = self.hue_offsets
            medians = [ np.median(group_data[self.plot_hues[i] == h])
                        for h in self.hue_names ]
            offsets_sorted = offsets[np.argsort(medians)]

            # Draw nested groups of boxes
            for j, hue_level in enumerate(self.hue_names):

                # Add a legend for this hue level
                if not i:
                    self.add_legend_data(ax, self.colors[j], hue_level)

                # Handle case where there is data at this level
                if group_data.size == 0:
                    continue

                hue_mask = self.plot_hues[i] == hue_level
                box_data = remove_na(group_data[hue_mask])

                # Handle case where there is no non-null data
                if box_data.size == 0:
                    continue

                # ==> Fix ordering
                center = i + offsets_sorted[j]

                artist_dict = ax.boxplot(box_data,
                                         vert=vert,
                                         patch_artist=True,
                                         positions=[center],
                                         widths=self.nested_width,
                                         **kws)
                self.restyle_boxplot(artist_dict, self.colors[j], props)

def sorted_boxplot(x=None, y=None, hue=None, data=None, order=None, hue_order=None,
                   orient=None, color=None, palette=None, saturation=.75,
                   width=.8, dodge=True, fliersize=5, linewidth=None,
                   whis=1.5, notch=False, ax=None, **kwargs):

    '''
    Same as sns.boxplot(), except that nested groups of boxes are plotted by
    increasing median.
    '''

    plotter = SortedBoxPlotter(x, y, hue, data, order, hue_order,
                               orient, color, palette, saturation,
                               width, dodge, fliersize, linewidth)
    if ax is None:
        ax = plt.gca()
    kwargs.update(dict(whis=whis, notch=notch))
    plotter.plot(ax, kwargs)
    return ax

Для запуска с вашими примерами данных:

import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame([ ["XXX", "Men" ,  115],
                    ["XXX", "Men" ,  105    ],
                    ["XXX", "Men" ,  114],
                    ["YYY", "Men" ,  100],
                    ["YYY", "Men" ,  90    ],
                    ["YYY", "Men" ,  95],
                    ["YYY", "Men" ,  101],
                    ["XXX", "Women", 120    ],
                    ["XXX", "Women", 122],
                    ["XXX", "Women", 115],
                    ["XXX", "Women", 117    ],
                    ["YYY", "Women", 91],
                    ["YYY", "Women", 90],
                    ["YYY", "Women", 90]],
                  columns = ["Area", "Gender", "Quantity"])
sorted_boxplot(x="Area", y="Quantity", hue="Gender", data=df, palette="Set3")
plt.show()

Результат:

enter image description here

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