Контроль свойств маркера в морском попарном боксплоте - PullRequest
0 голосов
/ 20 марта 2020

Я пытаюсь построить блокпост для двух разных наборов данных на одном графике. Ось X - это часы дня, а ось Y - от 0 до 1 (назовем это эффективностью). Я хотел бы иметь разные маркеры для средств каждого блока набора данных. Я использую «meanprops» для морских перевозок, но это меняет стиль маркера для обоих наборов данных одновременно. Я добавил 2000 строк данных в Excel, которые можно загрузить здесь . Значения могут не совпадать с указанными на картинке, но их должно быть достаточно.

По сути, я хочу, чтобы красные квадраты были голубыми на оранжевом поле и красным на синем. Вот что мне удалось сделать до сих пор:

Current Boxplot output

Я попытался изменить средние предложения, используя словарь с метками в качестве ключей, но, похоже, вводить все oop (в PyCharm это говорит Оценка ...)

import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd

#make sure you have your path sorted out
group1 = pd.read_excel('group1.xls')

ax,fig = plt.subplots(figsize = (20,10))

#does not work
#ax = sns.boxplot(data=group1, x='hour', y='M1_eff', hue='labels',showfliers=False, showmeans=True,\
#                 meanprops={"marker":{'7':"s",'8':'s'},"markerfacecolor":{'7':"white",'8':'white'}, 
#"markeredgecolor":{'7':"blue",'8':'red'})

#works but produces similar markers
ax = sns.boxplot(data=group1, x='hour', y='M1_eff', hue='labels',showfliers=False, showmeans=True,\
             meanprops={"marker":"s","markerfacecolor":"white", "markeredgecolor":"blue"})

plt.legend(title='Groups', loc=2, bbox_to_anchor=(1, 1),borderaxespad=0.5)

# Add transparency to colors
for patch in ax.artists:
     r, g, b, a = patch.get_facecolor()
     patch.set_facecolor((r, g, b, .4))
ax.set_xlabel("Hours",fontsize=14)
ax.set_ylabel("M1 Efficiency",fontsize=14)
ax.tick_params(labelsize=10)
plt.show()

Я также попробовал FacetGrid , но безрезультатно (Останавливается на "Оценка ...") :

g = sns.FacetGrid(group1, col="M1_eff", hue="labels",hue_kws=dict(marker=["^", "v"]))
g = (g.map(plt.boxplot, "hour", "M1_eff")
     .add_legend())
g.show()

Любая помощь приветствуется!

1 Ответ

1 голос
/ 21 марта 2020

Я не думаю, что вы можете сделать это, используя sns.boxplot() напрямую. Я думаю, вам придется рисовать средства "от руки"

N=100
df = pd.DataFrame({'hour':np.random.randint(0,3,size=(N,)),
                   'M1_eff': np.random.random(size=(N,)),
                   'labels':np.random.choice([7,8],size=(N,))})

x_col = 'hour'
y_col = 'M1_eff'
hue_col = 'labels'
width = 0.8
hue_order=[7,8]

marker_colors = ['red','blue']

# get the offsets used by boxplot when hue-nesting is used
# https://github.com/mwaskom/seaborn/blob/c73055b2a9d9830c6fbbace07127c370389d04dd/seaborn/categorical.py#L367
n_levels = len(hue_order)
each_width = width / n_levels
offsets = np.linspace(0, width - each_width, n_levels)
offsets -= offsets.mean()

fig, ax = plt.subplots()
ax = sns.boxplot(data=df, x=x_col, y=y_col, hue=hue_col, hue_order=hue_order, showfliers=False, showmeans=False)

means = df.groupby([hue_col,x_col])[y_col].mean()
for (gr,temp),o,c in zip(means.groupby(level=0),offsets,marker_colors):
    ax.plot(np.arange(temp.values.size)+o, temp.values, 's', c=c)

enter image description here

...