You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 11:54:55