如何让matplotlib中mark_inset连线在图例下方、刻度标记在折线图上方?
解决方案
问题1:调整mark_inset连线至图例下方
mark_inset函数会返回连线和主图上的矩形框两个元素,只需将它们的zorder设为低于图例的zorder即可。同时注意正确获取图例对象(原代码中链式调用set_zorder会导致变量为None):
# 修改图例创建代码,拆分赋值与zorder设置 leg = ax.legend(handlelength=0, handletextpad=0, fontsize=8, fancybox=1, framealpha=1, labelcolor='linecolor', loc='lower center') leg.set_zorder(15) # 修改mark_inset部分,捕获返回元素并设置zorder inset_lines, inset_rect = mark_inset(ax, ax2, loc1=2, loc2=3, fc='none', ec='k', lw=0.8) for line in inset_lines: line.set_zorder(7) # 低于图例的15 inset_rect.set_zorder(7)
问题2:将刻度标记置于折线图上方
在tick_params中添加zorder参数,设置为大于折线的zorder值(折线zorder为4-6,这里设为10即可),确保刻度线和标签显示在折线之上:
# 主图刻度设置 ax.tick_params(axis="both", which='both', labelsize=9, direction='in', left=True, bottom=True, right=True, top=True, zorder=10) # 子图刻度设置 ax2.tick_params(axis="both", which='both', labelsize=9, direction='in', left=True, bottom=True, right=True, top=True, zorder=10)
修改后的完整代码
import matplotlib.pyplot as plt import numpy as np from mpl_toolkits.axes_grid1.inset_locator import InsetPosition, mark_inset plind = 1 # don't want the first plot ### make the main plot fig, ax = plt.subplots(1, 1, figsize=(3.35,2.5), dpi=150) ### make the first plot ### three bits of data ax.plot(f[plind:]/1e3, s[plind:], zorder=4, c='C0', label='BES') ax.plot(ff[plind:]/1e3, ss[plind:], zorder=6, c='C2', label='BES welch, N=2$^3$') ax.plot(fbeam[plind:]/1e3, sbeam[plind:], lw=0.8, zorder=5, c='C1', label='Beam') ### want this fill between on the right ax.fill_between([5e2,4e3], [ylim[0],ylim[0]], [ylim[-1],ylim[-1]], color='C3', alpha=0.3, zorder=3) ### set the x and y limits ax.set_xlim([4e-3, 2e3]) ax.set_ylim([1e-19, 1e-1]) ### want it in log scale ax.set_xscale('log') ax.set_yscale('log') ### set the ylabel ax.set_ylabel('Spectra (V$^2$/Hz)', fontsize=9) ### formatting the ticks - 添加zorder参数 ax.tick_params(axis="both", which='both', labelsize=9, direction='in', left=True, bottom=True, right=True, top=True, zorder=10) ax.minorticks_on() ### make the legend - 拆分赋值与zorder设置 leg = ax.legend(handlelength=0, handletextpad=0, fontsize=8, fancybox=1, framealpha=1, labelcolor='linecolor', loc='lower center') leg.set_zorder(15) ### changing the positions so it fits within my box X0 = ax.get_position().x0 + 0.07 X1 = ax.get_position().x1 - 0.32 Y0 = ax.get_position().y0 + 0.06 Y1 = ax.get_position().y1 + 0.09 ax.set_position([X0, Y0, X1-X0, Y1-Y0]) ### making the inset ax2 = plt.axes([0, 0, 1, 1]) ip = InsetPosition(ax, [1.05, 0., 1, 1]) ax2.set_axes_locator(ip) # 捕获mark_inset返回元素并设置zorder inset_lines, inset_rect = mark_inset(ax, ax2, loc1=2, loc2=3, fc='none', ec='k', lw=0.8) for line in inset_lines: line.set_zorder(7) inset_rect.set_zorder(7) ### plot the data again ax2.plot(f[plind:]/1e3, s[plind:], zorder=4, c='C0') ax2.plot(ff[plind:]/1e3, ss[plind:], zorder=6, c='C2') ax2.plot(fbeam[plind:]/1e3, sbeam[plind:], lw=0.8, zorder=5, c='C1') ### limit it and set the log scale for y only ax2.set_xlim([2, 7]) ax2.set_ylim([5e-12,2e-5]) ax2.set_yscale('log') ### format the ticks - 添加zorder参数 ax2.yaxis.tick_right() ax2.tick_params(axis="both", which='both', labelsize=9, direction='in', left=True, bottom=True, right=True, top=True, zorder=10) ax2.minorticks_on() ax2.set_xticks(np.arange(2,7.1,1)) ### make a joint axis for the xlabel ax3=fig.add_subplot(111, frameon=False) ax3.set_position([ax.get_position().x0, ax.get_position().y0, ax2.get_position().x1-ax.get_position().x0, ax.get_position().y1-ax.get_position().y0]) ax3.tick_params(labelcolor='none', which='both', top=False, bottom=False, left=False, right=False) ax3.set_xlabel('Frequency (kHz)')
内容的提问来源于stack exchange,提问作者Steven Thomas
相关产品推荐
相关产品推荐

