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)
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