Как сузить выбросы на коробчатой ​​диаграмме? - PullRequest
0 голосов
/ 06 мая 2020

Я пытаюсь использовать matlotlib для управления появлением выбросов в прямоугольной диаграмме с "зубцами", созданной с помощью seaborn. Мой код выглядит следующим образом:

ax = sns.boxplot(y= "class", x = "Proba",hue = "Stage", data = df_tidy, notch = True,
                 showmeans= True, meanprops={"marker": ".", "markerfacecolor":"red", "markeredgecolor": "red"},
                 flierprops = dict(markerfacecolor = '.1', markersize = .0018, linestyle = "none", markeredgecolor='steelblue'),
                 boxprops=dict(alpha=.7), width=.3)

Однако у меня есть довольно большое количество выбросов, которые делают коробчатую диаграмму немного непривлекательной с эстетической точки зрения; в частности, я вижу почти непрерывный поток выбросов за усами. К сожалению, я не могу сгенерировать фиктивные данные для этого примера, так как для этого требуется, чтобы в большом наборе данных было много выбросов. выбросы и уменьшить их размер, но это не сильно улучшило результат. Один из вариантов, который работал достаточно хорошо, заключался в установке аргумента «стиль линий» в flierprops на «пунктирный».

Однако есть ли способ передать аргумент "дрожание" в словарь flierprops? Может кто-нибудь предложить способ сделать выбросы дрожащими?

1 Ответ

1 голос
/ 06 мая 2020

Первая часть кода пытается создать MRE.

Чтобы иметь очень маленькие маркеры, можно установить цвет линии на 'none', чтобы сделать эти линии вокруг маркеров полностью невидимыми, и использовать маркер пиксель ',' . Многие маркеры рядом с одним и тем же местом можно улучшить с помощью альфа-канала. вам может потребоваться поэкспериментировать с вашими данными, чтобы выяснить, какое количество альфа дает наилучший результат. получить строки, принадлежащие ax. Кажется, что каждый седьмой Line2D в списке соответствует выбросам. Мы можем извлечь их Y-позиции, добавить немного дрожания и заменить их.

import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

N = 100000
x = np.where(np.random.randint(20, size=N * 6) > 0,
             np.random.normal(np.repeat([30, 35], N * 3), 10, N * 6) * np.tile([1, 1.3, 1.1], N * 2),
             np.random.normal(80, 5, N * 6))
y = np.tile(['A', 'B', 'C'], N * 2)
hue = np.repeat(['X', 'Y'], N * 3)

ax = sns.boxplot(y=y, x=x, hue=hue, notch=True,
                 showmeans=True, meanprops={"marker": ".", "markerfacecolor": "red", "markeredgecolor": "red"},
                 flierprops=dict(marker=',', markerfacecolor='steelblue', markeredgecolor='none', alpha=.1),
                 boxprops=dict(alpha=.7), width=.3)

for line in ax.get_lines()[6::7]:
    # line.set_mec('purple') # to test that we have the correct Line2Ds
    yoffsets = line.get_ydata()
    line.set_ydata(yoffsets + np.random.uniform(-0.05, 0.05, yoffsets.size))

jittered outliers

...