![](/img/trans.png)
[英]Draw lines perpendicular to X axis and Y axis to a curve in matplotlib plot
[英]Matplotlib: keep grid lines behind the graph but the y and x axis above
我很难在图表下绘制网格线而不会弄乱主要的 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 自己的示例,我进行了一些调整以展示如何使问题出现。 我无法发布图像,但如果您运行代码,您会看到条形图绘制在水平网格线上方以及 x 轴和 y 轴上方。 我不希望 x 和 y 轴被图形隐藏,尤其是当刻度也被阻塞时。
当我在背景中有网格线时,我遇到了在绘图线下方绘制轴的相同问题:
ax.yaxis.grid() # grid lines
ax.set_axisbelow(True) # grid lines are behind the rest
对我zorder
的解决方案是将plot()
函数的zorder
参数设置为 1 到 2 之间的值。目前还不清楚,但 zorder 值可以是任何数字。 从matplotlib.artist.Artist
类的文档中:
set_zorder(级别)
为艺术家设置 zorder。 首先绘制具有较低 zorder 值的艺术家。
接受:任何数量
因此:
for i in range(5):
ax.plot(range(10), np.random.randint(10, size=10), zorder=i / 100.0 + 1)
我没有检查过这个范围之外的值,也许它们也可以工作。
我已经尝试过 matplotlib 1.2.1、1.3.1rc2 和 master (commit 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'
和向外,使用direction='inout'
编辑2
我在@tcaswell 评论后做了一些测试。
如果zorder
函数中的ax.bar
设置为 <=2,则在条形上方绘制轴、刻度线和网格线。 如果值 >2.01(轴的默认值),则在轴、刻度线和网格的顶部绘制条形。 然后可以为脊线设置更大的值(如上),但任何更改zorder
的尝试都会被忽略(尽管这些值会在相应的艺术家上更新)。
我已经尝试将zorder=1
用于bar
,将zorder=0
用于网格,并且网格绘制在条形的顶部。 所以 zorder 被忽略。
回顾
在我看来,刻度线和网格zorder
只是被忽略并保留为默认值。 对我来说,这是一个与bar
或某些patches
有某种关系的错误。
顺便说一句,我记得在使用imshow
时成功更改了刻度线中的imshow
我有与@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
。
一个更简单更好的解决方案是从 grid 命令复制线条并禁用网格,然后再次添加线条但使用正确的 zorder:
ax.grid(True)
lines = ax.xaxis.get_gridlines().copy() + ax.yaxis.get_gridlines().copy()
ax.grid(False)
for l in lines:
ax.add_line(l)
l.set_zorder(0)
我知道这是一个很老的问题,但问题似乎仍然存在,所以让我用 Python 3.9.6 和 Matplotlib 3.4.2 写下 MRE 和我的解决方案。
问题
正如 OP 所知,条形图的默认zorder
相对较低。 以下代码生成一个图表,其中刻度线和网格线都在条形图上方。
import matplotlib.pyplot as plt
y = (20, 35, 30, 35, 27)
x = range(len(y))
fig, ax = plt.subplots()
ax.bar(x, y)
ax.grid(True)
ax.tick_params(direction="in", length=10)
plt.show()
可以使用ax.set_axisbelow(True)
移动条形后面的刻度线和网格线,但随后 x 轴上的刻度被条形隐藏。
import matplotlib.pyplot as plt
y = (20, 35, 30, 35, 27)
x = range(len(y))
fig, ax = plt.subplots()
ax.bar(x, y)
ax.grid(True)
ax.tick_params(direction="in", length=10)
ax.set_axisbelow(True) # This line added.
plt.show()
解决方案
在绘制图中的所有元素后重新绘制刻度线。 (我假设它们是不透明的,重绘是无害的。)
import matplotlib.artist
import matplotlib.backend_bases
import matplotlib.pyplot as plt
class TickRedrawer(matplotlib.artist.Artist):
"""Artist to redraw ticks."""
__name__ = "ticks"
zorder = 10
@matplotlib.artist.allow_rasterization
def draw(self, renderer: matplotlib.backend_bases.RendererBase) -> None:
"""Draw the ticks."""
if not self.get_visible():
self.stale = False
return
renderer.open_group(self.__name__, gid=self.get_gid())
for axis in (self.axes.xaxis, self.axes.yaxis):
loc_min, loc_max = axis.get_view_interval()
for tick in axis.get_major_ticks() + axis.get_minor_ticks():
if tick.get_visible() and loc_min <= tick.get_loc() <= loc_max:
for artist in (tick.tick1line, tick.tick2line):
artist.draw(renderer)
renderer.close_group(self.__name__)
self.stale = False
y = (20, 35, 30, 35, 27)
x = range(len(y))
fig, ax = plt.subplots()
ax.bar(x, y)
ax.grid(True)
ax.tick_params(direction="in", length=10)
ax.set_axisbelow(True)
ax.add_artist(TickRedrawer()) # This line added.
plt.show()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.