Matplotlib等高线图clabel标签靠近边界的优化方案求助
如何优化Matplotlib中等高线标签的位置?
我在使用Matplotlib绘制等高线图时,发现clabel生成的标签过于靠近图边界。尝试过manual参数,但由于是通过循环生成多条等高线,无法预先确定每个标签的放置位置。
我的绘图代码如下:
#!/usr/bin/env python # -*- coding: utf-8 -*- """ Test contours """ # %% import numpy as np import matplotlib.pyplot as plt g = 9.8 rhoh = 929 # hydrate density rhol = 1029 # seawater density rhos = 2650 # dry sediment density psi = 25 # constant friction angle ° H = 137.95 # min depth of the hydrate layer m D = 17.6 # max thickness of the hydrate layer m nu = [0.15, 0.45] # min and max Poisson's ratio # ----- Constants ----- # def weight(phi=0.483): gammas = rhos * g # unit weight of dry soil gammal = rhol * g # unit weight of seawater return gammal, (gammas - gammal) * (1 - phi) # ----- Critical stress ----- # def normal(H, beta): beta = np.deg2rad(beta) _, gammap = weight() return H * gammap * np.cos(beta) ** 2 def slip(H, beta, nu, E): sigma0 = normal(H, beta) G = E / 2 / (1 + nu) df = np.tan(np.deg2rad(psi)) du_slip = sigma0 - 0.579 * G / 100 / df / (1 - nu) du_slip[du_slip < 0] = np.nan return du_slip def mesh(N): Hd = H + np.linspace(0, D, N) nuu = np.linspace(nu[0], nu[1], N) Hd, nnuu = np.meshgrid(Hd, nuu) return Hd, nnuu E = 70e6 beta = [5, 10, 15] N = 1000 Hd, nu = mesh(N) du_slip = [] for i in range(len(beta)): du_slip.append(slip(Hd, beta[i], nu, E)) styles = ["-", "--", ":", "-."] colors = ["k", "b", "r", "g"] levels = np.arange(0.5, 0.9, 0.1) for i in range(len(beta)): c = plt.contour( Hd - H, nu, du_slip[i] / 1e6, levels, colors=colors[i], linestyles=styles[i], linewidths=1, ) # 临时解决方法(注释状态) cl = plt.clabel(c, levels, fontsize=8, use_clabeltext=True) # for l in cl: # # 移动标签位置避免重叠 # l.set_position( # ( # l.get_position()[0] - 1, # l.get_position()[1] # - 0.005 # * np.tan(l.get_rotation() * np.pi / 180), # 0.005是试出来的数值 # ) # ) plt.plot([], [], styles[i], color="k", label=rf"$\beta$={beta[i]}°") plt.legend(loc="lower left", frameon=True) plt.xlabel(r"$D$ (m)", fontsize=12) plt.ylabel(r"$\nu$", rotation="horizontal", fontsize=12, labelpad=15) plt.title(r"$\Delta u_\mathrm{slip}$ (MPa)", fontsize=12) plt.savefig("test1.png", bbox_inches="tight")
我当前的临时解决方法是获取每个标签的位置和方向,沿等高线稍微下移标签:
cl = plt.clabel(c, levels, inline=False, fontsize=8, use_clabeltext=True) for l in cl: # 移动标签位置避免重叠 l.set_position( ( l.get_position()[0] - 1, l.get_position()[1] - 0.005 * np.tan(l.get_rotation() * np.pi / 180), # 0.005是试出来的数值 ) )
调整后图的效果有所改善,但仍不够理想。
优化方案
1. 利用clabel的offset参数(Matplotlib 3.7+)
如果你的Matplotlib版本是3.7及以上,可以直接使用offset参数,让标签沿等高线法线方向偏移,避免靠近边界:
cl = plt.clabel(c, levels, fontsize=8, use_clabeltext=True, offset=5)
offset的单位是点(points),可以根据需要调整数值,让标签远离边界和等高线。
2. 基于边界距离自动调整标签位置
通过计算标签当前位置到图边界的距离,自动调整标签的偏移量,确保标签在绘图区域内:
cl = plt.clabel(c, levels, fontsize=8, use_clabeltext=True) ax = plt.gca() xlim = ax.get_xlim() ylim = ax.get_ylim() x_pad = (xlim[1] - xlim[0]) * 0.02 # x方向留2%的边距 y_pad = (ylim[1] - ylim[0]) * 0.02 # y方向留2%的边距 for l in cl: x, y = l.get_position() # 检查是否靠近x边界 if x < xlim[0] + x_pad: x += x_pad * 2 elif x > xlim[1] - x_pad: x -= x_pad * 2 # 检查是否靠近y边界 if y < ylim[0] + y_pad: y += y_pad * 2 elif y > ylim[1] - y_pad: y -= y_pad * 2 l.set_position((x, y))
这种方法会自动把靠近边界的标签往内部移动,无需手动计算偏移角度。
3. 使用inline_spacing参数调整标签与等高线的间距
inline_spacing控制标签和截断的等高线之间的间距,增大这个值可以让标签远离等高线,间接避免靠近边界:
cl = plt.clabel(c, levels, fontsize=8, use_clabeltext=True, inline_spacing=3)
inline_spacing的单位是点,默认是5,你可以根据需要调整更大的数值。
4. 调整等高线的绘制范围
可以通过缩小等高线的绘制范围,让标签有更多空间展示。比如在调用contour时,对输入的x、y数据做轻微裁剪:
# 裁剪x和y的范围,留出边距 x_data = Hd - H y_data = nu x_min, x_max = x_data.min(), x_data.max() y_min, y_max = y_data.min(), y_data.max() x_margin = (x_max - x_min) * 0.05 y_margin = (y_max - y_min) * 0.05 c = plt.contour( x_data[(x_data >= x_min + x_margin) & (x_data <= x_max - x_margin)], y_data[(y_data >= y_min + y_margin) & (y_data <= y_max - y_margin)], du_slip[i] / 1e6, levels, colors=colors[i], linestyles=styles[i], linewidths=1, )
不过这种方法会让等高线离边界有一定距离,需要根据实际需求权衡。
内容的提问来源于stack exchange,提问作者noir
相关产品推荐
相关产品推荐

