1

I have the following class which I intend to use in labelling specific parts of a time series.

class Labeler(object):
    def __init__(self, accel_data, vline=0):
        self.fig = plt.figure(figsize=(10,2))

        self.accel_data = accel_data
        x_ = np.arange(len(self.accel_data))

        self.plot, = plt.plot(x_, self.accel_data, picker=100)
        plt.xlim(0, len(self.accel_data)-1)

        self.final_loc = 0
        self.vline_loc = 0
        self.vline = plt.axvline(self.vline_loc, color='red')

        self.fig.canvas.mpl_connect('button_press_event', self._onclick)

        self.button_next = Button(plt.axes([0.85, 0.78, 0.05, 0.1]), 'Next', color='#32CD32')
        self.button_next.on_clicked(self._nextbutton)

        self.button_done = Button(plt.axes([0.85, 0.65, 0.05, 0.1]), 'Done', color='orange')
        self.button_done.on_clicked(self._donebutton)
        plt.show(block=True)

        self.starts = []

    def _onclick(self, event):
        self.final_loc = self.vline_loc
        self.vline_loc = int(event.xdata)
        self.vline.set_xdata(self.vline_loc)

    def _nextbutton(self, event):
        self.starts.append(['code', self.final_loc])
        n = np.random.randint(1000)
        self.plot.set_xdata(np.arange(n))
        self.plot.set_ydata(np.random.rand(n))
        self.plot.set_title(str(n))

   def _donebutton(self, event):
        plt.close() # close to stop plot

Now, I want to use this in an ipython notebook so that I can use it in a loop like this:

for i in range(5):
    l = Labeler(np.random.rand(1000))
    print(l.starts) # print the locs of vertical lines
    cont = input("Press any key to continue")

My problem is that when I loop over the plot, it waits until the loop is finished before displaying the plot. What I want it to do is open a single plot, determine parts using the red line, and then proceed to the next plot. Please let me know how this can be accomplished. Thanks!

3
  • I suggest plotting in a thread. Commented May 26, 2017 at 6:42
  • @LiranFunaro what do you mean by that? Commented May 26, 2017 at 7:00
  • Open a thread an run your code there. Commented May 26, 2017 at 7:02

1 Answer 1

1

Solution for jupyter notebook

The problem in a notebook is that the interactive figure prevents further code from being executed. The only solution I can think of is to let the figure take over control over the updates.
The following would be an example (I'm sure it's not what you actually wanted, but I had problems understanding the purpose of some of the code, so it does something similar). The idea would be to provide all the data already to the class, which can then loop through it.

%matplotlib notebook
import matplotlib.pyplot as plt
from matplotlib.widgets import Button
import numpy as np


class Labeler(object):
    def __init__(self, data, vline=0):
        self.fig = plt.figure(figsize=(10,2))
        self.ax = self.fig.gca()
        self.i = 0
        self.data = data 
        
        self.fig.canvas.mpl_connect('button_press_event', self._onclick)
        self.button_next = Button(plt.axes([0.85, 0.78, 0.05, 0.1]), 'Next', color='#32CD32')
        self.button_next.on_clicked(self._nextbutton)
        self.button_done = Button(plt.axes([0.85, 0.65, 0.05, 0.1]), 'Done', color='orange')
        self.button_done.on_clicked(self._donebutton)

        self.starts = []
        plt.show()
        

    def _nextbutton(self, event):
        self.i
        self.final_loc = 0
        self.vline_loc = 0
        self.accel_data = self.data[self.i % len(data)]
        self.x = np.arange(len(self.accel_data))
        plt.xlim(0, len(self.accel_data)-1)
        self.plot, = self.ax.plot(self.x, self.accel_data, picker=100)
        self.vline = self.ax.axvline(self.vline_loc, color='red')
        self.starts.append(['code', self.final_loc])
        self.ax.set_title(str(self.i))
        self.i += 1
        self.fig.canvas.draw()
        

    def _onclick(self, event):
        self.final_loc = self.vline_loc
        self.vline_loc = int(event.xdata)
        self.vline.set_xdata(self.vline_loc)
        self.fig.canvas.draw()


    def _donebutton(self, event):
        #plt.close() # close to stop plot
        self.ax.clear()
        pass

data = []
for i in range(5):
    data.append(np.random.rand(60+10*i))
l = Labeler(data)

enter image description here

Solution for a console:

The following code runs fine for me.

import matplotlib.pyplot as plt
from matplotlib.widgets import Button
import numpy as np


class Labeler(object):
    def __init__(self, accel_data, vline=0):
        self.fig = plt.figure(figsize=(10,2))
        self.ax = self.fig.gca()
        self.accel_data = accel_data
        x_ = np.arange(len(self.accel_data))

        self.plot, = plt.plot(x_, self.accel_data, picker=100)
        plt.xlim(0, len(self.accel_data)-1)

        self.final_loc = 0
        self.vline_loc = 0
        self.vline = plt.axvline(self.vline_loc, color='red')

        self.fig.canvas.mpl_connect('button_press_event', self._onclick)

        self.button_next = Button(plt.axes([0.85, 0.78, 0.05, 0.1]), 'Next', color='#32CD32')
        self.button_next.on_clicked(self._nextbutton)

        self.button_done = Button(plt.axes([0.85, 0.65, 0.05, 0.1]), 'Done', color='orange')
        self.button_done.on_clicked(self._donebutton)
        
        self.starts = []
        plt.show(block=True)

        

    def _onclick(self, event):
        self.final_loc = self.vline_loc
        self.vline_loc = int(event.xdata)
        self.vline.set_xdata(self.vline_loc)

    def _nextbutton(self, event):
        self.starts.append(['code', self.final_loc])
        n = np.random.randint(1000)
        self.plot.set_xdata(np.arange(n))
        self.plot.set_ydata(np.random.rand(n))
        self.ax .set_title(str(n))

    def _donebutton(self, event):
        plt.close() # close to stop plot
        
for i in range(5):
    l = Labeler(np.random.rand(1000))
    print(l.starts) # print the locs of vertical lines
    cont = raw_input("Press any key to continue")

enter image description here

Sign up to request clarification or add additional context in comments.

8 Comments

yes, it works when ran from the terminal but I want to use it inside an ipython notebook..
Which backend are you using`?
The backend is nbAgg
Ok, sorry for confusion. Do you want me to delete the answer?
that's fine. no problem
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.