可以控制matplotlib标记方向吗?

32 投票
5 回答
19337 浏览
提问于 2025-04-18 04:36

如果我有一个三角形的标记,能不能控制它的方向?我有一系列的面和它们对应的顶点,我想把它们画成一个基础地图。我知道在使用Mayavi和tvtk.PolyData的时候,这个脚本很简单。但是因为我在处理地图而不是3D物体,所以事情变得有点复杂。

补充一下:我在做地图的时候使用的是basemap工具。

5 个回答

2

我觉得有一个更好更全面的答案,关于Matplotlib 3.3.3的内容可以参考这个链接:Matplotlib 3.3.3

这里有一个选项叫“verts”,它用来指定标记的形状,格式是一个包含(x,y)坐标的列表,这些坐标就是你路径的顶点。这样你就可以绘制几乎任何形状的标记,可以是填充的,也可以是空心的,或者是封闭的等等。根据我的测试,其他的标记选项(见下文)仍然适用。

举个例子:

   plt.plot(x,y,
       marker=[(0,-24),(-10,-20),(10,-16),(-10,12),(10,8),(0,-4),(0,0)],
       markersize=42, color='w', linestyle='None',
       markeredgecolor='k', markeredgewidth= 2.)

这段代码会创建一个形状像弹簧的标记。大小会自动映射到一个单位正方形上,而你的点(0,0)会放在x,y的位置。从这里开始,制作一个函数来旋转整个坐标列表到给定的角度应该是个简单的任务。

自定义的弹簧形状标记

5

看看这个 matplotlib.markers 模块:

(numsides, 0, angle) - 这是一个有 numsides 条边的规则多边形,旋转了 angle 角度。
(numsides, 1, angle) - 这是一个像星星一样的符号,有 numsides 条边,旋转了 angle 角度。
(numsides, 2, angle) - 这是一个星号符号,有 numsides 条边,旋转了 angle 角度。

所以,比如说,你可以使用一个任意的多边形,并指定一个角度:

marker = (3, 0, 45)  # triangle rotated by 45 degrees.
6

使用自定义 matplotlib.path.Path 创建不规则三角形的解决方案

如果你在寻找一种标记符号,能够清楚地表示方向(范围在 [0, 2pi) 之间),你可以通过 路径来创建一个标记

因为路径会被绘图程序自动缩放(这样最外面的点会接触到框的边界 -1 <= x, y <= 1),所以你还需要额外调整点的大小。

在这里输入图片描述

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt



def gen_arrow_head_marker(rot):
    """generate a marker to plot with matplotlib scatter, plot, ...

    https://matplotlib.org/stable/api/markers_api.html#module-matplotlib.markers

    rot=0: positive x direction
    Parameters
    ----------
    rot : float
        rotation in degree
        0 is positive x direction

    Returns
    -------
    arrow_head_marker : Path
        use this path for marker argument of plt.scatter
    scale : float
        multiply a argument of plt.scatter with this factor got get markers
        with the same size independent of their rotation.
        Paths are autoscaled to a box of size -1 <= x, y <= 1 by plt.scatter
    """
    arr = np.array([[.1, .3], [.1, -.3], [1, 0], [.1, .3]])  # arrow shape
    angle = rot / 180 * np.pi
    rot_mat = np.array([
        [np.cos(angle), np.sin(angle)],
        [-np.sin(angle), np.cos(angle)]
        ])
    arr = np.matmul(arr, rot_mat)  # rotates the arrow

    # scale
    x0 = np.amin(arr[:, 0])
    x1 = np.amax(arr[:, 0])
    y0 = np.amin(arr[:, 1])
    y1 = np.amax(arr[:, 1])
    scale = np.amax(np.abs([x0, x1, y0, y1]))
    codes = [mpl.path.Path.MOVETO, mpl.path.Path.LINETO,mpl.path.Path.LINETO, mpl.path.Path.CLOSEPOLY]
    arrow_head_marker = mpl.path.Path(arr, codes)
    return arrow_head_marker, scale

fig, ax = plt.subplots()
for rot in [0, 15, 30, 45, 60, 90, 110, 180, 210, 315, 360]:

    marker, scale = gen_arrow_head_marker(rot)
    markersize = 25
    ax.scatter(rot, 0, marker=marker, s=(markersize*scale)**2)

ax.set_xlabel('Rotation in degree')

plt.show()
16

我只是想添加一个方法,让其他不规则多边形的标记样式可以旋转。下面我通过修改标记样式类的变换属性,旋转了“细钻石”、“加号”和“竖线”。

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

for m in ['d', '+', '|']:

    for i in range(5):
        a1, a2  = np.random.random(2)
        angle = np.random.choice([180, 45, 90, 35])

        # make a markerstyle class instance and modify its transform prop
        t = mpl.markers.MarkerStyle(marker=m)
        t._transform = t.get_transform().rotate_deg(angle)
        plt.scatter((a1), (a2), marker=t, s=100)

在这里输入图片描述

48

你可以使用关键字参数 marker 来创建 自定义多边形,并传入一个包含3个数字的元组 (边的数量, 样式, 旋转角度)

如果你想创建一个三角形,可以使用 (3, 0, 旋转角度),下面是一个示例。

import matplotlib.pyplot as plt

x = [1,2,3]
for i in x:
    plt.plot(i, i, marker=(3, 0, i*90), markersize=20, linestyle='None')

plt.xlim([0,4])
plt.ylim([0,4])

plt.show()

Plot

撰写回答