class PyplotEmbed(tk.Frame): """ Class that will make a tkinter frame with a matplotlib plot area embedded in the frame """ def __init__(self, master, toolbox_frame, plt_props, _master_frame, y_lims, x_low, x_high): """ Initialize the class with a parent of tkinter Frame and embed a pyplot graph in it The class also will have a list to hold the data series that is displayed :param toolbox_frame: tkinter frame that the toolbox can be shown in :param plt_props: properties of the pyplot :param _master: the frame that is the master to this frame :param _params: parameters needed for setting up the class :return: """ tk.Frame.__init__( self, master=_master_frame) # initialize with the parent class self.master = _master_frame self.l = None self.user_sets_labels_after_run = True self.label_instance = "" # Make an area to graph the data self.graph_area = tk.Frame(self) self.plotted_lines = [ ] # make a list to hold the Line2D to display in the graph self.data = _master_frame.data # alias the data for this class to the main data self.legend_displayed = False # initiate the pyplot area self.init_graph_area(plt_props, toolbox_frame, y_lims, x_low, x_high) self.toolbar_status = False def init_graph_area(self, plt_props, toolbox_frame, y_lim, x_low, x_high): """ take the tkinter Frame (self) and embed a pyplot figure into it :param plt_props: dictionary of properties of the pyplot :return: bind figure and axis to this instance """ self.graph_area.figure_bed = plt.figure(figsize=(5, 4)) self.graph_area.axis = plt.subplot(111) self.graph_area.axis.format_coord = lambda x, y: "" # remove the coordinates in the toolbox # go through the plot properties and apply each one that is listed for key, value in plt_props.iteritems(): eval("plt." + key + "(" + value + ")") # get the limits of the x axis from the parameters if they are not in the properties if "xlim" not in plt_props: plt.xlim(x_low, x_high) # calculate the current limit that can be reached, which depends on the resistor value # of the TIAassume the adc can read +- 1V (1000 mV) plt.ylim(-y_lim, y_lim) # format the graph area, make the canvas and show it self.graph_area.figure_bed.set_facecolor('white') self.graph_area.canvas = FigureCanvasTkAgg(self.graph_area.figure_bed, master=self) self.graph_area.canvas._tkcanvas.config(highlightthickness=0) # Make a binding for the user to change the data legend # uncomment below to start making a data legend editor self.graph_area.canvas.mpl_connect('button_press_event', self.legend_handler) # Make the toolbar and then unpack it. allow the user to display or remove it later self.toolbar = NavToolbar(self.graph_area.canvas, toolbox_frame) self.toolbar.pack_forget() self.graph_area.canvas.draw() self.graph_area.canvas.get_tk_widget().pack(side='left', fill=tk.BOTH, expand=1) def update_data(self, x_data, y_data, _raw_y_data=None, label=None): print _raw_y_data if self.user_sets_labels_after_run: self.data.add_data(x_data, y_data, _raw_y_data) self.display_data() if not label: toplevel.UserSetDataLabel(self) else: self.change_label(label) else: self.data.add_data(x_data, y_data, _raw_y_data) self.display_data() def change_label(self, label, index=None): """ :param label: :param index: :return: """ if not index: index = self.data.index - 1 self.data.change_label(label, index) self.update_legend() def add_notes(self, _notes): """ Save a note to the data to save with it :param _notes: string """ self.data.notes[-1] = _notes def display_data_user_input(self, x_data, y_data): """ Update the label to what the user inputted, and display the data :param x_data: list - x-axis data :param y_data: list - y-axis data """ label = self.label_instance self.display_data(x_data, y_data, self.data.index - 1) def display_data(self): """ Take in a x and y data set and plot them in the self instance of the pyplot :param x_data: x axis data :param y_data: y axis data :return: """ index = self.data.index - 1 # it was incremented at the end of the add_data method x_data = self.data.voltage_data[index] y_data = self.data.current_data[index] _label = self.data.label[index] # if this is the first data series to be added the legend has to be displayed also if not self.legend_displayed: _box = self.graph_area.axis.get_position() self.graph_area.axis.set_position([ _box.x0, _box.y0, _box.width * LEGEND_SPACE_RATIO, _box.height ]) self.legend_displayed = True # add the data to the plot area and update the legend print len(x_data), len(y_data) print y_data l = self.graph_area.axis.plot(x_data, y_data, label=_label) self.data.colors.append(l[0].get_color()) self.plotted_lines.append(l) self.update_legend() def update_amp_data(self, t, y, time_displayed): # self.graph_area.axis.clear() if not self.l and t: self.l, = self.graph_area.axis.plot(t, y) self.graph_area.axis.set_xlim(t[-1] - time_displayed, t[-1]) elif y: self.l.set_ydata(y) self.l.set_xdata(t) self.graph_area.axis.set_xlim(t[-1] - time_displayed, t[-1]) # self.graph_area.axis.set_ylim(0, 60000) self.graph_area.canvas.draw() def update_legend(self): """ Update the legend and redraw the graph """ handle, labels = self.graph_area.axis.get_legend_handles_labels() self.graph_area.axis.legend( handle, self.data.label, loc='center left', bbox_to_anchor=(1, 0.5), title='Data series', prop={'size': 10}, fancybox=True) # not adding all this screws it up # up for some reason self.graph_area.canvas.show( ) # update the canvas where the data is being shown def delete_all_lines(self): """ Remove all the lines from the graph """ logging.debug("deleting all lines") while self.plotted_lines: # remove lines release all the memory l = self.plotted_lines.pop(0) l.pop().remove( ) # self.plotted_lines is a list of list so you have to pop twice del l # see stackoverflow "how to remove lines in a matplotlib" # Update the legend with an empty data set but will keep the title and box showing # in the graph area self.update_legend() def delete_a_line(self, index): """ Delete a single line from the graph :param index: int, index of which line to delete. the lines are saved in a list called self.plotted_lines """ logging.debug("deleting line: %i", index) line = self.plotted_lines.pop(index) self.data.remove_data(index) line.pop().remove() del line # release memory self.update_legend() def change_line_color(self, _color, index): """ Change the color of a line :param _color: tkinter color option to change to :param index: index of which line in the self.plotted_lines list to change """ self.plotted_lines[index][0].set_color(_color) self.data.colors[index] = _color def update_graph(self): """ Redraw the graoh """ self.graph_area.canvas.show() def toolbar_toggle(self): """ Display or remove the toolbar from the GUI """ if self.toolbar_status: # there is a toolbar, so remove it self.toolbar.pack_forget() self.toolbar_status = False else: # no toolbar yet so add one self.toolbar.pack(side='left', anchor='w') self.toolbar_status = True def legend_handler(self, event): """ Bind event of clicking on the data legend to call up a top level to change the data style and label :param event: click event that occured """ if event.x > (0.82 * self.winfo_width() ): # if mouse is clicked on the right side self.master.change_data_labels() def resize_x(self, x_low, x_high): """ Change the scale of the x axis :param x_low: lower limit on x axis :param x_high: upper limit on x axis """ self.graph_area.axis.set_xlim([x_low, x_high]) self.graph_area.canvas.show() def resize_y(self, _current_limit): """ Change the scale of the y axis :param _current_limit: most current (positive or negative) """ self.graph_area.axis.set_ylim(-_current_limit * 1.2, _current_limit * 1.2) self.graph_area.canvas.show()
class PyplotEmbed(tk.Frame): """ Class that will make a tkinter frame with a matplotlib plot area embedded in the frame """ def __init__(self, master, data): tk.Frame.__init__(self, master=master) self.index = 1 self.lines = [] self.vert_line = None self.data = data self.cursor_connect = None self.graph_area = tk.Frame(self) self.figure_bed = plt.figure(figsize=(6,4)) self.axis = self.figure_bed.add_subplot(111) self.canvas = FigureCanvasTkAgg(self.figure_bed, master=self) self.canvas._tkcanvas.config(highlightthickness=0) self.toolbar = NavToolbar(self.canvas, self) # TODO: check this # self.toolbar.pack_forget() self.toolbar.pack() self.canvas.draw() self.canvas.get_tk_widget().pack(side='left', fill=tk.BOTH, expand=1) def plot(self, data, _label): # self.data.plot(ax=self.graph_area.axis, label='channel {0}'.format(self.index)) # line = self.axis.plot(data.index, data['voltage'], label=_label)[0] line = self.axis.plot(data.index, data, label=_label)[0] self.lines.append(line) self.axis.legend() self.index += 1 self.canvas.show() def delete_all(self): while self.lines: l = self.lines.pop() l.remove() del l self.canvas.draw() self.index = 1 self.axis.legend() def time_shift(self, data_index: int, time_to_shift: float): adj_time_shift = time_to_shift - self.data.time_start[data_index] x_data = self.data.adjusted_data[data_index].index - adj_time_shift self.lines[data_index].set_xdata(x_data) self.canvas.draw() def get_fit_start(self): print('make cursor') # cursor = self.axis.axvline(color='r') self.cursor_connect = self.canvas.mpl_connect('motion_notify_event', self.onMouseMove) self.canvas.mpl_connect('button_press_event', self.onclick) self.canvas.show() def onMouseMove(self, event): if not event.xdata: # mouse is not over the plot area return if self.vert_line: self.vert_line.remove() del self.vert_line self.vert_line = None self.vert_line = self.axis.axvline(x=event.xdata, color='r', linewidth=2) self.canvas.show() def onclick(self, event): if event.dblclick == 1: full_data_set = self.data.adjusted_data[-1] start_index = full_data_set.index.get_loc(event.xdata, 'nearest') # start_index = pd.Index(self.data.adjusted_data[-1]).get_loc(event.xdata, 'nearest') start_num = full_data_set.index[start_index] data_to_fit = self.data.adjusted_data[-1][start_num:start_num+20] self.fit_data(data_to_fit, start_num) def fit_data(self, _data, starting_place): print('fitting') self.canvas.mpl_disconnect(self.cursor_connect) t = _data.index - starting_place # change the time so t=0 at the start of the recording amplitude_guess = -_data.voltage.min() time_shift = 0 bounds = ( 0.0, [1.2*amplitude_guess, 1.2*amplitude_guess, 1.2*amplitude_guess, 1.2*amplitude_guess, 0.2, 2, 100, 100]) initial_guess = ( 2. * amplitude_guess / 3, amplitude_guess / 3., amplitude_guess / 2., amplitude_guess / 2., 0.2, 2, 2, 15) fitted_parameters, _ = curve_fit(fitting_func_2a_2i_exp, t, _data.voltage, p0=initial_guess, bounds=bounds, ftol=0.0000005, xtol=0.0000005) # fitted_parameters, _ = curve_fit(fitting_func_2a_2i_exp, t, _data.voltage, p0=initial_guess) print('fitting params: {0}'.format(fitted_parameters)) # make a new line with the fitted parameters and draw it y_fitted = fitting_func_2a_2i_exp(t, *fitted_parameters) # plt.plot(t + _data.index, y_fitted, linewidth=2, label="Check") fitted_line = self.axis.plot(_data.index, y_fitted, linewidth=2, label='fitted')[0]
class PyplotEmbed(tk.Frame): """ Class that will make a tkinter frame with a matplotlib plot area embedded in the frame """ def __init__(self, root, toolbox_frame, plt_props, _master_frame, _params): """ Initialize the class with a parent of tkinter Frame and embed a pyplot graph in it The class also will have a list to hold the data series that is displayed :param toolbox_frame: tkinter frame that the toolbox can be shown in :param plt_props: properties of the pyplot :param _master: the frame that is the master to this frame :param _params: parameters needed for setting up the class :return: """ tk.Frame.__init__(self, master=_master_frame) # initialize with the parent class self.master = _master_frame self.label_instance = "" """ Make an area to graph the data """ self.graph_area = tk.Frame(self) self.params = root.operation_params self.plotted_lines = [] # make a list to hold the Line2D to display in the graph self.data = root.data # alias the data for this class to the main data """ Create a list to hold the matplotlib lines """ # self.plotted_lines = [] # root.plotted_lines = self.plotted_lines self.params = _params self.legend_displayed = False """ initiate the pyplot area """ self.init_graph_area(plt_props, toolbox_frame) self.toolbar_status = False def init_graph_area(self, plt_props, toolbox_frame): """ take the tkinter Frame (self) and embed a pyplot figure into it :param plt_props: dictionary of properties of the pyplot :return: bind figure and axis to this instance """ self.graph_area.figure_bed = plt.figure(figsize=(5, 4)) self.graph_area.axis = plt.subplot(111) self.graph_area.axis.format_coord = lambda x, y: "" # remove the coordinates in the toolbox """ go through the plot properties and apply each one that is listed """ for key, value in plt_props.iteritems(): eval("plt." + key + "(" + value + ")") """ get the limits of the x axis from the parameters if they are not in the properties """ if "xlim" not in plt_props: plt.xlim(self.params['low_cv_voltage'], self.params['high_cv_voltage']) """ calculate the current limit that can be reached, which depends on the resistor value of the TIA assume the adc can read +- 1V (1000 mV)""" current_limit = 1000 / self.params['TIA_resistor'] # units: (mV/kohms) micro amperes plt.ylim(-current_limit, current_limit) """ format the graph area, make the canvas and show it """ self.graph_area.figure_bed.set_facecolor('white') self.graph_area.canvas = FigureCanvasTkAgg(self.graph_area.figure_bed, master=self) self.graph_area.canvas._tkcanvas.config(highlightthickness=0) """ Make a binding for the user to change the data legend """ # uncomment below to start making a data legend editor # self.graph_area.canvas.mpl_connect('button_press_event', self.legend_handler) """ Make the toolbar and then unpack it. allow the user to display or remove it later """ self.toolbar = NavToolbar(self.graph_area.canvas, toolbox_frame) self.toolbar.pack_forget() self.graph_area.canvas.draw() self.graph_area.canvas.get_tk_widget().pack(side='top', fill=tk.BOTH, expand=1) def update_data(self, x_data, y_data, _raw_y_data=None): if self.params['user_sets_labels_after_run']: self.data.add_data(x_data, y_data, _raw_y_data) self.display_data() toplevel.UserSetDataLabel(self) else: self.data.add_data(x_data, y_data, _raw_y_data) self.display_data() def change_label(self, label, index=None): if not index: index = self.data.index - 1 self.data.change_label(label, index) self.update_legend() def add_notes(self, _notes): self.data.notes[-1] = _notes def display_data_user_input(self, x_data, y_data): label = self.label_instance self.display_data(x_data, y_data, self.data.index-1) def display_data(self): """ Take in a x and y data set and plot them in the self instance of the pyplot :param x_data: x axis data :param y_data: y axis data :return: """ index = self.data.index - 1 # it was incremented at the end of the add_data method x_data = self.data.x_data[index] y_data = self.data.y_data[index] _label = self.data.label[index] """ if this is the first data series to be added the legend has to be displayed also """ if not self.legend_displayed: _box = self.graph_area.axis.get_position() self.graph_area.axis.set_position([_box.x0, _box.y0, _box.width * legend_space_ratio, _box.height]) self.legend_displayed = True """ add the data to the plot area and update the legend """ l = self.graph_area.axis.plot(x_data, y_data, label=_label) self.data.colors.append(l[0].get_color()) self.plotted_lines.append(l) self.update_legend() def update_legend(self): handle, labels = self.graph_area.axis.get_legend_handles_labels() self.graph_area.axis.legend(handle, self.data.label, loc='center left', bbox_to_anchor=(1, 0.5), title='Data series', prop={'size': 10}, fancybox=True) # not adding all this screws it up for some reason # self.graph_area.axis.legend.get_frame().set_alpha(0.5) self.graph_area.canvas.show() # update the canvas where the data is being shown def delete_all_lines(self): logging.debug("deleting all lines") while self.plotted_lines: l = self.plotted_lines.pop(0) l.pop().remove() # self.plotted_lines is a list of list so you have to pop twice del l # see stackoverflow "how to remove lines in a matplotlib", this is needed to release the memory """ Update the legend with an empty data set but will keep the title and box showing in the graph area """ self.update_legend() def delete_a_line(self, index): logging.debug("deleting line: %i", index) line = self.plotted_lines.pop(index) self.data.remove_data(index) line.pop().remove() del line self.update_legend() def change_line_color(self, _color, index): logging.debug("change line color: ", _color, index) print self.plotted_lines print self.plotted_lines[index] self.plotted_lines[index][0].set_color(_color) self.data.colors[index] = _color def update_graph(self): self.graph_area.canvas.show() def toolbar_toggle(self): """ Display or remove the toolbar from the GUI :return: """ if self.toolbar_status: # there is a toolbar, so remove it self.toolbar.pack_forget() self.toolbar_status = False else: # no toolbar yet so add one self.toolbar.pack(side='left', anchor='w') self.toolbar_status = True def legend_handler(self, event): """ :param event: :return: """ if event.x > (0.8 * self.winfo_width()): # if mouse is clicked on the right side print "on right side" legend_top.DataLegendTop(self) def resize_x(self, x_low, x_high): """ Change the scale of the x axis :param x_low: lower limit on x axis :param x_high: upper limit on x axis :return: """ self.graph_area.axis.set_xlim([x_low, x_high]) self.graph_area.canvas.show() def resize_y(self, _current_limit): """ Change the scale of the y axis :param _current_limit: most current (positive or negative) :return: """ self.graph_area.axis.set_ylim(-_current_limit, _current_limit) self.graph_area.canvas.show()
class PyplotEmbed(tk.Frame): """ Class that will make a tkinter frame with a matplotlib plot area embedded in the frame """ def __init__(self, root, toolbox_frame, plt_props, _master_frame, _params): """ Initialize the class with a parent of tkinter Frame and embed a pyplot graph in it The class also will have a list to hold the data series that is displayed :param toolbox_frame: tkinter frame that the toolbox can be shown in :param plt_props: properties of the pyplot :param _master: the frame that is the master to this frame :param _params: parameters needed for setting up the class :return: """ tk.Frame.__init__( self, master=_master_frame) # initialize with the parent class self.master = _master_frame self.label_instance = "" """ Make an area to graph the data """ self.graph_area = tk.Frame(self) self.params = root.operation_params self.plotted_lines = [ ] # make a list to hold the Line2D to display in the graph self.data = root.data # alias the data for this class to the main data """ Create a list to hold the matplotlib lines """ # self.plotted_lines = [] # root.plotted_lines = self.plotted_lines self.params = _params self.legend_displayed = False """ initiate the pyplot area """ self.init_graph_area(plt_props, toolbox_frame) self.toolbar_status = False def init_graph_area(self, plt_props, toolbox_frame): """ take the tkinter Frame (self) and embed a pyplot figure into it :param plt_props: dictionary of properties of the pyplot :return: bind figure and axis to this instance """ self.graph_area.figure_bed = plt.figure(figsize=(5, 4)) self.graph_area.axis = plt.subplot(111) self.graph_area.axis.format_coord = lambda x, y: "" # remove the coordinates in the toolbox """ go through the plot properties and apply each one that is listed """ for key, value in plt_props.iteritems(): eval("plt." + key + "(" + value + ")") """ get the limits of the x axis from the parameters if they are not in the properties """ if "xlim" not in plt_props: plt.xlim(self.params['low_cv_voltage'], self.params['high_cv_voltage']) """ calculate the current limit that can be reached, which depends on the resistor value of the TIA assume the adc can read +- 1V (1000 mV)""" current_limit = 1000 / self.params[ 'TIA_resistor'] # units: (mV/kohms) micro amperes plt.ylim(-current_limit, current_limit) """ format the graph area, make the canvas and show it """ self.graph_area.figure_bed.set_facecolor('white') self.graph_area.canvas = FigureCanvasTkAgg(self.graph_area.figure_bed, master=self) self.graph_area.canvas._tkcanvas.config(highlightthickness=0) """ Make a binding for the user to change the data legend """ # uncomment below to start making a data legend editor # self.graph_area.canvas.mpl_connect('button_press_event', self.legend_handler) """ Make the toolbar and then unpack it. allow the user to display or remove it later """ self.toolbar = NavToolbar(self.graph_area.canvas, toolbox_frame) self.toolbar.pack_forget() self.graph_area.canvas.draw() self.graph_area.canvas.get_tk_widget().pack(side='top', fill=tk.BOTH, expand=1) def update_data(self, x_data, y_data, _raw_y_data=None): if self.params['user_sets_labels_after_run']: self.data.add_data(x_data, y_data, _raw_y_data) self.display_data() toplevel.UserSetDataLabel(self) else: self.data.add_data(x_data, y_data, _raw_y_data) self.display_data() def change_label(self, label, index=None): if not index: index = self.data.index - 1 self.data.change_label(label, index) self.update_legend() def add_notes(self, _notes): self.data.notes[-1] = _notes def display_data_user_input(self, x_data, y_data): label = self.label_instance self.display_data(x_data, y_data, self.data.index - 1) def display_data(self): """ Take in a x and y data set and plot them in the self instance of the pyplot :param x_data: x axis data :param y_data: y axis data :return: """ index = self.data.index - 1 # it was incremented at the end of the add_data method x_data = self.data.x_data[index] y_data = self.data.y_data[index] _label = self.data.label[index] """ if this is the first data series to be added the legend has to be displayed also """ if not self.legend_displayed: _box = self.graph_area.axis.get_position() self.graph_area.axis.set_position([ _box.x0, _box.y0, _box.width * legend_space_ratio, _box.height ]) self.legend_displayed = True """ add the data to the plot area and update the legend """ l = self.graph_area.axis.plot(x_data, y_data, label=_label) self.data.colors.append(l[0].get_color()) self.plotted_lines.append(l) self.update_legend() def update_legend(self): handle, labels = self.graph_area.axis.get_legend_handles_labels() self.graph_area.axis.legend( handle, self.data.label, loc='center left', bbox_to_anchor=(1, 0.5), title='Data series', prop={'size': 10}, fancybox=True) # not adding all this screws it up for some reason # self.graph_area.axis.legend.get_frame().set_alpha(0.5) self.graph_area.canvas.show( ) # update the canvas where the data is being shown def delete_all_lines(self): logging.debug("deleting all lines") while self.plotted_lines: l = self.plotted_lines.pop(0) l.pop().remove( ) # self.plotted_lines is a list of list so you have to pop twice del l # see stackoverflow "how to remove lines in a matplotlib", this is needed to release the memory """ Update the legend with an empty data set but will keep the title and box showing in the graph area """ self.update_legend() def delete_a_line(self, index): logging.debug("deleting line: %i", index) line = self.plotted_lines.pop(index) self.data.remove_data(index) line.pop().remove() del line self.update_legend() def change_line_color(self, _color, index): logging.debug("change line color: ", _color, index) print self.plotted_lines print self.plotted_lines[index] self.plotted_lines[index][0].set_color(_color) self.data.colors[index] = _color def update_graph(self): self.graph_area.canvas.show() def toolbar_toggle(self): """ Display or remove the toolbar from the GUI :return: """ if self.toolbar_status: # there is a toolbar, so remove it self.toolbar.pack_forget() self.toolbar_status = False else: # no toolbar yet so add one self.toolbar.pack(side='left', anchor='w') self.toolbar_status = True def legend_handler(self, event): """ :param event: :return: """ if event.x > (0.8 * self.winfo_width() ): # if mouse is clicked on the right side print "on right side" legend_top.DataLegendTop(self) def resize_x(self, x_low, x_high): """ Change the scale of the x axis :param x_low: lower limit on x axis :param x_high: upper limit on x axis :return: """ self.graph_area.axis.set_xlim([x_low, x_high]) self.graph_area.canvas.show() def resize_y(self, _current_limit): """ Change the scale of the y axis :param _current_limit: most current (positive or negative) :return: """ self.graph_area.axis.set_ylim(-_current_limit, _current_limit) self.graph_area.canvas.show()
class PyplotEmbed(tk.Frame): """ Class that will make a tkinter frame with a matplotlib plot area embedded in the frame """ def __init__(self, master, data): tk.Frame.__init__(self, master=master) self.index = 1 self.lines = [] self.labels = [] self.colors = [] self.vert_line = None self.data = data self.cursor_connect = None self.graph_area = tk.Frame(self) self.figure_bed = plt.figure(figsize=(6, 4)) self.axis = self.figure_bed.add_subplot(111) self.canvas = FigureCanvasTkAgg(self.figure_bed, master=self) self.canvas._tkcanvas.config(highlightthickness=0) self.toolbar = NavToolbar(self.canvas, self) # TODO: check this # self.toolbar.pack_forget() self.toolbar.pack() self.canvas.draw() self.canvas.get_tk_widget().pack(side='left', fill=tk.BOTH, expand=1) def plot(self, data, _label, color=None): # self.data.plot(ax=self.graph_area.axis, label='channel {0}'.format(self.index)) # line = self.axis.plot(data.index, data['voltage'], label=_label)[0] line = self.axis.plot(data.index, data, label=_label)[0] if color: line.set_color(color) self.colors.append(line.get_color()) self.labels.append(_label) self.lines.append(line) self.axis.legend() self.index += 1 self.canvas.show() def delete_all(self): while self.lines: l = self.lines.pop() l.remove() del l self.canvas.draw() self.index = 1 self.axis.legend() def delete_some_data(self, picks): print('delete in graph: ', picks) for index in reversed(picks): self.delete_line(index) def delete_line(self, _index): self.index -= 1 del self.labels[_index] line = self.lines.pop(_index) line.remove() del line self.update_legend() def change_line_color(self, _color, index): print('change line:', index, _color) self.lines[index].set_color(_color) self.colors[index] = _color def change_line_style(self, style, index): if style != 'solid': self.lines[index].set_linestyle(style) self.lines[index].set_dashes((1, 5)) def update_legend(self): """ Update the legend and redraw the graph """ handle, labels = self.axis.get_legend_handles_labels() self.axis.legend( handle, self.labels, loc='best', # bbox_to_anchor=(1, 0.5), # title='Data series', prop={'size': 10}, fancybox=True) # not adding all this screws it up # up for some reason self.canvas.show() # update the canvas where the data is being shown def time_shift(self, data_index: int, time_to_shift: float): adj_time_shift = time_to_shift - self.data.time_start[data_index] x_data = self.data.adjusted_data[data_index].index - adj_time_shift self.lines[data_index].set_xdata(x_data) self.canvas.draw() def get_fit_start(self): print('make cursor') # cursor = self.axis.axvline(color='r') self.cursor_connect = self.canvas.mpl_connect('motion_notify_event', self.onMouseMove) self.canvas.mpl_connect('button_press_event', self.onclick) self.canvas.show() def onMouseMove(self, event): if not event.xdata: # mouse is not over the plot area return if self.vert_line: self.vert_line.remove() del self.vert_line self.vert_line = None self.vert_line = self.axis.axvline(x=event.xdata, color='r', linewidth=2) self.canvas.show() def onclick(self, event): if event.dblclick == 1: full_data_set = self.data.adjusted_data[-1] start_index = full_data_set.index.get_loc(event.xdata, 'nearest') # start_index = pd.Index(self.data.adjusted_data[-1]).get_loc(event.xdata, 'nearest') start_num = full_data_set.index[start_index] data_to_fit = self.data.adjusted_data[-1][start_num:start_num + 20] self.fit_data(data_to_fit, start_num) def fit_data(self, _data, starting_place): print('fitting') self.canvas.mpl_disconnect(self.cursor_connect) t = _data.index - starting_place # change the time so t=0 at the start of the recording amplitude_guess = -_data.voltage.min() time_shift = 0 bounds = (0.0, [ 1.2 * amplitude_guess, 1.2 * amplitude_guess, 1.2 * amplitude_guess, 1.2 * amplitude_guess, 0.2, 2, 100, 100 ]) initial_guess = (2. * amplitude_guess / 3, amplitude_guess / 3., amplitude_guess / 2., amplitude_guess / 2., 0.2, 2, 2, 15) fitted_parameters, _ = curve_fit(fitting_func_2a_2i_exp, t, _data.voltage, p0=initial_guess, bounds=bounds, ftol=0.0000005, xtol=0.0000005) # fitted_parameters, _ = curve_fit(fitting_func_2a_2i_exp, t, _data.voltage, p0=initial_guess) print('fitting params: {0}'.format(fitted_parameters)) # make a new line with the fitted parameters and draw it y_fitted = fitting_func_2a_2i_exp(t, *fitted_parameters) # plt.plot(t + _data.index, y_fitted, linewidth=2, label="Check") fitted_line = self.axis.plot(_data.index, y_fitted, linewidth=2, label='fitted')[0] def toogle_data_decimation(self, data): # line: matplotlib.lines.Line2D # type hint the for loop variable for i, line in enumerate(self.lines): line.set_xdata(data[i].index.values) line.set_ydata(data[i]) self.canvas.show()