Matplotlib: keep grid lines behind the graph but the y and x axis above
Solution 1
I have tried matplotlib 1.2.1, 1.3.1rc2 and master (commit 06d014469fc5c79504a1b40e7d45bc33acc00773)
To get the axis spines on top of the the bars you can do the following:
for k, spine in ax.spines.items(): #ax.spines is a dictionary
spine.set_zorder(10)
EDIT
It seems that I can't make the tick lines to go on top of the bars. I've tried
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)
and some other way with no results. It seems that when drawing the bars they are put on top and the zorder is ignored
A workaround could be to draw the tick lines outwards
ax.tick_params(direction='out', length=4, color='k', zorder=10)
or both in and outwards, using direction='inout'
EDIT2
I've done some test after @tcaswell comments.
If zorder
in the ax.bar
function is set to be <=2, the axis, ticklines and grid lines are drawn above the bars. If the valus is >2.01 (the default value for axis) the bars are drawn on top of the axis, ticklines and grid. Then it possible to set larger values to the spines (as above) but any attempt to change the zorder
of the ticklines is simply ignored (although the values are updated on the corresponding artists).
I've tried the to use zorder=1
for the bar
and zorder=0
for the grid and the grid is drawn on top of the bars. So zorder is ignored.
recap
It seems to me that ticklines and grid zorder
are just ignored and kept to the default values. For me this is a bug somehow related with bar
or some patches
.
BTW, I do remember changing successfully the zorder in ticklines when using imshow
Solution 2
I had the same problem of axes getting drawn below the plot line when I have grid lines in the background:
ax.yaxis.grid() # grid lines
ax.set_axisbelow(True) # grid lines are behind the rest
The solution that worked for me was to set the zorder
argument of the plot()
function to a value between 1 and 2. It is not immediately clear, but the zorder value can be any number. From the documentation for the matplotlib.artist.Artist
class:
set_zorder(level)
Set the zorder for the artist. Artists with lower zorder values are drawn first.
ACCEPTS: any number
Therefore:
for i in range(5):
ax.plot(range(10), np.random.randint(10, size=10), zorder=i / 100.0 + 1)
I haven't checked for values outside this range, maybe they would also work.
Solution 3
I had the same problem of plotting above the axes as @luke_16. In my case, it arose when using the option ax.set_axisbelow(True)
to set the grind behind the plots.
My workaround for this bug is, not to use the onboard-grid, but to simulate it:
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)
This function only needs the current axis-instance and then draws an onboard-like grid behind everything else at the major ticks (optional also for minor ticks).
For having the axis and axis ticks on top of the graphs, it is necessary to leave ax.set_axisbelow(False)
to False
and not to use zorder
>2 in plots. I managed the zorder of plots without any zorder
-option by changing the order of plot-commands in code.
Related videos on Youtube
luke_16
Updated on September 15, 2022Comments
-
luke_16 about 1 year
I am having a hard time plotting grid lines under my graphs without messing with the main x and y axis 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()
The example is taken from matplotlib's own, and I have tweaked a little to show how to make the problem appear. I cannot post images but if you run the code you will see that the bars are plotted above the horizontal grid lines as well as above the x and y axis. I do not want the x and y axis being hidden by the graph, especially when the ticks are also getting blocked.
-
tacaswell about 10 yearsthat sounds like a bug, can you check if it also happen on master?
-
Francesco Montesano about 10 yearsI give a try and let you know
-
Francesco Montesano about 10 years@tcaswell I've tried on 1.3.1rc2 and master (just fetched) and does not work. It's a bug then. Who files it? [I can try to give a look at the source code later today if I find any hint about the problem]
-
tacaswell about 10 yearsactually, I think this is more of a 'feature' than a bug as the grid lines inherit their z order from the axis objects.
-
tacaswell about 10 yearstry making the zorder of your bar graph negative.
-
Francesco Montesano about 10 years@tcaswell: if I put
-3
the grid and the ticklines are above. Are you saying that either grids and ticklines are above or below the bars? I'm fine if this is the default, but you should be able to change it if needed. -
luke_16 about 10 years@tcaswell the fact that it inherits the zorder from the axis object should not mean that I cannot change it. That is what I am trying to do in ax.yaxis.grid(True, which='major', linestyle='-', color='#D9D9D9',zorder=2, alpha = .9)
-
tacaswell about 10 years@luke_16 iirc the tick lines + axes are drawn in one shot by the renderers so they can't have different zorders.
-
J_Scholz over 3 yearsI don't understand what ax1 is in your solution.