0

I have a script that can draw 2 markers on a plot and after that fill the area between. The outcome looks like this:

enter image description here

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... enter image description here

... 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()
Community
  • 1
  • 1
Aquiles Páez
  • 503
  • 6
  • 18
  • 1
    Firstly you would need to pass an instance of your class, e.g. `c_a_r = calc_and_remove()`. Secondly your `draw_point()` function appears to coded to deal with clicking on the graph, not the button. You would also need to connect your class somehow to the plot. – Martin Evans Jan 09 '17 at 07:54
  • 2
    The specific error you mention is because there is no instance of the class `calc_and_remove`. You should create an instance of it. Normally in Python camel casing is used for classes. It would make the code a little easier to read. – J. P. Petersen Jan 09 '17 at 11:41
  • @J.P.Petersen thanks for your suggestion, I don't get that error anymore. I made some fixes, though I still cannot implement the class properly to erase the plot updates. Now I get errorType: 'NoneType' object is not callable – Aquiles Páez Jan 19 '17 at 17:29
  • @MartinEvans yes, one of the errors is that it was expecting a click on the figure, I changed that to 'button_press_event'. And passed the instance of the class just like you said. – Aquiles Páez Jan 19 '17 at 17:32
  • @Goyo hello, I edited the question with the TypeError I'm getting. TypeError: 'NoneType' object is not callable – Aquiles Páez Jan 19 '17 at 17:40

0 Answers0