Пример #1
0
class MyFrame(wx.Frame):
    def __init__(self, parent, id, trial_values, outsider_points,
                 channel_number, trial_number, channel_mean, channel_std_der,
                 y_min, y_max, stdX):
        wx.Frame.__init__(self,
                          parent,
                          id,
                          'scrollable plot',
                          style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER,
                          size=(800, 400))
        self.panel = wx.Panel(self, -1)

        self.fig = Figure((5, 4), 75)
        self.canvas = FigureCanvasWxAgg(self.panel, -1, self.fig)

        self.scroll_range = len(trial_values)
        self.canvas.SetScrollbar(wx.HORIZONTAL, 0, 5, self.scroll_range)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.canvas, -1, wx.EXPAND)

        self.panel.SetSizer(sizer)
        self.panel.Fit()

        self.outsider_points = outsider_points
        self.bursts_x = list(map(lambda x: x[0], self.outsider_points))
        self.bursts_y = list(map(lambda x: x[1], self.outsider_points))
        self.stdX = stdX
        self.y_min = y_min
        self.y_max = y_max
        self.channel_mean = channel_mean
        self.channel_std_der = channel_std_der
        self.trial_values = trial_values
        self.init_data()
        self.init_plot(channel_number, trial_number)

        self.canvas.Bind(wx.EVT_SCROLLWIN, self.OnScrollEvt)

    def init_data(self):
        self.x = []
        for i in range(len(self.trial_values)):
            self.x.append(i)

        # Extents of data sequence:
        self.i_min = 0
        # self.i_max = len(self.t)
        self.i_max = len(self.trial_values)

        # Size of plot window:
        self.i_window = len(self.trial_values)

        # Indices of data interval to be plotted:
        self.i_start = 0
        self.i_end = self.i_start + self.i_window

    def init_plot(self, channel_number, trial_number):
        self.axes = self.fig.add_subplot(111)
        self.plot_data = \
            self.axes.plot(self.x[self.i_start:self.i_end],
                           self.trial_values[self.i_start:self.i_end])[0]

        self.axes.set_ylim(min(self.y_min, -self.stdX * self.channel_std_der),
                           self.y_max)

        self.axes.axhline(y=self.channel_mean, linewidth=0.3, color='r')
        self.axes.axhline(y=self.stdX * self.channel_std_der,
                          linewidth=0.3,
                          color='g',
                          linestyle='--')
        self.axes.axhline(y=-self.stdX * self.channel_std_der,
                          linewidth=0.3,
                          color='g',
                          linestyle='--')

        self.axes.set_ylabel('Amplitudes')
        self.axes.set_xlabel('Relative Timestamp')
        self.axes.set_title('Channel ' + str(channel_number) + ' Trial ' +
                            str(trial_number) + ' Snapshot')

    def draw_plot(self):

        # Update data in plot:
        self.plot_data.set_xdata(self.x[self.i_start:self.i_end])
        self.plot_data.set_ydata(self.trial_values[self.i_start:self.i_end])

        # Adjust plot limits:
        self.axes.set_xlim((min(self.x[self.i_start:self.i_end]),
                            max(self.x[self.i_start:self.i_end])))

        self.axes.set_ylim(min(self.y_min, -self.stdX * self.channel_std_der),
                           self.y_max)

        self.axes.axhline(y=self.channel_mean, linewidth=0.3, color='r')
        self.axes.axhline(y=self.stdX * self.channel_std_der,
                          linewidth=0.3,
                          color='g',
                          linestyle='--')
        self.axes.axhline(y=-self.stdX * self.channel_std_der,
                          linewidth=0.3,
                          color='g',
                          linestyle='--')

        # self.axes.scatter(self.bursts_x, self.bursts_y, c='black')
        for i in range(0, len(self.bursts_x), 2):
            point1 = [self.bursts_x[i], self.bursts_y[i]]
            point2 = [self.bursts_x[i + 1], self.bursts_y[i + 1]]
            x_values = [point1[0], point2[0]]
            y_values = [point1[1], point2[1]]
            if (all(i > self.channel_mean for i in y_values)):
                y_values = [
                    self.stdX * self.channel_std_der,
                    self.stdX * self.channel_std_der
                ]
            else:
                y_values = [
                    -self.stdX * self.channel_std_der,
                    -self.stdX * self.channel_std_der
                ]
            self.axes.plot(x_values, y_values, color='black')
            self.axes.scatter(x_values, y_values, c='black')

        # Redraw:
        self.canvas.draw()

    def update_scrollpos(self, new_pos):
        self.i_start = self.i_min + new_pos
        self.i_end = self.i_min + self.i_window + new_pos
        self.canvas.SetScrollPos(wx.HORIZONTAL, new_pos)
        self.draw_plot()

    def OnScrollEvt(self, event):
        evtype = event.GetEventType()

        if evtype == wx.EVT_SCROLLWIN_THUMBTRACK.typeId:
            pos = event.GetPosition()
            self.update_scrollpos(pos)
        elif evtype == wx.EVT_SCROLLWIN_LINEDOWN.typeId:
            pos = self.canvas.GetScrollPos(wx.HORIZONTAL)
            self.update_scrollpos(pos + 1)
        elif evtype == wx.EVT_SCROLLWIN_LINEUP.typeId:
            pos = self.canvas.GetScrollPos(wx.HORIZONTAL)
            self.update_scrollpos(pos - 1)
        elif evtype == wx.EVT_SCROLLWIN_PAGEUP.typeId:
            pos = self.canvas.GetScrollPos(wx.HORIZONTAL)
            self.update_scrollpos(pos - 10)
        elif evtype == wx.EVT_SCROLLWIN_PAGEDOWN.typeId:
            pos = self.canvas.GetScrollPos(wx.HORIZONTAL)
            self.update_scrollpos(pos + 10)
        else:
            print("unhandled scroll event, type id:", evtype)
