如何 access/change matplotlib 散点图上各个点的属性

How to access/change properties of individual points on matplotlib scatter plot

有没有办法修改 matplotlib 散点图上各个点的属性,例如使某些点不可见或更改 theirsize/shape?

让我们考虑使用 pandas.DataFrame():

的示例数据集
import pandas as pd
import matplotlib.pyplot as plt
import random

df = pd.DataFrame()
df['name'] = ['cat', 'dog', 'bird', 'fish', 'frog']
df['id'] = [1, 1, 1, 2, 2]
df['x'] = [random.randint(-10, 10) for n in range(5)]
df['y'] = [random.randint(-10, 10) for n in range(5)]

让我们把它画在散点图上:

sc = plt.scatter(df['x'].tolist(), df['y'].tolist())
plt.show()
#easy-peasy

情节已生成。

假设我想从现有绘图中删除 df 中 id=1 的所有数据点(例如单击按钮)。通过删除我不一定意味着删除。 set-invisible什么的就可以了。总的来说,我对一种遍历绘图上存在的每个点并对其进行处理的方法很感兴趣。

编辑 #1

使用 inspect 模块我注意到 sc 绘图对象包含名为 sc._offsets 的 属性。 这些似乎是 2D numpy 数组,其中包含散点图上数据点的坐标(对于 2D 图)。 这个 _offsets 属性 由 2 个部分组成? .. 我应该说吗?:“数据”(二维坐标数组)和“掩码”(二维布尔值数组:在这种情况下= False)和“填充值”,这对我来说似乎无关紧要。

我通过删除某些索引处的 _offsets 元素,设法从散点图中删除了选择点,如下所示:

sc._offsets = numpy.delete(sc._offsets, [0, 1, 3], axis=0)

然后重新绘制剧情:

sc.figure.canvas.draw()

由于数据框 'id' 列中的值和 sc._offsets 中的坐标对齐,我可以按索引删除坐标,其中 'id' 值(例如)= 1。 这就是我想要的,因为原始数据帧和数据集保持不变,所以我可以根据需要在散点图上重新创建点。

我想我可以使用“掩码”以某种方式 hide/show 在散点图上选择点,但我还不知道如何。我正在调查。

一个基本的解决方案。如果你的数据集不是很大,并且你知道区分数据的条件,你想以不同的方式绘制,你可以为每个条件创建一列,并用不同的标记和颜色绘制每一列。

假设您想绘制不同的大于 3 的 y:

import pandas as pd
import matplotlib.pyplot as plt
import random

df = pd.DataFrame()
df['name'] = ['cat', 'dog', 'bird', 'fish', 'frog']
df['id'] = [1, 1, 1, 2, 2]
df['x'] = [random.randint(-10, 10) for n in range(5)]
df['y'] = [random.randint(-10, 10) for n in range(5)]

_mask = df.y > 3  
df.loc[_mask, 'y_case_2'] = df.y
df.loc[~_mask, 'y_case_1'] = df.y 

sc = plt.scatter(df.x, df.y_case_1, marker='*', color='r')
sc = plt.scatter(df.x, df.y_case_2, marker='.', color='b')
plt.show()
df

注意:注意随机数据无法生成大于3的数据,如果是,请重试。

已解决

答案是设置掩码 numpy.core.ma.MaskedArray 位于 matplotlib 散点图的 sc._offsets.mask 属性 之下。 这可以在绘图生成期间和生成绘图之后以交互模式通过以下方式完成:

#before change:
#sc._offsets.mask = [[False, False], [False, False], [False, False], [False, False], [False, False]]

sc._offsets.mask = [[1, 1], [1, 1], [1, 1], [0, 0], [0, 0]]

#after change:
#sc._offsets.mask = [[True, True], [True, True], [True, True], [False, False], [False, False]]

#then re-draw plot
sc.figure.canvas.draw() #docs say that it's better to use draw_idle() but I don't see difference

根据要从图中排除的点的索引设置为真值,将从图中删除该特定点。它不会“删除”它。可以通过将 bool 值设置回“False”来恢复点数。请注意,它是二维数组,因此传递简单:[1, 1, 1, 0, 0] 不会做,你需要考虑绘图的 x 和 y 坐标。

有关详细信息,请参阅 numpy 文档: https://numpy.org/doc/stable/reference/maskedarray.generic.html#accessing-the-mask

如果出现问题,我会进行编辑。 谢谢大家的帮助。