Это невозможно сразу с текущими версиями 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](https://i.stack.imgur.com/WZOID.png)