1

I have written this code which allows the user to select 4 points on the graph and as the 4 points are selected, two lines are drawn. But I want the user to be able to see which points she has selected by changing the color of the point or drawing a small circle around it. I tried reading the matplotlib documentation but couldn't understand what to add/change in my code.

I just want to change the color of the selected points or draw a small circle around the selected points. How do I do that?

#ONCLICK Event which lets user select 4 points on the graph and stores the coordinates of the 
    points in coords
   coords=[]

   def onclick(self,event):
       global ix, iy, fig
       ix, iy = event.xdata, event.ydata
       
       print ('x = %d, y = %d'%(ix, it))
       #I am not able to plot this circle
       #plt.Circle((ix,iy), radius=0.07, color='g')
       event.canvas.draw()
       self.coords.append(ix)
       self.coords.append(iy)
 
       print(len(self.coords))
   
       if len(self.coords) == 8:
           fig.canvas.mpl_disconnect(cid)
           plt.close(1)
           
           s=self.coords[0]
           t=self.coords[1]
           u=self.coords[2]
           v=self.coords[3]
           w=self.coords[4]
           x=self.coords[5]
           y=self.coords[6]
           z=self.coords[7]
           
           line1= '(' + str("{:.2f}".format(s))+',' + str("{:.2f}".format(t)) + ')' + ',' + '(' +str("{:.2f}".format(u)) +',' + str("{:.2f}".format(v)) + ')'
           line2= '(' + str("{:.2f}".format(w))+',' + str("{:.2f}".format(x)) + ')' + ',' + '(' +str("{:.2f}".format(y)) +',' + str("{:.2f}".format(z)) + ')'
           
           df['Parameter']=df['Parameter'].astype('float')
           df['Step']=df['Step'].astype('float')
           a = df['Step']
           b = df['Parameter']
           
           #LINE EQUATION
           m1=(v-t)/(u-s)
           c1=t-m1*s
           x1=np.linspace(df.iloc[0]["Step"],df.iloc[samples-1]["Step"],100)
           y1=m1*x1+c1
           m2=(z-x)/(y-w)
           c2=x-m2*w
           x2=np.linspace(df.iloc[1]["Step"],df.iloc[samples-1]["Step"],100)
           y2=m2*x2 +c2
               
           #INTERSECTION
           det=m2-m1
           if det==0:
               print("Lines are parallel\n")
           else:
               pointx=(c1-c2)/det
               pointy=((c1*m2)-(m1*c2))/det
           
           #PLOTTING
           fig = plt.figure()
           ax = plt.axes()
           plt.plot(a, b, '.',color='yellow')
           plt.plot(x1,y1,color='red',label=line1)
           plt.plot(x2,y2,color='black',label=line2)
           plt.xlabel('Volume')
           plt.ylabel('Conductivity')
           ax.set_ylim(bottom=0)
           ax.set_xlim(left=0.)
           idx = np.argwhere(np.diff(np.sign(y2 - y1))).flatten()
           plt.title("END POINT")
           plt.plot(x2[idx], y2[idx], 'ro',color='Purple')
           plt.annotate("Intersecting Point", (pointx,pointy),color='Blue')
           plt.plot((pointx,pointx),(pointy,0),'--',color='purple')
           plt.annotate("(%s,0) Volume" %pointx, (pointx,0),color='Blue')
           mplcursors.cursor(hover=True)
           plt.legend()
           plt.show()
       return
   
   
   #Main graph which appears when a button in the interface is clicked.
   def manual(self):
       df['Parameter']=df['Parameter'].astype('float')
       df['Step']=df['Step'].astype('float')
       a = df['Step']
       b = df['Parameter']
       df['Parameter']=df['Parameter'].astype('float')
       df['Step']=df['Step'].astype('float')
       a=df['Step']
       b=df['Parameter']
       global fig
       fig=plt.figure()
       plt.xlabel('Volume')
       plt.ylabel('Conductivity')
       plt.title('SCATTER PLOT')
       plt.scatter(a, b,color='r', label=self.Name)
       mplcursors.cursor(hover=True)
       global cid
       cid = fig.canvas.mpl_connect('button_press_event', self.onclick)
       plt.legend()
       plt.show()
3
  • 1
    I understand that your points are simply P1(s,t), P2(u,v), P3(w,x), P4(y,z). You have many examples of annotating any point (px, py) in your code snippet at several instances. For example: plt.annotate("Intersecting Point", (pointx,pointy),color='Blue') Have you tried using this same method for the four points by replacing pointx,pointy with corresponding coordinates (for ex: u,v)? Commented Dec 14, 2020 at 20:02
  • @skuzzy If I do that, the points will be marked after the intersecting lines are drawn and not when the user selects the point. I want the points to be marked as soon as the user selects them. Commented Dec 15, 2020 at 8:07
  • Your points should get drawn as you call the plot method. Check my answer for a reference example. Commented Dec 15, 2020 at 9:08

1 Answer 1

1

The answer to your question is illustrated in your example itself. All you have to do is to grab the axes currently in context and plot your point emitted from the event on it. Here is a simple example that is not very dissimilar from your own.

from matplotlib import pyplot as plt

i = 0
def onclick(event):
    global i
    ix, iy = event.xdata, event.ydata
    ax = plt.gca()

    ax.plot(ix, iy, 'b*')
    ax.annotate(f"Clicked Point {i}", (ix,iy),color='Black')
    i += 1
    print(f'x = {ix}, y = {iy}')

    event.canvas.draw()

fig, ax = plt.subplots()
ax.set_xlim([0,10])
ax.set_ylim([0,10])

fig.canvas.callbacks.connect('button_press_event', onclick)
plt.show()
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for this solution. Though it is not what I wanted to achieve but it serves my purpose for now. Thank you so much!
Glad to know that. You should consider accepting the answer if it worked for you, or marking it as helpful.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.