Пример #2
0
class MyFrame(wx.Frame):
    """
    Creates a GUI class that displays data for an 8x8 set of electrodes
    with the corners missing. 
    Main View: Scrollable data for each electrode is displayed according
    to the placement of electrodes in the 8x8 arrangement
    Zoom in View: Scrollable data for a single electrode is displayed
    with MatPlotLib options such as saving data 
    """
    def __init__(self, parent, id, data, time, samprate):

        #Specify electrode numbers and electrodes that are missed
        #In this specific implementation we have
        #8x8 set of electrodes, with corners missing (0,7,56,63)
        self.empty = [0, 7, 56, 63]
        self.electrodeX = 8
        self.electrodeY = 8
        """
        if len(data)!=(self.electrodeX*self.electrodeY-len(self.empty)):
            print "You do not have enough data for electrodes."
            print "There should be data for 64 electrodes"
            raise ValueError
        """
        #Data Variables
        self.data = data
        self.time = time
        self.samprate = samprate

        #Adjust Display Size
        tmp = wx.DisplaySize()
        tmp2 = (tmp[0], tmp[1] - 100)
        wx.Frame.__init__(self, parent, id, 'LSCE - Overall Plot', (0, 0),
                          tmp2)
        self.panel = wx.Panel(self, -1)
        self.dimensions = self.GetSize()
        self.xoffset = 50
        self.yoffset = 100
        self.labelwidth = 140

        #canvas, graphs, scrollbar
        self.fig = Figure((5, 4), 75)
        self.canvas = FigureCanvasWxAgg(self.panel, -1, self.fig)
        self.scroll_range = len(data[0]) - time * samprate + 1
        print self.scroll_range
        self.canvas.SetScrollbar(wx.HORIZONTAL, 0,
                                 max(1, self.scroll_range / 20),
                                 self.scroll_range)
        self.graphs = []
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.canvas, -1, wx.EXPAND)
        self.panel.SetSizer(sizer)
        self.panel.Fit()
        self.lastupdate = datetime.datetime.utcnow()
        self.init_data()
        self.init_plot()
        self.Layout()

        #Bind Events, Scrollbar & Button Press
        self.canvas.Bind(wx.EVT_SCROLLWIN_THUMBTRACK, self.OnScrollEvt)
        self.canvas.Bind(wx.EVT_SCROLLWIN_THUMBRELEASE, self.OnScrollStop)
        self.canvas.mpl_connect('button_press_event', self.onclick)

    """
    Parses data to be fed into visualization. 
    """

    def init_data(self):

        # Generate x axis limits and data intervals:
        self.dt = 1.0 / self.samprate
        self.t = arange(0, float(len(self.data[0])) / self.samprate, self.dt)
        print "There are " + self.t.__repr__(
        ) + " time series, and " + self.data[0].__repr__() + " data entries."
        # Extents of data sequence:
        self.i_min = 0
        self.i_max = len(self.t)

        # Size of plot window:
        self.i_window = self.time * self.samprate
        print "Window size is " + self.i_window.__repr__() + " entries."
        # Indices of data interval to be plotted:
        self.i_start = 0
        self.i_end = self.i_start + self.i_window

    """
    Creates 8x8 Data Plots
    """

    def init_plot(self):

        #Start Time End Time Label Positioning
        self.label1x = self.xoffset
        self.labely = self.dimensions[1] - self.yoffset
        self.label2x = self.dimensions[0] - self.xoffset - self.labelwidth

        #Start Time End Time Labels
        self.startTime = wx.TextCtrl(
            self.panel,
            value="Start Time: " +
            (float(self.i_start) / self.samprate).__repr__(),
            pos=(self.label1x, self.labely),
            size=(self.labelwidth, -1))
        self.endTime = wx.TextCtrl(
            self.panel,
            value="End Time: " +
            (float(self.i_end) / self.samprate).__repr__(),
            pos=(self.label2x, self.labely),
            size=(self.labelwidth, -1))

        #creating each sub plot
        self.axes = []
        self.graphs = []
        arrayoffset = 0
        for j in range(self.electrodeX * self.electrodeY):
            if j not in self.empty:
                self.axes.append(
                    self.fig.add_subplot(self.electrodeX, self.electrodeY,
                                         j + 1))

                self.axes[j].yaxis.set_major_locator(
                    matplotlib.ticker.NullLocator())
                self.axes[j].xaxis.set_major_locator(
                    matplotlib.ticker.NullLocator())

                self.dataCurrent = self.data[0]
                self.graphs.append(self.axes[j].plot(
                    self.t[self.i_start:self.i_end],
                    self.data[0][self.i_start:self.i_end])[0])
            else:
                self.axes.append(0)
                self.graphs.append(0)
                arrayoffset = arrayoffset + 1
        self.canvas.draw()

    """
    Updates the section of data displayed according to scrolling event
    """

    def draw_plot(self):

        # Adjust plot limits:
        for i in range(self.electrodeX * self.electrodeY):
            if i not in self.empty:
                # Update data in plot:
                self.graphs[i].set_xdata(self.t[self.i_start:self.i_end])
                self.graphs[i].set_ydata(self.data[0][self.i_start:self.i_end])
                self.axes[i].set_xlim((min(self.t[self.i_start:self.i_end]),
                                       max(self.t[self.i_start:self.i_end])))
                self.axes[i].set_ylim(
                    (min(self.data[0][self.i_start:self.i_end]),
                     max(self.data[0][self.i_start:self.i_end])))

        # Redraw:
        self.canvas.draw()
        self.startTime.Refresh()
        self.endTime.Refresh()

    """
    Handles Graph Scrolling
    """

    def OnScrollEvt(self, event):

        if ((datetime.datetime.utcnow() - self.lastupdate).microseconds >
                250000):
            self.draw_plot()
            self.lastupdate = datetime.datetime.utcnow()

        # Update the indices of the plot:
        self.i_start = self.i_min + event.GetPosition()
        self.i_end = self.i_min + self.i_window + event.GetPosition()

        #Update Scrollbar & labels
        self.canvas.SetScrollPos(wx.HORIZONTAL, event.GetPosition(), True)
        self.startTime.ChangeValue("Start Time: " + (float(self.i_start) /
                                                     self.samprate).__repr__())
        self.endTime.ChangeValue("End Time: " + (float(self.i_end) /
                                                 self.samprate).__repr__())

    """
    Handles Graph Scrolling
    """

    def OnScrollStop(self, event):
        self.draw_plot()

    """
    When a graph is clicked on, handles the creation of a zoomed in 
    view of that graph (Zoom in View) 
    """

    def onclick(self, event):

        #loop through all plots to check which one was clicked
        i = 0
        while i < self.electrodeX * self.electrodeY:
            if i not in self.empty:
                if event.inaxes == self.axes[i]:
                    fig2 = plt.figure()
                    ax_single = fig2.add_subplot(111)

                    #input in data and graph section/ limits
                    ax_single.plot(self.t, self.data[0], 'yo-')
                    ax_single.set_xlim([0, self.time])
                    ax_single.set_autoscale_on(False)

                    #Plot Naming According to Electrode Position
                    if (i + 1) % self.electrodeX != 0:
                        rowno = ((i + 1) / self.electrodeX) + 1
                    else:
                        rowno = (i + 1) / self.electrodeX
                    if (i + 1) % self.electrodeX == 0:
                        colno = self.electrodeX
                    else:
                        colno = (i + 1) % self.electrodeX
                    fig2.canvas.set_window_title('Plot ' + rowno.__repr__() +
                                                 " x " + colno.__repr__())
                    fig2.show()

                    break
            i += 1