I have a script that can draw 2 markers on a plot and after that fill the area between. The outcome looks like this:
What I want to do is build a python class that will allow me to remove, through a button in the matplotlib figure, the content in ax.lines (for the markers) and ax.collections (for the filled area). Plus, reseting the content in "points" so I can repeat the process again.
I was trying to use this great example as a guide to build the class, but I couldn't adapt the implementation. When I run the script, it looks "good" at first glance...
... but when I hit "Draw" or "Erase", I get this message:
unbound method draw_points() must be called with calc_and_remove instance as first argument (got MouseEvent instance instead)
I'm not sure where I'm exactly wrong, can you guys help me out a bit? Here's what I have so far for the class.
Edit: I'm not getting that error message anymore, now I'm getting this one:
TypeError: 'NoneType' object is not callable
Still, I'm not getting the button to remove all the updates made to the plot. I'll keep working on this until I get it done or someone suggests and answer.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Button
# Find nearest element from a vector
def find_nearest(vector, val):
ind = (np.abs(vector - val)).argmin()
return ind
# Pick an event that allows you to mark two points and store it
# in the global variable "points"
def onpick(event):
thisline = event.artist
xdata = thisline.get_xdata()
ydata = thisline.get_ydata()
ind = event.ind
global points
points.append((xdata[ind[0]], ydata[ind[0]]))
for p in points:
if len(points) == 1:
x1, y1 = points[0]
ax.plot(x[find_nearest(x, x1)], y[find_nearest(x, x1)], marker='+', mew=10, markersize=40)
fig.canvas.draw()
elif len(points) == 2:
x1, y1 = points[0]
x2, y2 = points[1]
new_Y = y[find_nearest(x, x1): find_nearest(x, x2)]
new_X = x[find_nearest(x, x1): find_nearest(x, x2)]
ax.fill(new_X, new_Y)
ax.plot(x[find_nearest(x, x2)], y[find_nearest(x, x2)], marker='+', mew=10, markersize=40)
fig.canvas.draw()
break
return points
class Calc_And_Remove:
def __init__(self,fig, ax, points):
self.points=points
self.fig=fig
self.ax=ax
def connect(self):
self.cidremove = self.fig.canvas.mpl_connect('button_press_event', self.remove_drawings)
def disconnect(self):
self.fig.canvas.mpl_disconnect(self.cidremove)
def remove_drawings(self):
if len(points)==2:
self.ax.lines[1].remove()
self.ax.lines[2].remove()
self.ax.collections[0].remove()
self.fig.canvas.draw()
self.points = []
else:
print "Area has not been selected"
# create 1000 equally spaced points between -10 and 10
x = np.linspace(-10, 10, 1000)
# calculate the y value for each element of the x vector
y = -((x - 1) ** 2) + 50
points = []
fig, ax = plt.subplots()
ax.plot(x, y, markersize=40, picker=1)
cid = fig.canvas.mpl_connect('pick_event', onpick)
c_a_r=Calc_And_Remove(fig, ax, points)
Erase= plt.axes([0.81, 0.02, 0.1, 0.075])
b_delete_updates=Button(Erase,'Erase')
b_delete_updates.on_clicked(c_a_r.remove_drawings())
plt.show()