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

如何合并同子图多散点图的PathCollection实现跨散点选点删除

多个散点图合并为单个PathCollection实现跨集合选点删除

实现逻辑

要实现跨不同散点图选点删除,最简单的方案就是将所有散点的坐标、样式属性提前合并,仅生成单个PathCollection实例,原有套索选择逻辑无需做大量修改:

  • 若你可以控制散点生成逻辑:将所有散点的坐标数组拼接,对应的样式属性(颜色、大小、描边等)同步拼接后,仅调用一次ax.scatter生成单个散点集合
  • 若你只能拿到已有轴上的多个PathCollection:先遍历提取所有集合的坐标、样式属性做拼接,删除原有集合后新建单个合并后的集合添加到轴上

完整修改后代码

import numpy as np
from matplotlib.path import Path
from matplotlib.widgets import LassoSelector


class RemoveButton:
    def __init__(self, ax, collection, alpha_other=0.3):
        self.canvas = ax.figure.canvas
        self.collection = collection
        self.alpha_other = alpha_other

        self.xys = collection.get_offsets()
        self.Npts = len(self.xys)

        # 初始化逐点颜色
        self.fc = collection.get_facecolors()
        if len(self.fc) == 0:
            raise ValueError('Collection must have a facecolor')
        elif len(self.fc) == 1:
            self.fc = np.tile(self.fc, (self.Npts, 1))

        self.lasso = LassoSelector(ax, onselect=self.onselect)
        self.ind = []

    def onselect(self, verts):
        path = Path(verts)
        self.ind = np.nonzero(path.contains_points(self.xys))[0]
        self.fc[:, -1] = self.alpha_other
        self.fc[self.ind, -1] = 1
        self.collection.set_facecolors(self.fc)
        self.canvas.draw_idle()

    def disconnect(self):
        self.lasso.disconnect_events()
        self.fc[:, -1] = 1
        self.collection.set_facecolors(self.fc)
        self.canvas.draw_idle()


if __name__ == '__main__':
    import matplotlib.pyplot as plt

    data = np.random.rand(100, 2)
    data2 = np.random.rand(100, 2)

    subplot_kw = dict(xlim=(0, 1), ylim=(0, 1), autoscale_on=False)
    fig, ax = plt.subplots(subplot_kw=subplot_kw)

    # 合并两个散点的坐标,保留原默认颜色区分
    all_data = np.vstack([data, data2])
    color_list = ['#1f77b4'] * len(data) + ['#ff7f0e'] * len(data2)
    # 仅生成单个PathCollection
    pts = ax.scatter(all_data[:, 0], all_data[:, 1], s=80, c=color_list)

    selector = RemoveButton(ax=ax, collection=pts)

    def accept(event):
        if event.key == "enter":
            # 用索引掩码过滤保留未选中的点,效率更高且避免重复坐标误删
            keep_mask = np.ones(len(selector.xys), dtype=bool)
            keep_mask[selector.ind] = False
            pts.set_offsets(selector.xys[keep_mask])
            # 同步过滤颜色、坐标数组更新实例状态
            selector.fc = selector.fc[keep_mask]
            selector.xys = selector.xys[keep_mask]
            selector.Npts = len(selector.xys)

            fig.canvas.draw()
            selector.disconnect()
            ax.set_title("")

    fig.canvas.mpl_connect("key_press_event", accept)
    ax.set_title("Press enter to accept selected points.")

    plt.show()

补充说明

上述代码优化了原有的点删除逻辑,用索引掩码过滤替代遍历删除,避免坐标重复导致的误删问题,执行效率也更高。如果确实需要保留多个PathCollection而不合并,可以修改RemoveButton类,初始化时接收所有集合的列表,选点时遍历每个集合做路径包含判断,删除时同步更新对应集合的坐标即可。


内容的提问来源于stack exchange,提问作者Sina Niyavarzi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 05:45:02