Matplotlib: удерживайте линии сетки за графиком, но оси y и x выше
Мне тяжело строить линии сетки под моими графами, не возившись с основной осью x и y zorder:
import matplotlib.pyplot as plt
import numpy as np
N = 5
menMeans = (20, 35, 30, 35, 27)
menStd = (2, 3, 4, 1, 2)
ind = np.arange(N) # the x locations for the groups
width = 0.35 # the width of the bars
fig, ax = plt.subplots()
rects1 = ax.bar(ind, menMeans, width, color='r', yerr=menStd, alpha=0.9, linewidth = 0,zorder=3)
womenMeans = (25, 32, 34, 20, 25)
womenStd = (3, 5, 2, 3, 3)
rects2 = ax.bar(ind+width, womenMeans, width, color='y', yerr=womenStd, alpha=0.9, linewidth = 0,zorder=3)
# add some
ax.set_ylabel('Scores')
ax.set_title('Scores by group and gender')
ax.set_xticks(ind+width)
ax.set_xticklabels( ('G1', 'G2', 'G3', 'G4', 'G5') )
ax.legend( (rects1[0], rects2[0]), ('Men', 'Women') )
fig.gca().yaxis.grid(True, which='major', linestyle='-', color='#D9D9D9',zorder=2, alpha = .9)
[line.set_zorder(4) for line in ax.lines]
def autolabel(rects):
# attach some text labels
for rect in rects:
height = rect.get_height()
ax.text(rect.get_x()+rect.get_width()/2., 1.05*height, '%d'%int(height),
ha='center', va='bottom')
autolabel(rects1)
autolabel(rects2)
plt.show()
Пример берется из matplotlib own, и я немного изменил, чтобы показать, как сделать проблему. Я не могу размещать изображения, но если вы запустите код, вы увидите, что полосы отображаются над горизонтальными линиями сетки, а также над осью x и y. Я не хочу, чтобы ось x и y была скрыта графиком, особенно когда тики также блокируются.
Ответы
Ответ 1
Я пробовал matplotlib 1.2.1, 1.3.1rc2 и master (совершить 06d014469fc5c79504a1b40e7d45bc33acc00773)
Чтобы получить оси шипов сверху баров, вы можете сделать следующее:
for k, spine in ax.spines.items(): #ax.spines is a dictionary
spine.set_zorder(10)
ИЗМЕНИТЬ
Кажется, что я не могу заставить линии тика идти сверху баров. Я пробовал
1. ax.tick_params(direction='in', length=10, color='k', zorder=10)
#This increases the size of the lines to 10 points,
#but the lines stays hidden behind the bars
2. for l in ax.yaxis.get_ticklines():
l.set_zorder(10)
и другим способом без каких-либо результатов. Кажется, что при рисовании баров они помещаются сверху, а zorder игнорируется.
Обходной путь может заключаться в том, чтобы нарисовать тиковые линии наружу
ax.tick_params(direction='out', length=4, color='k', zorder=10)
или как внутри, так и снаружи, используя direction='inout'
EDIT2
Я сделал несколько тестов после комментариев @tcaswell.
Если zorder
в функции ax.bar
установлено равным <= 2, ось, клики и линии сетки вычерчены над столбцами. Если значение valus > 2.01 (значение по умолчанию для оси), то бары рисуются над осью, точками и сеткой. Затем можно установить более высокие значения в шипы (как указано выше), но любая попытка изменить zorder
для линий вычитания просто игнорируется (хотя значения обновляются у соответствующих исполнителей).
Я попробовал использовать zorder=1
для bar
и zorder=0
для сетки, а сетка рисуется сверху. Поэтому zorder игнорируется.
резюме
Мне кажется, что метки и сетка zorder
просто игнорируются и сохраняются до значений по умолчанию. Для меня это ошибка, связанная с bar
или некоторым patches
.
Кстати, я помню, как успешно менялся zorder в метокки при использовании imshow
Ответ 2
У меня была та же проблема с осями, которые рисуются ниже линии сюжета, когда у меня есть линии сетки в фоновом режиме:
ax.yaxis.grid() # grid lines
ax.set_axisbelow(True) # grid lines are behind the rest
Решение, которое сработало для меня, заключалось в том, чтобы установить аргумент zorder
функции plot()
на значение от 1 до 2. Это не сразу понятно, но значение zorder может быть любым числом. Из документации для matplotlib.artist.Artist
класс:
set_zorder (уровень)
Установите zorder для исполнителя. Сначала рисуются художники с более низкими значениями zorder.
ACCEPTS: любое число
Таким образом:
for i in range(5):
ax.plot(range(10), np.random.randint(10, size=10), zorder=i / 100.0 + 1)
Я не проверял значения вне этого диапазона, возможно, они также будут работать.
Ответ 3
У меня была такая же проблема построения над осями, как @luke_16. В моем случае это возникло при использовании опции ax.set_axisbelow(True)
, чтобы установить шлифование позади графиков.
Мое обходное решение для этой ошибки заключается в том, чтобы не использовать встроенную сетку, а имитировать ее:
def grid_selfmade(ax,minor=False):
y_axis=ax.yaxis.get_view_interval()
for xx in ax.xaxis.get_ticklocs():
ax.plot([xx,xx],y_axis,linestyle=':',linewidth=0.5,zorder=0)
if minor==True:
for xx in ax.xaxis.get_ticklocs(minor=True):
ax.plot([xx,xx],y_axis,linestyle=':',linewidth=0.5,zorder=0)
x_axis=ax.xaxis.get_view_interval()
for yy in ax.yaxis.get_ticklocs():
ax.plot(x_axis,[yy,yy],linestyle=':',linewidth=0.5,zorder=0,)
if minor==True:
for yy in ax.yaxis.get_ticklocs(minor=True):
ax.plot(x_axis,[yy,yy],linestyle=':',linewidth=0.5,zorder=0)
Эта функция нуждается только в текущем экземпляре оси, а затем рисует встроенную сетку позади всего остального на основных тиках (необязательно также для небольших тиков).
Для того, чтобы оси и оси располагались над диаграммами, необходимо оставить ax.set_axisbelow(False)
до False
и не использовать zorder
> 2 в графиках. Я управлял zorder графиков без каких-либо zorder
-option, изменяя порядок графических команд в коде.
Ответ 4
Более простое и лучшее решение - скопировать строки из команды сетки и отключить сетку и снова добавить строки снова, но с правильным zorder:
ax.grid(True)
lines = ax1.xaxis.get_gridlines().copy() + ax1.yaxis.get_gridlines().copy()
ax.grid(False)
for l in lines:
ax1.add_line(l)
l.set_zorder(0)