matplotlib 等高线标注太靠近地物边界

tzxcd3kk  于 2023-10-24  发布在  其他
关注(0)|答案(1)|浏览(137)

我正在使用matplotlib绘制等高线图,clabel生成的标签太靠近图形边界。

如何使它们更好地定位?我尝试了manual arg,但由于我有来自for循环的多个等高线,因此不容易确定每次放置的位置。我用来绘制的代码是

#!/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,
    )
    # my current hack
    cl = plt.clabel(c, levels, fontsize=8, use_clabeltext=True)
    # for l in cl:
    #     # move the location of the label to avoid overlapping
    #     l.set_position(
    #         (
    #             l.get_position()[0] - 1,
    #             l.get_position()[1]
    #             - 0.005
    #             * np.tan(l.get_rotation() * np.pi / 180),  # 0.005 from trial and error
    #         )
    #     )
    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:
        # move the location of the label to avoid overlapping
        l.set_position(
            (
                l.get_position()[0] - 1,
                l.get_position()[1]
                - 0.005
                * np.tan(l.get_rotation() * np.pi / 180),  # 0.005 from trial and error
            )
        )

情节比

更好,但仍然不够好。

6rqinv9w

6rqinv9w1#

clabel允许手动定位标签。只需将您的hack替换为

plt.clabel(c, inline=True, fmt="%1.1f", fontsize=10, manual=True)

(我添加了个人格式样式以供参考)。
运行脚本将打开一个包含绘图的窗口,并提示您单击鼠标左键(在触摸板上轻轻一点)在您想要每个标签的位置上。然后,当您对位置满意时,您可以通过右键单击继续进行下一次轮廓迭代(三指轻敲触摸板)。重复操作,直到所有轮廓都被标记,然后最后一次右键单击关闭提示。您的图像应该保存在本地正常的标签上。


`

相关问题