Matplotlib:使用空心标记绘制线条,使得线条在标记内不可见。

11

我有一个散点图,其中数据集的符号根据某种颜色比例着色。我想通过在这些点周围画一圈空心圆并用线连接它们来突出显示其中几个点。换句话说,在一个非常简化的示例中,我希望结果看起来像这样:

一个散点图,其中数据集被着色,并突出显示了一些点,这些点通过一条线连接在一起,其中符号内部的线段被隐藏.

使用以下代码,我可以制作一个类似的图表:

import numpy as np
import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(5,5))

X, Y = np.meshgrid(np.arange(10), np.arange(10))
Z = X**2 + Y**2

plt.scatter(X,Y,c=Z, s=300, cmap='viridis_r')

plt.plot([1, 4, 7], [7, 1, 4], 'k-o', linewidth=3, 
         markersize=14, markerfacecolor='none', markeredgewidth=2, 
        )

然而,结果看起来像这样:

一个带有彩色数据和一些突出点的散点图,由一条线连接.

我希望,在标记符号内部的线段被隐藏不可见。这是因为我想要吸引人们注意特定的数据点,并且不想将它们部分遮挡。

解决方法可能包括:

  1. 复制我想突出显示的数据点,并使用与原始符号完全相同的颜色填充标记。这不令人满意,因为(a) 我不总是能够访问数据,只能访问输出的图或轴实例,以及(b) 我不知道如何在半透明符号的情况下做到这一点,这是我的实际数据集中的情况。
  2. 手动计算适应坐标,使连接器线只达到标记的边缘。这似乎也不是很令人满意(鉴于轴和符号的坐标系统将不相同,我也不知道该怎么做)。

我的问题是:最好的解决方法是什么?是否存在比上述选项1和2更好的方法,如果没有,那么最好的方法是什么?正如我所说,对于1,我预见到透明度方面会有问题(我正在使用),而对于2,我预见到坐标系统方面可能存在问题,例如在缩放时等等。

(我的另一个小观察是,我对示例中的以下事情感到有些困惑:plt.plotplt.scatter似乎没有在完全相同的位置绘制东西(请参见此图),并且大小定义不一致)

2个回答

9
你希望获取数据坐标系中半径为点的透明(开放式)圆形,并将它们彼此连接,而不是中心点。这意味着您不能使用普通的线条。相反,可以使用多个ConnectionPatch来实现。你可以将它们缩小半个标记大小,以便它们接触圆的边界。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import ConnectionPatch

fig, ax = plt.subplots(figsize=(5,5))

X, Y = np.meshgrid(np.arange(10), np.arange(10))
Z = X**2 + Y**2

ax.scatter(X,Y,c=Z, s=300, cmap='viridis_r')

xc = [1, 4, 7]
yc = [7, 1, 4]

ax.plot(xc, yc, linewidth=0, marker="o", color="black",
         markersize=np.sqrt(300), markerfacecolor='none', markeredgewidth=3)

for i in range(len(xc)-1):
    cp = ConnectionPatch((xc[i],yc[i]), (xc[i+1], yc[i+1]), 
                         coordsA='data', coordsB='data', axesA=ax, axesB=ax,
                         shrinkA=np.sqrt(300)/2, shrinkB=np.sqrt(300)/2,
                         linewidth=2)
    ax.add_patch(cp)

plt.show()

enter image description here


另一种选择:在散点图下方画线,并在其上放置标记。 - Mad Physicist

0
一个替代已接受答案的方法是使用单独的散点图来表示标记,使用单独的线来表示连接。通过使用z-order,您可以确保线条在主散点图下方绘制,而标记在上方绘制。
import numpy as np
import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(5,5))

X, Y = np.meshgrid(np.arange(10), np.arange(10))
Z = X**2 + Y**2

pts = np.array([[1, 4, 7],
                [7, 1, 4]])

plt.scatter(X, Y, c=Z, s=300, cmap='viridis_r', vmin=Z.min(), vmax=Z.max())
plt.scatter(X[pts[1], pts[0]], Y[pts[1], pts[0]], s=300, c=Z[pts[1], pts[0]],
            marker='o', edgecolor='k', linewidth=2, zorder=20,
            vmin=Z.min(), vmax=Z.max(), cmap='viridis_r')
plt.plot(X[pts[1], pts[0]], Y[pts[1], pts[0]], 'k-', linewidth=2, zorder=10)

我们不再使用facecolor='none',而是用另一组标记覆盖圆圈。通过在两个散点图中使用vminvmax,确保顶点覆盖的颜色与底层圆圈相同。

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接