如何合并同子图多散点图的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
相关产品推荐
相关产品推荐

