Ejemplo n.º 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)
Ejemplo n.º 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, resolution):
        
        #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
        self.resolution = resolution
        self.stepsize = self.samprate / resolution
        #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.Bind(wx.EVT_SCROLLWIN_LINEDOWN, self.OnScrollLeft_small)
        self.canvas.Bind(wx.EVT_SCROLLWIN_LINEUP, self.OnScrollRight_small)
        self.canvas.Bind(wx.EVT_SCROLLWIN_PAGEDOWN, self.OnScrollLeft_large)
        self.canvas.Bind(wx.EVT_SCROLLWIN_PAGEUP, self.OnScrollRight_large)
        self.canvas.mpl_connect('button_press_event',self.onclick)


    def init_data(self):
        """
        Parses data to be fed into visualization. 
        """
    
        # 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)
    
        # 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
        
        # Indices of data interval to be plotted:
        self.i_start = 0
        self.i_end = self.i_start + self.i_window


    def init_plot(self):
        """
        Creates 8x8 Data Plots
        """
        
        #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__()+"s", 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__()+"s", 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.graphs.append(
                      self.axes[j].plot(self.t[self.i_start:self.i_end:max(1,self.stepsize)],
                                 self.data[j-arrayoffset][self.i_start:self.i_end:max(1,self.stepsize)])[0])
            else:
                self.axes.append(0)
                self.graphs.append(0)
                arrayoffset=arrayoffset+1
        self.canvas.draw()        
            
   
    def draw_plot(self, resAdj = 1.0):
        """
        Updates the section of data displayed according to scrolling event
        resAdj: gives the fraction of the designated resolution to display at. ie 1 being the original resolution and 0.5 being half the resolution
        """
        # print self.stepsize
        temp = self.stepsize
        self.stepsize = int(self.stepsize/resAdj)
        # Adjust plot limits:
        arrayoffset=0
        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:max(1,self.stepsize)])
                self.graphs[i].set_ydata(self.data[i-arrayoffset][self.i_start:self.i_end:max(1,self.stepsize)])
                self.axes[i].set_xlim(self.t[self.i_start], self.t[self.i_end])
                self.axes[i].set_ylim((min(self.data[i-arrayoffset][self.i_start:self.i_end:max(1,self.stepsize)]),
                            max(self.data[i-arrayoffset][self.i_start:self.i_end:max(1,self.stepsize)])))
            else:
                arrayoffset+=1
        self.stepsize = temp
        # Redraw:
        self.canvas.draw()
        self.startTime.Refresh()
        self.endTime.Refresh()
        
    def ScrollPlots(self):
        #Update the label values and set the plot ranges.
        self.i_start = self.i_min + self.canvas.GetScrollPos(wx.HORIZONTAL)
        self.i_end = self.i_min + self.i_window + self.canvas.GetScrollPos(wx.HORIZONTAL)
        self.startTime.ChangeValue("Start Time: " + (float(self.i_start)/self.samprate).__repr__()+"s")
        self.endTime.ChangeValue("End Time: " + (float(self.i_end)/self.samprate).__repr__()+"s")     

    def OnScrollRight_small(self, event):
        self.canvas.SetScrollPos(wx.HORIZONTAL, self.canvas.GetScrollPos(wx.HORIZONTAL)-self.i_window/4, True)
        self.ScrollPlots()
        self.draw_plot()

    
    def OnScrollLeft_small(self, event):
        self.canvas.SetScrollPos(wx.HORIZONTAL, self.canvas.GetScrollPos(wx.HORIZONTAL)+self.i_window/4, True)
        self.ScrollPlots()
        self.draw_plot()
    
    def OnScrollRight_large(self, event):
        self.canvas.SetScrollPos(wx.HORIZONTAL, self.canvas.GetScrollPos(wx.HORIZONTAL)-self.i_window, True)
        self.ScrollPlots()
        self.draw_plot()
    
    def OnScrollLeft_large(self, event):
        self.canvas.SetScrollPos(wx.HORIZONTAL, self.canvas.GetScrollPos(wx.HORIZONTAL)+self.i_window, True)
        self.ScrollPlots()
        self.draw_plot()

    def OnScrollEvt(self, event):
        """
        Handles Graph Scrolling
        """
        
        if((datetime.datetime.utcnow()-self.lastupdate).microseconds>750000):
            self.draw_plot(0.1)
            self.lastupdate = datetime.datetime.utcnow()
        
        #Set new scroll position
        self.canvas.SetScrollPos(wx.HORIZONTAL, event.GetPosition(), True)

        #Update the indicies of the plots:
        self.ScrollPlots()
    
    
    def OnScrollStop(self, event):
        """
        Handles Graph Scrolling
        """
        self.draw_plot()
    
    
    def onclick(self, event):
        """
        When a graph is clicked on, handles the creation of a zoomed in 
        view of that graph (Zoom in View) 
        """
        
        #loop through all plots to check which one was clicked
        i=0
        arrayoffset=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[i-arrayoffset], 'b-')
                    ax_single.set_xlim([self.i_start/self.samprate,self.i_end/self.samprate])
                    ax_single.set_autoscale_on(False)
                    ax_single.set_ylabel('Millivolts')
                    ax_single.set_xlabel('Time in Seconds')

                    #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
            else: 
                arrayoffset+=1
            i+=1