Home > front end >  Multiple mouse pick event Error on thinker Matplotlib Canvas plots
Multiple mouse pick event Error on thinker Matplotlib Canvas plots

Time:09-02

I am quite new to here, please bare with me. with "show polygon button", I generated 2 Matplotlib plots in my thinker canvas including a polygon plot and a scatter plot. I want to have a 2 separate mouse pick events to get coordinates from polygon(in blue) and scatter points(in orange). They(Pick events) seem working along but get an error when I try to run both at once since Matplotlib picker events interfering with other.
I appreciate your help. Code is given below:

import numpy as np
import pandas as pd
from pandastable import Table
from shapely.geometry import Polygon
import matplotlib
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import matplotlib.pyplot as plt

import tkinter as tk
from tkinter import ttk as ttk





matplotlib.use('TkAgg')


root = tk.Tk()
root.geometry('700x400')
root.state('zoomed')

df2 = pd.DataFrame({
    'x': [0,100,100,-100,-100,0,],
    'y': [0,0,500,500,0,0,],
})

df= pd.DataFrame()

frame = tk.Frame(root)
frame.place(x=500, y=500)
pt = Table(frame, dataframe=df, width=150,height=400)
pt.show()

class App():
    def __init__(self, master):
        self.master = master
          
        self.points = []
        self.pointSelect = None
        self.dotSelect=None
             
        # Frame 
        self.frame =tk.Frame(master, width=400, height =950,highlightbackground="blue", highlightthickness=5)
        self.frame.place(x=10, y=40)
        

        # button 
        self.button = tk.Button(self.frame,text = "Show Polygon", command=self.plot_section, width =15, height =2 )
        self.button.place (x=30, y=150)     
  
          

        
    def plot_section(self):
        pt.model.df = df2 # writing into pd data frame 
        pt.redraw()
             
        poly_new=list(tuple(map(tuple,np.asarray(df2))))
        print(poly_new)
        polygon2 = Polygon(poly_new)
        self.x,self.y = polygon2.exterior.xy       
        fig.clear()
        ax=fig.add_subplot(111)
        self.x2=(0,50)
        self.y2=(110,110)
        ax.plot(self.x,self.y, color ='blue',picker=True, pickradius=5)
        ax.scatter(self.x2, self.y2, s=32, color ='orange',picker=True)
        canvas.draw_idle()
        
        print(pt.model.df)
               
        def onpick(event):
 
            thisline = event.artist
            xdata = thisline.get_xdata()
            ydata = thisline.get_ydata()
            ind = event.ind
            print(xdata[ind][0] )
            self.points=[]
            self.points.append([xdata[ind][0], ydata[ind][0]])
            print('this point click on polygon', self.points)
            

        def onpick2(event):
        #This function is called whenever a point on the Tkinter Canvas is Clicked
            index = event.ind
            xy = event.artist.get_offsets()
            print ('hi scatter',xy[index])


        self.pointSelect=fig.canvas.mpl_connect('pick_event', onpick)
        self.dotSelects=fig.canvas.mpl_connect('pick_event', onpick2)
        

fig = Figure(figsize=(8,6), dpi=100)
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.draw()
canvas.get_tk_widget().pack(side=tk.RIGHT)

        
app = App(root)
root.mainloop()

Error message 1: (most recent call last): File "C:\Users\xxx\Anaconda3\envs\pls\lib\site-packages\matplotlib\cbook_init_.py", line 287, in process func(*args, **kwargs) File "C:\Users\xxx\AppData\Local\Temp\ipykernel_39168\1909536620.py", line 77, in onpick xdata = thisline.get_xdata() AttributeError: 'PathCollection' object has no attribute 'get_xdata'

Error message 2: (most recent call last): File "C:\Users\xxxxx\lib\site-packages\matplotlib\cbook_init_.py", line 287, in process func(*args, **kwargs) File "C:\Users\xxxx\AppData\Local\Temp\ipykernel_39168\1909536620.py", line 89, in onpick2 xy = event.artist.get_offsets() AttributeError: 'Line2D' object has no attribute 'get_offsets'

CodePudding user response:

event doesn't care what you clicked. It runs both functions when you click object on canvas.

And different objects have different functions and you should check instance of event.artist to run correct code for clicked object.

def onpick(event):
    print('onpick', event.artist)
    
    if isinstance(event.artist, matplotlib.lines.Line2D):
        thisline = event.artist
        xdata = thisline.get_xdata()
        ydata = thisline.get_ydata()
        ind = event.ind
        print(xdata[ind][0])
        self.points = []
        self.points.append([xdata[ind][0], ydata[ind][0]])
        print('this point click on polygon', self.points)

def onpick2(event):
    print('onpick2', event.artist)

    if isinstance(event.artist, matplotlib.collections.PathCollection):
        index = event.ind
        xy = event.artist.get_offsets()
        print ('hi scatter', xy[index])

You can even put all in one function.

def onpick(event):
    print('onpick', event.artist)
    
    if isinstance(event.artist, matplotlib.lines.Line2D):
        thisline = event.artist
        xdata = thisline.get_xdata()
        ydata = thisline.get_ydata()
        ind = event.ind
        print(xdata[ind][0])
        self.points = []
        self.points.append([xdata[ind][0], ydata[ind][0]])
        print('this point click on polygon', self.points)

    if isinstance(event.artist, matplotlib.collections.PathCollection):
        index = event.ind
        xy = event.artist.get_offsets()
        print ('hi scatter', xy[index])
  • Related