Используя Seaborn, как мне получить все элементы из точечного графика, чтобы они появлялись над элементами виолончельного участка?

Используя Seaborn 0.6.0, я пытаюсь наложить pointplot на violinplot, Моя проблема в том, что "палки" из отдельных наблюдений за violinplot нанесены поверх маркеров из pointplot как вы можете видеть ниже.

import seaborn as sns
import matplotlib.pyplot as plt

fig, ax = plt.subplots(1, figsize=[12,8])
sns.violinplot(x="day", y="total_bill", hue="smoker", data=tips,
               split=True, inner='stick', ax=ax, palette=['white']*2)
sns.pointplot(x="day", y='total_bill', hue="smoker",
                   data=tips, dodge=0.3, ax=ax, join=False)

Если внимательно присмотреться к этой фигуре, то она появляется, когда зеленая полоса ошибок отображается над палочками для скрипки (см. Субботу), а синие полосы ошибок, а также синие и зеленые точки - под палочками для скрипки.

Я пытался передать различные комбинации zorder для обеих функций, но это не улучшило внешний вид сюжета. Могу ли я что-нибудь сделать, чтобы все элементы из точки появились поверх всех элементов виолончели?

2 ответа

Решение

Похоже на ответ Дизи Асахи, но немного проще. Поскольку мы устанавливаем zorder, нам не нужно рисовать графики в том порядке, в котором мы хотим, чтобы они появлялись, что избавляет от необходимости сортировки художников. Я также делаю так, чтобы точка не появлялась в легенде, где она бесполезна.

import seaborn as sns
import matploltlib.pyplot as plt

tips = sns.load_dataset("tips")

ax = sns.pointplot(x="day", y='total_bill', hue="smoker",
              data=tips, dodge=0.3, join=False, palette=['white'])
plt.setp(ax.lines, zorder=100)
plt.setp(ax.collections, zorder=100, label="")

sns.violinplot(x="day", y="total_bill", hue="smoker", data=tips,
               split=True, inner='stick', ax=ax)

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

tips = sns.load_dataset("tips")

fig, ax = plt.subplots(1, figsize=[12,8])
sns.violinplot(x="day", y="total_bill", hue="smoker", data=tips,
               split=True, inner='stick', ax=ax)
a = list(ax.get_children()) # gets the artists created by violinplot
sns.pointplot(x="day", y='total_bill', hue="smoker",
                   data=tips, dodge=0.3, ax=ax, join=False, palette=['white'])
b = list(ax.get_children()) # gets the artists created by violinplot+pointplot

# get only the artists in `b` that are not in `a`
c = set(b)-set(a)
for d in c:
    d.set_zorder(1000) # set a-order to a high value to be sure they are on top

РЕДАКТИРОВАТЬ: после комментария @tcaswell, я также предлагаю другое решение (создать 2 оси, по одному для каждого типа графика). Однако обратите внимание, что если вы собираетесь направить маршрут, вам придется переделать легенду, так как они в конечном итоге накладываются в данном примере.

tips = sns.load_dataset("tips")

fig = plt.figure(figsize=[12,8])
ax1 = fig.add_subplot(111)
sns.violinplot(x="day", y="total_bill", hue="smoker", data=tips,
               split=True, inner='stick', ax=ax1)

ax2 = fig.add_subplot(111, frameon=False, sharex=ax1, sharey=ax1)
sns.pointplot(x="day", y='total_bill', hue="smoker",
                   data=tips, dodge=0.3, ax=ax2, join=False, palette=['white'])
ax2.set_xlabel('')
ax2.set_ylabel('')

Другие вопросы по тегам