Следующий скрипт создает экземпляр Figure
с синей гистограммой за вторичными линиями сетки, которые сами находятся за оранжевой кумулятивной гистограммой.
import matplotlib.pyplot as plt
import numpy as np
plt.style.use("seaborn-darkgrid")
np.random.seed(42)
foo = np.random.randn(1000)
fig, ax = plt.subplots()
ax.hist(foo, bins=50)
ax2 = ax.twinx()
ax2.hist(
foo, bins=50, density=True, cumulative=True, histtype = "step", color = "tab:orange"
)
plt.show()
Я искал способ разместить линии сетки за синей гистограммой и нашел связанную с этим проблему в matplotlib/matplotlib#7984. Это говорит
you can't interleave the drawing orders of artists from one Axes with those from another
и это объясняет, почему ax2.set_axisbelow(True)
не влияет на основной Axes
.
Могу ли я каким-то образом достичь своей цели? Обходные пути приветствуются (я полагаю, что канонического решения, согласно приведенной выше цитате, не существует).
Ваш желаемый порядок рисования (сначала самый задний)
Однако это невозможно, как видно из комментария
you can't interleave the drawing orders of artists from one Axes with those from another
Это означает, что вам нужно 4 оси вместо двух.
Это может выглядеть так:
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
foo = np.random.randn(1000)
fig, ax1a = plt.subplots() # ax1a for the histogram grid
ax2a = ax1a.twinx() # ax2a for the cumulative step grid
ax1b = ax1a.twinx() # ax1b for the histogram plot
ax2b = ax1a.twinx() # ax2a for the cumulative step plot
# Link the respective y-axes for grid and plot
ax1a.get_shared_y_axes().join(ax1a, ax1b)
ax2a.get_shared_y_axes().join(ax2a, ax2b)
# Remove ticks and labels and set which side to label
ticksoff = dict(labelleft=False, labelright=False, left=False, right=False)
ax1a.tick_params(axis = "y", **ticksoff)
ax2a.tick_params(axis = "y", **ticksoff)
ax1b.tick_params(axis = "y", labelleft=True, labelright=False, left=True, right=False)
ax2b.tick_params(axis = "y", labelleft=False, labelright=True, left=False, right=True)
# Spines off
for ax in [ax1a, ax2a, ax1b]:
for k,v in ax.spines.items():
v.set_visible(False)
ax1b.hist(foo, bins=50)
ax2b.hist(
foo, bins=50, density=True, cumulative=True, histtype = "step", color = "tab:orange"
)
ax1a.grid()
ax2a.grid()
plt.show()
Я не знал, что мы можем сделать четверняшки, используя twinx()
, и никогда бы не придумал эту идею. Спасибо!
Я только что попробовал ваш код и у меня есть два вопроса. i) Что делает оператор for
? Сюжеты и без этого хорошо смотрятся. ii) порядок создания экземпляров, кажется, имеет значение: т. е. создание ax1b
до того, как ax2a
наложит вторичную сетку на синий график. Почему twinx()
так себя ведет? Я открою еще один вопрос, если он предпочтительнее (особенно для последнего).
i) Сравнивая Без удаления шипов, с удалением шипов, я нахожу разницу достаточно разительной, чтобы оставить этот цикл for в коде. Но, конечно, вы можете отказаться от этого, если хотите. ii) Ключевым здесь является порядок, в котором оси рисуются на экране. Если не указано другое zorder
, они появляются в порядке их создания. Это решение обязательно требует, чтобы две оси с сетками были ниже двух других осей.
Так сложно найти информацию по этой теме, этот ответ потрясающий! Большое спасибо!
Уже есть принятый и работающий ответ, но я думаю, что есть еще один способ решить эту проблему, немного улучшив эстетику:
ax2
ax.set_ylim()
и ax.set_yticks()
, чтобы вручную указать диапазон и деления на первой оси Y, чтобы деления совпадали с делениями на ax2
. Таким образом, нет необходимости во втором наборе линий сетки, и график становится менее визуально загруженным.В приведенном выше примере это можно сделать следующим образом:
ax2.set_ylim(0.0, 1.05)
ax2.set_yticks(0.0, 0.2, 0.4, 0.6, 0.8, 1.0)
ax.set_ylim(0.0, 70*1.05)
ax.set_yticks(0, 14, 28, 42, 56, 70)
ax.grid(both)
ax.set_axisbelow(True)
Конечно, это может работать лучше или хуже в зависимости от реальных чисел, и в примере я перешел к нецелым числам. Можно было бы использовать отметки 15, 30... или изменить масштаб второй оси Y до 140 или первой до 100, но идеального решения не существует. Автоматизировать этот метод, конечно, было бы сложно, но я иногда использую его, если мне нужно сделать красивые графики для определенного набора данных, когда затраты времени на его настройку оправданы.
Это правильный ответ. Спасибо за объяснение.