【问题标题】:How do I highlight points by clicking on legend entries in matplotlib?如何通过单击 matplotlib 中的图例条目来突出显示点?
【发布时间】:2020-05-12 06:57:47
【问题描述】:

我正在绘制一个简单的散点图,其中包含 3 组数据,分别标记为 A、B 和 C。

  1. 如何编写代码以允许单击图例条目 A 并突出显示与 A 关联的点,同时使与标签 B 和 C 关联的点变暗?

  2. 是否可以选择(通过单击并拖动,或使用 ctrl 键单击多个图例条目)并突出显示关联的点,同时使具有其他标签的点变暗(图例上未选择的标签)?

按照此处的示例https://matplotlib.org/3.1.1/gallery/event_handling/legend_picking.html(使用绘图而不是散布),我取得了一些进展,但无法完全让代码按照我想要的方式工作。在示例中,他们通过 leg.get_lines() 为每个图例条目设置了选择器属性,我尝试了一个类似的东西 (leg.get_patches()),它给出了一个空的字典。我无法取得进一步的进展,希望有人可以提供帮助。提前致谢。

import numpy as np
import tkinter as tk
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

class MainApplication(tk.Frame): 
    def __init__(self, root, *args, **kwargs):
        tk.Frame.__init__(self, root, *args, **kwargs)
        self.root = root
        self.frame = tk.Frame(self.root)
        self.frame.grid(row=0, column=0)
        self.plot_button = tk.Button(self.frame, text='Plot XY', command=self.xy_plot)
        self.plot_button.grid(row=0, column=0)

        self.figure = plt.figure(figsize=(5,5))
        self.canvas = FigureCanvasTkAgg(self.figure, master=self.frame)
        self.canvas.get_tk_widget().grid(row=1, column=0)

        self.X = [np.random.rand(5), np.random.rand(5), np.random.rand(5)]
        self.Y = [np.random.rand(5), np.random.rand(5), np.random.rand(5)]
        self.labels = ['A','B','C']
        self.figure.canvas.mpl_connect('pick_event', self.onpick)

    def xy_plot(self):   
        ax = self.figure.add_subplot(111)  
        self.pts = []
        for x, y, grp in zip(self.X, self.Y, self.labels):
            self.pts.append(ax.scatter(x, y, label=grp))
        leg = ax.legend(self.pts, self.labels, fontsize=12)
        leg.set_picker(5) #should be set for individual entries? If so, how?
        self.canvas.draw()

    def onpick(self, event):
        #obviously this function needs to be modified
        self.pts[0].set_alpha(0.9) 
        self.pts[1].set_alpha(0.1
        self.canvas.draw()

if __name__ == "__main__":
    root = tk.Tk() 
    MainApplication(root)
    root.mainloop()

我遇到的所有示例都涉及循环 leg.get_lines() 并为 leg.get_lines() 中的每个元素设置 set_picker(value)。但是,对于散点图,leg.get_lines() 是空的。我尝试查看 leg.dict['legendHandles'] ,我发现它由 3 个(在我的情况下) collections.PathCollection 对象组成。这些对象有 set_picker() 方法吗?在我看来,散点图的传说与情节的传说非常不同。有人可以解释一下吗?

【问题讨论】:

    标签: python matplotlib legend


    【解决方案1】:

    类似于我问题中链接中显示的示例,我遍历了 legendHandles 并设置了 set_picker(5)。这允许单击不同的图例条目并允许我通过 event.artist.get_label() 获取标签。对 onpick 函数的修改似乎是一种 hack,但它可以满足我的需求。有没有比我正在做的更优雅和正确的方法来遍历 legendHandles?欢迎任何改进“解决方案”的建议。

    def xy_plot(self):   
    
        ax = self.figure.add_axes([0,0,1,1])  
        self.pts = []
    
        for x, y, grp in zip(self.X, self.Y, self.labels):
            self.pts.append(ax.scatter(x, y, label=grp))
        self.leg = ax.legend(self.pts, self.labels)
    
        for obj in self.leg.__dict__['legendHandles']:
            obj.set_picker(5)
    
        self.canvas.draw()
    
    
    def onpick(self, event):
    
        groups = {key: val for key, val in zip(self.labels, self.pts)}
        label = event.artist.get_label()
        for key in groups:
            if key == label:
                groups[key].set_alpha(1.0)
            else:
                groups[key].set_alpha(0.2)
    
        self.canvas.draw()
    

    【讨论】:

      猜你喜欢
      • 2019-06-13
      • 2019-04-29
      • 1970-01-01
      • 2017-03-03
      • 2020-08-27
      • 2016-11-25
      • 2017-08-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多