class matplotsink(wx.Panel): def __init__(self, parent, title, queue, gsz, zoom): wx.Panel.__init__(self, parent, wx.SIMPLE_BORDER) self.gsz = gsz self.parent = parent self.title = title self.q = queue self.zoom = zoom self.paused = False # self.create_menu() # self.create_status_bar() self.create_main_panel() def create_menu(self): self.menubar = wx.MenuBar() menu_file = wx.Menu() m_expt = menu_file.Append(-1, "&Save plot\tCtrl-S", "Save plot to file") self.Bind(wx.EVT_MENU, self.on_save_plot, m_expt) menu_file.AppendSeparator() m_exit = menu_file.Append(-1, "E&xit\tCtrl-X", "Exit") self.Bind(wx.EVT_MENU, self.on_exit, m_exit) self.menubar.Append(menu_file, "&File") self.SetMenuBar(self.menubar) def create_main_panel(self): self.panel = self self.init_plot() self.canvas = FigCanvas(self.panel, -1, self.fig) self.scroll_range = 400 self.canvas.SetScrollbar(wx.HORIZONTAL, 0, 5, self.scroll_range) self.canvas.Bind(wx.EVT_SCROLLWIN, self.OnScrollEvt) self.pause_button = wx.Button(self.panel, -1, "Pause") self.Bind(wx.EVT_BUTTON, self.on_pause_button, self.pause_button) self.Bind(wx.EVT_UPDATE_UI, self.on_update_pause_button, self.pause_button) self.cb_grid = wx.CheckBox(self.panel, -1, "Show Grid", style=wx.ALIGN_RIGHT) self.Bind(wx.EVT_CHECKBOX, self.on_cb_grid, self.cb_grid) self.cb_grid.SetValue(True) self.cb_xlab = wx.CheckBox(self.panel, -1, "Show X labels", style=wx.ALIGN_RIGHT) self.Bind(wx.EVT_CHECKBOX, self.on_cb_xlab, self.cb_xlab) self.cb_xlab.SetValue(True) self.hbox1 = wx.BoxSizer(wx.HORIZONTAL) self.hbox1.Add(self.pause_button, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL) self.hbox1.AddSpacer(20) self.hbox1.Add(self.cb_grid, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL) self.hbox1.AddSpacer(10) self.hbox1.Add(self.cb_xlab, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL) self.vbox = wx.BoxSizer(wx.VERTICAL) self.vbox.Add(self.canvas, 1, flag=wx.LEFT | wx.TOP | wx.GROW) self.vbox.Add(self.hbox1, 0, flag=wx.ALIGN_LEFT | wx.TOP) self.panel.SetSizer(self.vbox) self.vbox.Fit(self) self.ani = animation.FuncAnimation(self.fig, self.draw_plot, interval=100) def OnScrollEvt(self, event): self.i_start = event.GetPosition() self.i_end = self.i_window + event.GetPosition() self.draw_plot(0) def create_status_bar(self): self.statusbar = self.CreateStatusBar() def draw_test(self, event): self.xar = np.arange(len(self.q.queue)) self.yar = np.array(self.q.queue) self.axes.plot(self.xar, self.yar) def init_plot(self): self.dpi = 100 self.fig = Figure((3.0, 3.0), dpi=self.dpi) self.fig.set_size_inches(7.0, 4.0) self.fig.set_dpi(self.dpi) self.axes = self.fig.add_subplot(111) self.axes.set_axis_bgcolor('black') self.axes.set_title(self.title, size=12) pylab.setp(self.axes.get_xticklabels(), fontsize=8) pylab.setp(self.axes.get_yticklabels(), fontsize=8) self.i_window = self.gsz self.i_start = 0 self.i_end = self.i_start + self.i_window # plot the data as a line series, and save the reference # to the plotted line series # self.plot_data = self.axes.plot( [], linewidth=1, color=(1, 1, 0), )[0] def draw_plot(self, event): """ Redraws the plot """ if len(list(self.q.queue)) > 1 and not self.paused: if self.zoom: xmax = len(list( self.q.queue)) if len(list(self.q.queue)) > 50 else 50 xmin = xmax - 50 # for ymin and ymax, find the minimal and maximal values # in the data set and add a mininal margin. # # note that it's easy to change this scheme to the # minimal/maximal value in the current display, and not # the whole data set. # ymin = round(min(list(self.q.queue)), 0) - 1 ymax = round(max(list(self.q.queue)), 0) + 1 self.axes.set_xbound(lower=xmin, upper=xmax) self.axes.set_ybound(lower=ymin, upper=ymax) # anecdote: axes.grid assumes b=True if any other flag is # given even if b is set to False. # so just passing the flag into the first statement won't # work. # if self.cb_grid.IsChecked(): self.axes.grid(True, color='gray') else: self.axes.grid(False) # Using setp here is convenient, because get_xticklabels # returns a list over which one needs to explicitly # iterate, and setp already handles this. # pylab.setp(self.axes.get_xticklabels(), visible=self.cb_xlab.IsChecked()) self.plot_data.set_xdata(np.arange(len(list(self.q.queue)))) self.plot_data.set_ydata(np.array(list(self.q.queue))) self.canvas.draw() else: if self.cb_grid.IsChecked(): self.axes.grid(True, color='gray') else: self.axes.grid(False) # Using setp here is convenient, because get_xticklabels # returns a list over which one needs to explicitly # iterate, and setp already handles this. pylab.setp(self.axes.get_xticklabels(), visible=self.cb_xlab.IsChecked()) self.plot_data.set_xdata( np.arange(len(list( self.q.queue)))[self.i_start:self.i_end]) self.plot_data.set_ydata( np.array(list(self.q.queue))[self.i_start:self.i_end]) self.axes.set_xlim( min( np.arange(len(list( self.q.queue)))[self.i_start:self.i_end]), max( np.arange(len(list( self.q.queue)))[self.i_start:self.i_end])) # if self.zoom: self.axes.set_ylim(min(np.array(list(self.q.queue))), max(np.array(list(self.q.queue)))) self.canvas.draw() def on_pause_button(self, event): self.paused = not self.paused def on_update_pause_button(self, event): label = "Resume" if self.paused else "Pause" self.pause_button.SetLabel(label) def on_cb_grid(self, event): self.draw_plot(0) def on_cb_xlab(self, event): self.draw_plot(0) def on_save_plot(self, event): file_choices = "PNG (*.png)|*.png" dlg = wx.FileDialog(self, message="Save plot as...", defaultDir=os.getcwd(), defaultFile="plot.png", wildcard=file_choices, style=wx.SAVE) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() self.canvas.print_figure(path, dpi=self.dpi) self.flash_status_message("Saved to %s" % path) def on_redraw_timer(self, event): # if paused do not add data, but still redraw the plot # (to respond to scale modifications, grid change, etc.) # if not self.paused: self.data += self.datagen.next() self.draw_plot(0) def on_exit(self, event): self.Destroy() def flash_status_message(self, msg, flash_len_ms=1500): self.statusbar.SetStatusText(msg) self.timeroff = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.on_flash_status_off, self.timeroff) self.timeroff.Start(flash_len_ms, oneShot=True) def on_flash_status_off(self, event): self.statusbar.SetStatusText('')
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): def __init__(self, parent, id): 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 = 400 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.init_data() self.init_plot() self.canvas.Bind(wx.EVT_SCROLLWIN, self.OnScrollEvt) def init_data(self): # Generate some data to plot: self.dt = 0.01 self.t = arange(0,5,self.dt) self.x = sin(2*pi*self.t) # Extents of data sequence: self.i_min = 0 self.i_max = len(self.t) # Size of plot window: self.i_window = 100 # Indices of data interval to be plotted: self.i_start = 0 self.i_end = self.i_start + self.i_window def init_plot(self): self.axes = self.fig.add_subplot(111) self.plot_data = \ self.axes.plot(self.t[self.i_start:self.i_end], self.x[self.i_start:self.i_end])[0] def draw_plot(self): # Update data in plot: self.plot_data.set_xdata(self.t[self.i_start:self.i_end]) self.plot_data.set_ydata(self.x[self.i_start:self.i_end]) # Adjust plot limits: self.axes.set_xlim((min(self.t[self.i_start:self.i_end]), max(self.t[self.i_start:self.i_end]))) self.axes.set_ylim((min(self.x[self.i_start:self.i_end]), max(self.x[self.i_start:self.i_end]))) # Redraw: self.canvas.draw() def OnScrollEvt(self, event): # 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() self.draw_plot()
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