def _setup_ui(self): # Add a side menu for specifying the wavelength of the selected line panel = QtWidgets.QWidget() label = QtWidgets.QLabel("Enter wavelength [Å]:", panel) help_label = QtWidgets.QLabel("Enter a wavelength value, zoom in, then select the region " "containing the emission line at the specified wavelength.", panel) help_label.setStyleSheet("font-style: italic;") self._ui['textbox'] = QtWidgets.QLineEdit(parent=panel) panel.layout = QtWidgets.QGridLayout(panel) panel.layout.addWidget(label, 0, 0, 1, 1) panel.layout.addWidget(self._ui['textbox'], 0, 1, 1, 1) panel.layout.addWidget(help_label, 1, 0, 1, 2, Qt.AlignCenter) main_window = self.fig.canvas.manager.window dock = QtWidgets.QDockWidget("Enter wavelength:", main_window) main_window.addDockWidget(Qt.BottomDockWidgetArea, dock) dock.setWidget(panel) # A 1D span selector to highlight a given line span = SpanSelector(self.ax, self._on_select, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='red')) span.set_active(False) def enable_span(): tb = self.fig.canvas.manager.toolbar if span.active: span.set_active(False) else: span.set_active(True) if tb._active == 'PAN': tb.pan() tb._actions['pan'].setChecked(False) if tb._active == 'ZOOM': tb.zoom() tb._actions['zoom'].setChecked(False) span_control = QtWidgets.QPushButton('λ') span_control.setCheckable(True) span_control.clicked.connect(enable_span) span_control.setStyleSheet("color: #de2d26; font-weight: bold;") self.fig.canvas.manager.toolbar.addWidget(span_control) # setup auto-identify button if self.line_list is not None: autoid_control = QtWidgets.QPushButton('auto-identify') autoid_control.clicked.connect(self.auto_identify) self.fig.canvas.manager.toolbar.addWidget(autoid_control) # add a button for "done" done_control = QtWidgets.QPushButton('done') done_control.clicked.connect(self._finish) self.fig.canvas.manager.toolbar.addWidget(done_control) plt.show()
class HELPQDialg(QWidget): def __init__(self, parent=None): super(HELPQDialg, self).__init__(parent) self.results = {} self.help_result = [] self.pc = 0 self.ms = [] self.rt = [] self.createVariabletable() self.create_canvas1('scan', 'ETA or LPG') self.create_canvas2('scan', 'Resolved Chromatographic Profiles') self.canvas1.setMinimumWidth(800) self.canvas1.setMaximumWidth(800) self.canvas2.setMinimumWidth(800) self.canvas2.setMaximumWidth(800) self.mthcombox = QComboBox() self.mthcombox.addItem("ETA") self.mthcombox.addItem("LPG") self.DoETA = QPushButton("Do") LAYER = QLabel("LAYER:") self.LComboBox = QSpinBox() wLabel = QLabel("W:") self.DComboBox = QSpinBox() self.DComboBox.setRange(3, 9) self.DComboBox.setSingleStep(2) self.DComboBox.setValue(7) CLabel1 = QLabel("~") CLabel2 = QLabel("~") CLabel3 = QLabel("~") Selabel = QLabel("SE:") self.SComboBox1 = QLineEdit() self.SComboBox2 = QLineEdit() self.sbtn = QPushButton("...") Ovlabel = QLabel("OV:") self.obtn1 = QPushButton("...") self.OComboBox1 = QLineEdit() self.OComboBox2 = QLineEdit() self.OComboBox3 = QLineEdit() self.OComboBox4 = QLineEdit() self.obtn2 = QPushButton("...") self.DoFR = QPushButton("FR") self.addbtn = QPushButton("Add raw data") self.undobtn = QPushButton("Undo") hbox0 = QHBoxLayout() hbox0.addWidget(LAYER) hbox0.addWidget(self.LComboBox) hbox1 = QHBoxLayout() hbox1.addWidget(wLabel) hbox1.addWidget(self.DComboBox) hbox2 = QHBoxLayout() hbox2.addWidget(self.mthcombox) hbox2.addWidget(self.DoETA) hbox3 = QHBoxLayout() hbox3.addWidget(Selabel) hbox3.addWidget(self.SComboBox1) hbox3.addWidget(CLabel1) hbox3.addWidget(self.SComboBox2) hbox3.addWidget(self.sbtn) hbox4 = QHBoxLayout() hbox4.addWidget(Ovlabel) hbox4.addWidget(self.OComboBox1) hbox4.addWidget(CLabel2) hbox4.addWidget(self.OComboBox2) hbox4.addWidget(self.obtn1) hbox5 = QHBoxLayout() hbox5.addWidget(Ovlabel) hbox5.addWidget(self.OComboBox3) hbox5.addWidget(CLabel3) hbox5.addWidget(self.OComboBox4) hbox5.addWidget(self.obtn2) hbox6 = QHBoxLayout() hbox6.addStretch() hbox6.addWidget(self.DoFR) hbox7 = QHBoxLayout() hbox7.addStretch() hbox7.addWidget(self.undobtn) GLay = QGridLayout() GLay.addWidget(self.addbtn, 0, 0) GLay.addLayout(hbox0, 1, 0) GLay.addLayout(hbox1, 2, 0) GLay.addLayout(hbox2, 3, 0) GLay.addLayout(hbox3, 4, 0) GLay.addLayout(hbox4, 5, 0) GLay.addLayout(hbox5, 6, 0) GLay.addLayout(hbox6, 7, 0) GLay.addLayout(hbox7, 8, 0) VLay = QVBoxLayout() VLay.addWidget(self.canvas1) VLay.addWidget(self.canvas2) VLay1 = QVBoxLayout() VLay1.addLayout(GLay) VLay1.addStretch() mainLayout = QHBoxLayout() mainLayout.addLayout(VLay) mainLayout.addLayout(VLay1) self.setLayout(mainLayout) self.resize(800, 600) self.move(320, 75) self.setWindowTitle("HELP") self.span1.set_active(True) self.span2.set_active(False) self.span3.set_active(False) self.DoETA.clicked.connect(self.eta) self.DoFR.clicked.connect(self.fr) self.undobtn.clicked.connect(self.undo) self.sbtn.clicked.connect(self.span_mode1) self.obtn1.clicked.connect(self.span_mode2) self.obtn2.clicked.connect(self.span_mode3) def createVariabletable(self): self.VariableTable = QtGui.QTableWidget(0, 1) self.VariableTable.setSelectionMode( QtGui.QAbstractItemView.SingleSelection) self.VariableTable.horizontalHeader().hide() self.VariableTable.verticalHeader().hide() self.VariableTable.setShowGrid(False) self.VariableTable.setFixedWidth(200) def redraw1(self): self.canvas1.draw() self.update() def redraw2(self): self.canvas2.draw() self.update() def create_canvas1(self, xname, title): self.fig1 = plt.figure() self.axes1 = plt.subplot(111) self.axes1.set_xlabel(xname) self.axes1.set_title(title, fontsize=9) self.canvas1 = FigureCanvas(self.fig1) self.axes1.tick_params(axis='both', labelsize=8) ymino, ymaxo = self.axes1.get_ylim() xmino, xmaxo = self.axes1.get_xlim() self.oxy = [(xmino, xmaxo), (ymino, ymaxo)] self.span1 = SpanSelector(self.axes1, self.span_select_callback1, 'horizontal', minspan=0.002, useblit=True, rectprops=dict(alpha=0.5, facecolor='red'), onmove_callback=None, button=[1]) self.span2 = SpanSelector(self.axes1, self.span_select_callback2, 'horizontal', minspan=0.002, useblit=True, rectprops=dict(alpha=0.5, facecolor='green'), onmove_callback=None, button=[1]) self.span3 = SpanSelector(self.axes1, self.span_select_callback3, 'horizontal', minspan=0.002, useblit=True, rectprops=dict(alpha=0.5, facecolor='green'), onmove_callback=None, button=[1]) plt.subplots_adjust(bottom=0.2, top=0.90, left=0.08, right=0.9) self.redraw1() self.span1.set_active(True) def create_canvas2(self, xname, title): self.fig2 = plt.figure() self.axes2 = plt.subplot(111) self.axes2.set_xlabel(xname) self.axes2.set_title(title, fontsize=9) self.canvas2 = FigureCanvas(self.fig2) self.axes2.tick_params(axis='both', labelsize=8) plt.subplots_adjust(bottom=0.2, top=0.90, left=0.08, right=0.9) self.redraw2() def span_mode1(self, event): self.span1.set_active(True) self.span2.set_active(False) self.span3.set_active(False) self.span1.connect_event('motion_notify_event', self.span1.onmove) self.span1.connect_event('button_press_event', self.span1.press) self.span1.connect_event('button_release_event', self.span1.release) self.leftdblclick = False self.rightdblclick = False self.redraw1() print "span1" def span_mode2(self, event): self.span1.set_active(False) self.span3.set_active(False) self.span2.set_active(True) self.span2.connect_event('motion_notify_event', self.span2.onmove) self.span2.connect_event('button_press_event', self.span2.press) self.span2.connect_event('button_release_event', self.span2.release) self.leftdblclick = False self.rightdblclick = False self.redraw1() print "span2" def span_mode3(self, event): self.span1.set_active(False) self.span2.set_active(False) self.span3.set_active(True) self.span3.connect_event('motion_notify_event', self.span3.onmove) self.span3.connect_event('button_press_event', self.span3.press) self.span3.connect_event('button_release_event', self.span3.release) self.leftdblclick = False self.rightdblclick = False self.redraw1() print "span3" def span_select_callback1(self, xmin, xmax): ax = np.arange(0, self.x['d'].shape[0]) imin, imax = np.searchsorted(ax, (xmin, xmax)) imax = min(len(ax) - 1, imax) seg = ax[[imin, imax]] # self.axes1.scatter(xmin, self.y[imin], s=30, marker='^', # color='red', label='x1 samples') # self.axes1.scatter(xmax, self.y[imax], s=30, marker='v', # color='red', label='x1 samples') self.axes1.fill_between(range(imin, imax), self.oxy[1][0], self.oxy[1][1], facecolor='yellow', alpha=0.5) self.redraw1() self.SComboBox1.setText(str(imin)) self.SComboBox2.setText(str(imax)) def span_select_callback2(self, xmin, xmax): ax = np.arange(0, self.x['d'].shape[0]) imin, imax = np.searchsorted(ax, (xmin, xmax)) imax = min(len(ax) - 1, imax) seg = ax[[imin, imax]] # self.axes1.scatter(xmin, self.y[imin], s=30, marker='^', # color='red', label='x1 samples') # self.axes1.scatter(xmax, self.y[imax], s=30, marker='v', # color='red', label='x1 samples') self.axes1.fill_between(range(imin, imax), self.oxy[1][0], self.oxy[1][1], facecolor='Green', alpha=0.5) self.redraw1() self.OComboBox1.setText(str(imin)) self.OComboBox2.setText(str(imax)) def span_select_callback3(self, xmin, xmax): ax = np.arange(0, self.x['d'].shape[0]) imin, imax = np.searchsorted(ax, (xmin, xmax)) imax = min(len(ax) - 1, imax) seg = ax[[imin, imax]] self.axes1.fill_between(range(imin, imax), self.oxy[1][0], self.oxy[1][1], facecolor='Green', alpha=0.5) self.redraw1() self.OComboBox3.setText(str(imin)) self.OComboBox4.setText(str(imax)) def add_data(self, x, pc): self.x = x self.pc = pc self.new_x = x['d'] self.axes1.plot(x['d']) self.axes1.set_title("raw data", fontsize=9) self.axes1.set_xlabel("Scans") self.axes1.tick_params(axis='both', labelsize=8) self.LComboBox.setRange(1, self.pc) ymino, ymaxo = self.axes1.get_ylim() xmino, xmaxo = self.axes1.get_xlim() self.oxy = [(xmino, xmaxo), (ymino, ymaxo)] self.redraw1() def eta(self): self.layel = self.LComboBox.value() if self.layel < self.pc: if self.mthcombox.currentText() == "ETA": w = self.DComboBox.value() self.l, self.em = FSWFA(self.new_x, w, self.pc) self.axes1.clear() self.axes1.plot(self.l, self.em, '-o') self.axes1.set_title("ETA", fontsize=9) self.axes1.set_xlabel("Scans") self.axes1.tick_params(axis='both', labelsize=8) self.redraw1() else: u, T = svdX(self.new_x) self.axes1.clear() self.axes1.plot(u[:, 0], u[:, 1], '-o') C = np.arange(0, u.shape[0]) for a, b, c in zip(u[:, 0], u[:, 1], C): self.axes1.text(a, b + 0.001, '%.0f' % c, ha='center', va='bottom', fontsize=7) self.axes1.set_xlabel("p1") self.axes1.set_ylabel("p2") self.axes1.set_title("LPG", fontsize=9) self.redraw1() ymino, ymaxo = self.axes1.get_ylim() xmino, xmaxo = self.axes1.get_xlim() self.oxy = [(xmino, xmaxo), (ymino, ymaxo)] else: msgBox = QMessageBox() msgBox.setText("All component finished") msgBox.exec_() def fr(self): s1 = self.SComboBox1.text() s2 = self.SComboBox2.text() z1 = self.OComboBox1.text() z2 = self.OComboBox2.text() z3 = self.OComboBox3.text() z4 = self.OComboBox4.text() s = list() z = list() if (s1 and s2): s.append(range(int(s1), int(s2))) if (z1 and z2): z.append(range(int(z1), int(z2))) if (z3 and z4): z.append(range(int(z3), int(z4))) if len(s[0]) == 0 or len(z[0]) == 0: msgBox = QMessageBox() msgBox.setText( "Please input selective region or zero-concentration region") msgBox.exec_() if len(s) and len(z): DATAF = open('HELP_m.pkl', 'w') X = {'x': self.new_x, 'so': s[0], 'z': z[0]} pickle.dump(X, DATAF) DATAF.close() c, new_x = FR(self.new_x, s[0], z[0], self.pc - self.LComboBox.value() + 1) # plt.plot(c) # plt.show() # plt.plot(new_x) # plt.show() helpre = {'new_x': self.new_x, 'l': self.l, 'em': self.em, 'c': c} if len(self.help_result) == self.layel: self.help_result.pop(self.layel) self.help_result.append(helpre) self.new_x = new_x self.LComboBox.setValue(self.LComboBox.value() + 1) self.SComboBox1.setText(str()) self.SComboBox2.setText(str()) self.OComboBox1.setText(str()) self.OComboBox2.setText(str()) self.OComboBox3.setText(str()) self.OComboBox4.setText(str()) self.axes2.plot(c / np.linalg.norm(c)) self.redraw2() self.axes1.clear() self.axes1.set_xlabel("scan") self.axes1.plot(self.new_x) self.axes1.set_title("after stripping", fontsize=9) self.axes1.set_xlabel("Scans") self.redraw1() ymino, ymaxo = self.axes1.get_ylim() xmino, xmaxo = self.axes1.get_xlim() self.oxy = [(xmino, xmaxo), (ymino, ymaxo)] if self.layel == self.pc - 1: #cc = np.sum(self.new_x, 1) indd = np.argmax(np.sum(self.new_x, 0)) cc = self.new_x[:, indd] ind = np.argmax(cc) for i, indd in enumerate(np.arange(ind, 0, -1)): if cc[indd - 1] >= cc[indd] and cc[indd - 1] <= 0.5 * np.max(cc): cc[0:indd] = 0 break if cc[indd - 1] < 0: cc[0:indd] = 0 break for i, indd in enumerate(np.arange(ind, len(cc) - 1, 1)): if cc[indd + 1] >= cc[indd] and cc[indd + 1] <= 0.5 * np.max(cc): cc[indd + 1:len(cc)] = 0 break if cc[indd + 1] < 0: cc[indd + 1:len(cc)] = 0 break helpre = { 'new_x': [], 'l': [], 'em': [], 'c': cc / np.linalg.norm(cc) } self.help_result.append(helpre) self.axes2.plot(cc / np.linalg.norm(cc)) self.redraw2() return self.layel = self.layel + 1 w = self.DComboBox.value() self.l, self.em = FSWFA(self.new_x, w, self.pc - self.LComboBox.value() + 1) def undo(self): self.axes1.clear() self.axes1.set_xlabel("scan") self.axes2.clear() self.axes2.set_xlabel("scan") self.LComboBox.setValue(1) self.help_result = [] self.rt = [] self.ms = [] self.new_x = self.x['d'] self.axes1.plot(self.new_x) self.axes1.set_title("raw data", fontsize=9) self.axes1.set_xlabel("Scans") self.axes1.tick_params(axis='both', labelsize=8) self.redraw2() self.redraw1() def getmsrt(self): if len(self.help_result) == self.pc: C = np.zeros((self.x['d'].shape[0], self.pc)) for i, v in enumerate(self.help_result): C[:, i] = self.help_result[i]['c'] S = np.zeros((self.pc, self.x['d'].shape[1])) for j in range(0, S.shape[1]): a = fnnls(np.dot(C.T, C), np.dot(C.T, self.x['d'][:, j]), tole='None') S[:, j] = a['xx'] rts = self.x['rt'][np.sort(np.argmax(C, axis=0))] index = np.argsort(np.argmax(C, axis=0)) for ind, val in enumerate(index): self.rt.append(rts[ind]) ss = S[val, :] self.ms.append(ss / norm(ss)) else: msgBox = QMessageBox() msgBox.setText("Please resolve all components") msgBox.exec_() def get_resu(self): self.getmsrt() if len(self.rt): RESU = { "methods": "H", "ms": self.ms, 'rt': self.rt, 'mz': self.x['mz'], 'pc': self.pc, 'R2': 'none' } else: RESU = {} return RESU
class TrackChart(wx.Panel): def __init__(self, parent, main_window): wx.Panel.__init__(self, parent, size=(100, 100)) self.main_window = main_window self.main_box = wx.StaticBox(self, label='Spotfinding Chart') self.main_fig_sizer = wx.StaticBoxSizer(self.main_box, wx.VERTICAL) self.SetSizer(self.main_fig_sizer) self.track_figure = Figure() self.track_axes = self.track_figure.add_subplot(111) self.track_axes.set_ylabel('Found Spots') self.track_axes.set_xlabel('Frame') self.track_figure.set_tight_layout(True) self.track_canvas = FigureCanvas(self, -1, self.track_figure) self.track_axes.patch.set_visible(False) self.plot_sb = wx.Slider(self, minValue=0, maxValue=1) self.plot_sb.Hide() self.main_fig_sizer.Add(self.track_canvas, 1, wx.EXPAND) self.main_fig_sizer.Add(self.plot_sb, flag=wx.EXPAND) # Scroll bar binding self.Bind(wx.EVT_SCROLL, self.onScroll, self.plot_sb) # Plot bindings self.track_figure.canvas.mpl_connect('button_press_event', self.onPress) self.reset_chart() def onSelect(self, xmin, xmax): """ Called when SpanSelector is used (i.e. click-drag-release); passes on the boundaries of the span to tracker window for selection and display of the selected images """ if self.selector == 'select': self.select_span.set_visible(True) self.patch_x = int(xmin) self.patch_x_last = int(xmax) + 1 self.patch_width = self.patch_x_last - self.patch_x self.bracket_set = True self.main_window.update_image_list() gp = self.main_window.tracker_panel.graph_panel ip = self.main_window.tracker_panel.image_list_panel sp = self.main_window.tracker_panel.chart_sash_position if sp == 0: sp = int(self.main_window.GetSize()[0] * 0.70) self.main_window.tracker_panel.chart_splitter.SplitVertically( gp, ip, sp) self.main_window.tracker_panel.Layout() elif self.selector == 'zoom': if (int(xmax) - int(xmin) >= 5): self.x_min = int(xmin) self.x_max = int(xmax) self.plot_zoom = True self.max_lock = False self.chart_range = int(self.x_max - self.x_min) self.main_window.tracker_panel.chart_window.toggle.SetValue( True) self.main_window.tracker_panel.chart_window.toggle_boxes( flag_on=True) self.main_window.tracker_panel.chart_window.ctr.SetValue( self.chart_range) sb_center = self.x_min + self.chart_range / 2 self.plot_sb.SetValue(sb_center) self.plot_sb.Show() self.draw_plot() if self.bracket_set: self.bracket_set = False self.main_window.tracker_panel.chart_sash_position = \ self.main_window.tracker_panel.chart_splitter.GetSashPosition() self.main_window.tracker_panel.chart_splitter.Unsplit() self.main_window.tracker_panel.Layout() def onScroll(self, e): sb_center = self.plot_sb.GetValue() half_span = (self.x_max - self.x_min) / 2 if sb_center - half_span == 0: self.x_min = 0 self.x_max = half_span * 2 else: self.x_min = sb_center - half_span self.x_max = sb_center + half_span if self.plot_sb.GetValue() == self.plot_sb.GetMax(): self.max_lock = True else: self.max_lock = False self.draw_plot() def onPress(self, e): """ If left mouse button is pressed, activates the SpanSelector; otherwise, makes the span invisible and sets the toggle that clears the image list; if shift key is held, does this for the Selection Span, otherwise does this for the Zoom Span """ if e.button != 1: self.zoom_span.set_visible(False) self.select_span.set_visible(False) self.bracket_set = False self.plot_zoom = False self.plot_sb.Hide() self.draw_plot() # Hide list of images self.main_window.tracker_panel.chart_sash_position = \ self.main_window.tracker_panel.chart_splitter.GetSashPosition() self.main_window.tracker_panel.chart_splitter.Unsplit() self.main_window.tracker_panel.chart_window.toggle.SetValue(False) self.main_window.tracker_panel.chart_window.toggle_boxes( flag_on=False) self.main_window.tracker_panel.Layout() else: if self.main_window.tb_btn_view.IsToggled(): self.selector = 'select' self.zoom_span.set_visible(False) self.select_span.set_visible(True) elif self.main_window.tb_btn_zoom.IsToggled(): self.selector = 'zoom' self.zoom_span.set_visible(True) self.select_span.set_visible(False) def reset_chart(self): self.track_axes.clear() self.track_figure.patch.set_visible(False) self.track_axes.patch.set_visible(False) self.xdata = [] self.ydata = [] self.idata = [] self.x_min = 0 self.x_max = 1 self.y_max = 1 self.bracket_set = False self.button_hold = False self.plot_zoom = False self.chart_range = None self.selector = None self.max_lock = True self.patch_x = 0 self.patch_x_last = 1 self.patch_width = 1 self.start_edge = 0 self.end_edge = 1 self.acc_plot = self.track_axes.plot([], [], 'o', color='#4575b4')[0] self.rej_plot = self.track_axes.plot([], [], 'o', color='#d73027')[0] self.idx_plot = self.track_axes.plot([], [], 'wo', ms=2)[0] self.bragg_line = self.track_axes.axhline(0, c='#4575b4', ls=':', alpha=0) self.highlight = self.track_axes.axvspan(0.5, 0.5, ls='--', alpha=0, fc='#deebf7', ec='#2171b5') self.track_axes.set_autoscaley_on(True) self.select_span = SpanSelector(ax=self.track_axes, onselect=self.onSelect, direction='horizontal', rectprops=dict(alpha=0.5, ls=':', fc='#deebf7', ec='#2171b5')) self.select_span.set_active(False) self.zoom_span = SpanSelector(ax=self.track_axes, onselect=self.onSelect, direction='horizontal', rectprops=dict(alpha=0.5, ls=':', fc='#ffffd4', ec='#8c2d04')) self.zoom_span.set_active(False) def draw_bragg_line(self): min_bragg = self.main_window.tracker_panel.min_bragg.ctr.GetValue() if min_bragg > 0: self.bragg_line.set_alpha(1) else: self.bragg_line.set_alpha(0) self.bragg_line.set_ydata(min_bragg) try: self.draw_plot() except AttributeError: pass def draw_plot(self, new_x=None, new_y=None, new_i=None, new_p=None): min_bragg = self.main_window.tracker_panel.min_bragg.ctr.GetValue() if new_x is None: new_x = [] if new_y is None: new_y = [] if new_i is None: new_i = [] nref_x = np.append(self.xdata, np.array(new_x).astype(np.double)) nref_y = np.append(self.ydata, np.array(new_y).astype(np.double)) nref_i = np.append(self.idata, np.array(new_i).astype(np.double)) self.xdata = nref_x self.ydata = nref_y self.idata = nref_i nref_xy = list(zip(nref_x, nref_y)) all_acc = [i[0] for i in nref_xy if i[1] >= min_bragg] all_rej = [i[0] for i in nref_xy if i[1] < min_bragg] if nref_x != [] and nref_y != []: if self.plot_zoom: if self.max_lock: self.x_max = np.max(nref_x) self.x_min = self.x_max - self.chart_range else: self.x_min = -1 self.x_max = np.max(nref_x) + 1 if min_bragg > np.max(nref_y): self.y_max = min_bragg + int(0.1 * min_bragg) else: self.y_max = np.max(nref_y) + int(0.1 * np.max(nref_y)) self.track_axes.set_xlim(self.x_min, self.x_max) self.track_axes.set_ylim(0, self.y_max) else: self.x_min = -1 self.x_max = 1 acc = [int(i) for i in all_acc if self.x_min < i < self.x_max] rej = [int(i) for i in all_rej if self.x_min < i < self.x_max] self.acc_plot.set_xdata(nref_x) self.rej_plot.set_xdata(nref_x) self.idx_plot.set_xdata(nref_x) self.acc_plot.set_ydata(nref_y) self.rej_plot.set_ydata(nref_y) self.idx_plot.set_ydata(nref_i) self.acc_plot.set_markevery(acc) self.rej_plot.set_markevery(rej) self.Layout() count = '{}'.format(len([i for i in nref_xy if i[1] >= min_bragg])) idx_count = '{}'.format(len(nref_i[~np.isnan(nref_i)])) self.main_window.tracker_panel.count_txt.SetLabel(count) self.main_window.tracker_panel.idx_count_txt.SetLabel(idx_count) self.main_window.tracker_panel.info_sizer.Layout() # Set up scroll bar if len(self.xdata) > 0: self.plot_sb.SetMax(np.max(nref_x)) if self.max_lock: self.plot_sb.SetValue(self.plot_sb.GetMax()) # Draw extended plots self.track_axes.draw_artist(self.acc_plot) self.track_axes.draw_artist(self.rej_plot) # If any new folders are found, place marker at switch if new_p is not None: for p in new_p: self.track_axes.axvline(p[0], ymin=-15, c='red', ls='--') label = os.path.basename(p[1]) self.track_axes.annotate(label, xy=(p[0], 1), ha='left', va='top', xycoords=('data', 'figure fraction'))
class TrackChart(wx.Panel): def __init__(self, parent, main_window): wx.Panel.__init__(self, parent, size=(100, 100)) self.main_window = main_window self.main_box = wx.StaticBox(self, label='Spotfinding Chart') self.main_fig_sizer = wx.StaticBoxSizer(self.main_box, wx.VERTICAL) self.SetSizer(self.main_fig_sizer) self.track_figure = Figure() self.track_axes = self.track_figure.add_subplot(111) self.track_axes.set_ylabel('Found Spots') self.track_axes.set_xlabel('Frame') self.track_figure.set_tight_layout(True) self.track_canvas = FigureCanvas(self, -1, self.track_figure) self.track_axes.patch.set_visible(False) self.plot_sb = wx.Slider(self, minValue=0, maxValue=1) self.plot_sb.Hide() self.main_fig_sizer.Add(self.track_canvas, 1, wx.EXPAND) self.main_fig_sizer.Add(self.plot_sb, flag=wx.EXPAND) # Scroll bar binding self.Bind(wx.EVT_SCROLL, self.onScroll, self.plot_sb) # Plot bindings self.track_figure.canvas.mpl_connect('button_press_event', self.onPress) # self.track_figure.canvas.mpl_connect('scroll_event', self.onScroll) self.reset_chart() def onSelect(self, xmin, xmax): ''' Called when SpanSelector is used (i.e. click-drag-release); passes on the boundaries of the span to tracker window for selection and display of the selected images ''' if self.selector == 'select': self.select_span.set_visible(True) self.patch_x = int(xmin) self.patch_x_last = int(xmax) + 1 self.patch_width = self.patch_x_last - self.patch_x self.bracket_set = True self.main_window.update_image_list() gp = self.main_window.tracker_panel.graph_panel ip = self.main_window.tracker_panel.image_list_panel sp = self.main_window.tracker_panel.chart_sash_position if sp == 0: sp = int(self.main_window.GetSize()[0] * 0.75) self.main_window.tracker_panel.chart_splitter.SplitVertically( gp, ip, sp) self.main_window.tracker_panel.Layout() elif self.selector == 'zoom': if (int(xmax) - int(xmin) >= 5): self.x_min = int(xmin) self.x_max = int(xmax) self.plot_zoom = True self.max_lock = False self.chart_range = int(self.x_max - self.x_min) self.main_window.tracker_panel.chart_window.toggle.SetValue( True) self.main_window.tracker_panel.chart_window.toggle_boxes( flag_on=True) self.main_window.tracker_panel.chart_window.ctr.SetValue( self.chart_range) sb_center = self.x_min + self.chart_range / 2 self.plot_sb.SetValue(sb_center) self.plot_sb.Show() self.draw_plot() if self.bracket_set: self.bracket_set = False self.main_window.tracker_panel.chart_sash_position = \ self.main_window.tracker_panel.chart_splitter.GetSashPosition() self.main_window.tracker_panel.chart_splitter.Unsplit() self.main_window.tracker_panel.Layout() def onScroll(self, e): sb_center = self.plot_sb.GetValue() half_span = (self.x_max - self.x_min) / 2 if sb_center - half_span == 0: self.x_min = 0 self.x_max = half_span * 2 else: self.x_min = sb_center - half_span self.x_max = sb_center + half_span if self.plot_sb.GetValue() == self.plot_sb.GetMax(): self.max_lock = True else: self.max_lock = False self.draw_plot() def onPress(self, e): ''' If left mouse button is pressed, activates the SpanSelector; otherwise, makes the span invisible and sets the toggle that clears the image list; if shift key is held, does this for the Selection Span, otherwise does this for the Zoom Span ''' if e.button != 1: self.zoom_span.set_visible(False) self.select_span.set_visible(False) self.bracket_set = False self.plot_zoom = False self.plot_sb.Hide() self.draw_plot() # Hide list of images self.main_window.tracker_panel.chart_sash_position = \ self.main_window.tracker_panel.chart_splitter.GetSashPosition() self.main_window.tracker_panel.chart_splitter.Unsplit() self.main_window.tracker_panel.chart_window.toggle.SetValue(False) self.main_window.tracker_panel.chart_window.toggle_boxes( flag_on=False) self.main_window.tracker_panel.Layout() else: if self.main_window.tb_btn_view.IsToggled(): self.selector = 'select' self.zoom_span.set_visible(False) self.select_span.set_visible(True) elif self.main_window.tb_btn_zoom.IsToggled(): self.selector = 'zoom' self.zoom_span.set_visible(True) self.select_span.set_visible(False) # Using Shift key to determine zoom or list; keeping code around for now # if e.key == 'shift': # self.selector = 'select' # self.zoom_span.set_visible(False) # self.select_span.set_visible(True) # else: # self.selector = 'zoom' # self.zoom_span.set_visible(True) # self.select_span.set_visible(False) def reset_chart(self): self.track_axes.clear() self.track_figure.patch.set_visible(False) self.track_axes.patch.set_visible(False) self.xdata = [] self.ydata = [] self.x_min = 0 self.x_max = 1 self.y_max = 1 self.bracket_set = False self.button_hold = False self.plot_zoom = False self.chart_range = None self.selector = None self.max_lock = True self.patch_x = 0 self.patch_x_last = 1 self.patch_width = 1 self.start_edge = 0 self.end_edge = 1 self.acc_plot = self.track_axes.plot([], [], 'o', color='#4575b4')[0] self.rej_plot = self.track_axes.plot([], [], 'o', color='#d73027')[0] self.bragg_line = self.track_axes.axhline(0, c='#4575b4', ls=':', alpha=0) self.highlight = self.track_axes.axvspan(0.5, 0.5, ls='--', alpha=0, fc='#deebf7', ec='#2171b5') self.track_axes.set_autoscaley_on(True) self.select_span = SpanSelector(ax=self.track_axes, onselect=self.onSelect, direction='horizontal', rectprops=dict(alpha=0.5, ls=':', fc='#deebf7', ec='#2171b5')) self.select_span.set_active(False) self.zoom_span = SpanSelector(ax=self.track_axes, onselect=self.onSelect, direction='horizontal', rectprops=dict(alpha=0.5, ls=':', fc='#ffffd4', ec='#8c2d04')) self.zoom_span.set_active(False) def draw_bragg_line(self): min_bragg = self.main_window.tracker_panel.min_bragg.ctr.GetValue() if min_bragg > 0: self.bragg_line.set_alpha(1) else: self.bragg_line.set_alpha(0) self.bragg_line.set_ydata(min_bragg) try: self.draw_plot() except AttributeError, e: pass
class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self): # Initiate window in class 'QMainWindow' super().__init__() # Configure window layout in Ui_MainWindow self.setupUi(self) # Initiate figure, canvas and axes self.fig = Figure(figsize=(100, 100)) self.canvas = FigureCanvas(self.fig) self.ax = self.fig.subplots() # Define axes lines self.ax.axhline(linewidth=1, linestyle="dashdot", color="#6E6E6E") self.ax.axvline(linewidth=1, linestyle="dashdot", color="#6E6E6E") # Set plot title self.ax.set_title("Simple plot tool built with Python") # Local dictionary rectprops = dict(facecolor='gray', alpha=0.5) # Connect event with string *button_press_event* to *on_mouse_press* function # https://matplotlib.org/api/backend_bases_api.html?highlight=mpl_connect#matplotlib.backend_bases.FigureCanvasBase.mpl_connect self.canvas.mpl_connect('button_press_event', self.on_mouse_press) self.canvas.mpl_connect('motion_notify_event', self.on_move_mouse) # Create 'RectangleSelector' object to be activated when press on Zoom Rect Buttom # REMARK: This functions creates a set of polylines in the axes # https://matplotlib.org/api/widgets_api.html?highlight=rectangleselector#matplotlib.widgets.RectangleSelector # https://matplotlib.org/gallery/widgets/rectangle_selector.html?highlight=rectangleselector self.RS = RectangleSelector(self.ax, self.on_select_zoom_box, useblit=True, rectprops=rectprops) self.RS.set_active(False) # deactivate the selector # Create 'SpanSelector' object in vertical and horizontal directions, to be activated with zoom vert and hor # https://matplotlib.org/api/widgets_api.html?highlight=spanselector#matplotlib.widgets.SpanSelector # https://matplotlib.org/gallery/widgets/span_selector.html?highlight=spanselector self.SSv = SpanSelector(self.ax, self.on_vert_zoom, 'vertical', useblit=True, rectprops=rectprops) self.SSh = SpanSelector(self.ax, self.on_hor_zoom, 'horizontal', useblit=True, rectprops=rectprops) self.SSv.set_active(False) self.SSh.set_active(False) # Create 'Multicursor' object in vertical and horizontal directions # https://matplotlib.org/api/widgets_api.html#matplotlib.widgets.MultiCursor # https://matplotlib.org/gallery/widgets/multicursor.html?highlight=multicursor self.MC = MultiCursor(self.canvas, (self.ax, ), useblit=True, horizOn=True, vertOn=True, linewidth=1, color="#C8C8C8") self.MC.set_active(True) # Add Figure Canvas to PyQt Widget # REMARK: It is HERE where the matplotlib canvas is conected to PyQt layout (lacking of official documentation) # https://www.riverbankcomputing.com/static/Docs/PyQt5/api/qtwidgets/qboxlayout.html?highlight=addwidget self.verticalLayout.addWidget(self.canvas) # Add a empty line to end of axis's line list (RectangleSelector already created some) self.ax.plot([], []) self.lines = 1 # Number of real plot lines # Set axis labels self.ax.set_xlabel("x axis") self.ax.set_ylabel("y axis") # Initiate first current path self.path = [] # Plot current equation (method already conected to signal 'returnPressed' of 'lineEditEq', defined bellow) self.on_lineEditEq_returnPressed() # Configure home axes limits (method already conected to signal 'clicked' of 'pushButtonHome', defined bellow) self.on_pushButtonHome_clicked() self.pushButtonPlayMovie.setText("Play Movie \n in last plot\n(►)") self.running = False def on_move_mouse(self, event): # Clears terminal # clc() if event.inaxes: # Print coordinates to mouse position print("\nPosition :==============") print("x = ", event.xdata, " | y = ", event.ydata) print("MultiCursor active? ", self.MC.active) else: # If the mouse is not over an axes print("Clicked out of axes") # Function to be called when clicking on canvas def on_mouse_press(self, event: matplotlib.backend_bases.MouseEvent): """ Function that is called when click with mouse on FIGURE CANVAS (not only inside axes) This Functions only prints information on the terminal Arguments: event {matplotlib.backend_bases.MouseEvent} -- For the location events (button and key press/release), if the mouse is over the axes, the inaxes attribute of the event will be set to the Axes the event occurs is over, and additionally, the variables xdata and ydata attributes will be set to the mouse location in data coordinates. See KeyEvent and MouseEvent for more info. https://matplotlib.org/api/backend_bases_api.html?highlight=mpl_connect#matplotlib.backend_bases.KeyEvent https://matplotlib.org/api/backend_bases_api.html?highlight=mpl_connect#matplotlib.backend_bases.MouseEvent """ # Clears terminal clc() # If the mouse is over an axes if event.inaxes: # Print polylines ploted in axes print("Polylines objects: =================") i = 0 for line in event.inaxes.lines: print("line [", i, "]: ", line) i += 1 # Print coordinates to mouse position print("\nPosition :==============") print("x = ", event.xdata, " | y = ", event.ydata) self.canvas.draw() else: # If the mouse is not over an axes print("Clicked out of axes") # Function to be called by 'RectangleSelector' object def on_select_zoom_box(self, eclick: matplotlib.backend_bases.MouseEvent, erelease: matplotlib.backend_bases.MouseEvent): """Function that is called by "RectangleSelector" object from "matplotlib.widgets" Arguments: eclick {matplotlib.backend_bases.MouseEvent} -- matplotlib event at press mouse button erelease {matplotlib.backend_bases.MouseEvent} -- matplotlib event at release mouse button https://matplotlib.org/api/backend_bases_api.html?highlight=matplotlib%20backend_bases%20mouseevent#matplotlib.backend_bases.MouseEvent """ self.MC.set_active( True ) # Está em primeiro porque reseta os limites do eixo. Se estivesse depois, as linhas abaixo seriam sobrepostas self.ax.set_xlim(eclick.xdata, erelease.xdata) self.ax.set_ylim(eclick.ydata, erelease.ydata) self.get_limits() self.canvas.draw() print("") self.RS.set_active(False) # Functions to be called when "zoom" vertical and horizontal directions def on_vert_zoom(self, vmin: float, vmax: float): """Function to zoom only in vertical direction that is called by de SpanSelector object with direction="vertical" Arguments: vmin {float} -- min range value vmax {float} -- max range value """ self.MC.set_active(True) self.ax.set_ylim(vmin, vmax) self.get_limits() self.SSv.set_active(False) def on_hor_zoom(self, hmin: float, hmax: float): """Function to zoom only in horizontal direction that is called by de SpanSelector object with direction="horizontal" Arguments: hmin {float} -- min range value hmax {float} -- max range value """ self.MC.set_active(True) self.ax.set_xlim(hmin, hmax) self.get_limits() self.SSh.set_active(False) # Get values from lineEdits and set axes limits to they def set_limits(self): """Function to get values from 'lineEdits' boxes and set limits of axes""" # Get values from edit boxes xinf = float(self.lineEditXinf.text()) xsup = float(self.lineEditXsup.text()) yinf = float(self.lineEditYinf.text()) ysup = float(self.lineEditYsup.text()) # Set axes limits self.ax.set_xlim(xinf, xsup) self.ax.set_ylim(yinf, ysup) # Redraw figure canvas self.canvas.draw() self.get_limits() # Get axes limits and put on lineEdits def get_limits(self): """Function to get the actual limits of axes and put it on 'lineEdits' """ self.lineEditXinf.setText("{:0.2f}".format(self.ax.get_xlim()[0])) self.lineEditXsup.setText("{:0.2f}".format(self.ax.get_xlim()[1])) self.lineEditYinf.setText("{:0.2f}".format(self.ax.get_ylim()[0])) self.lineEditYsup.setText("{:0.2f}".format(self.ax.get_ylim()[1])) @QtCore.pyqtSlot() def on_lineEditEq_returnPressed(self): # Get data from edit boxes start = float(self.lineEditStart.text()) stop = float(self.lineEditStop.text()) num = int(self.lineEditNum.text()) # Calculate data to plot the curve x = linspace(start, stop, num) try: y = eval(self.lineEditEq.text()) except: return None # Set new data to the curve self.ax.lines[-1].set_data(x, y) # Update x and y path = self.ax.lines[-1].get_path() x = path.vertices[:, 0] y = path.vertices[:, 1] # Color new line if all(x == x[0]) or all(y == y[0]): self.ax.lines[-1].set_color("#969696") self.ax.lines[-1].set_linestyle("dashdot") else: self.ax.lines[-1].set_color("#000000") self.ax.lines[-1].set_linestyle("solid") # Get the last line path self.path = self.ax.lines[-1].get_path() # Redraw figure canvas self.canvas.draw() @QtCore.pyqtSlot() def on_lineEditStart_returnPressed(self): self.on_lineEditEq_returnPressed() @QtCore.pyqtSlot() def on_lineEditStop_returnPressed(self): self.on_lineEditEq_returnPressed() @QtCore.pyqtSlot() def on_lineEditNum_returnPressed(self): self.on_lineEditEq_returnPressed() @QtCore.pyqtSlot() def on_lineEditXinf_returnPressed(self): self.set_limits() @QtCore.pyqtSlot() def on_lineEditXsup_returnPressed(self): self.set_limits() @QtCore.pyqtSlot() def on_lineEditYinf_returnPressed(self): self.set_limits() @QtCore.pyqtSlot() def on_lineEditYsup_returnPressed(self): self.set_limits() @QtCore.pyqtSlot() def on_pushButtonHome_clicked(self): # Reset auto-scale self.ax.set_autoscale_on(True) # Recompute data limits self.ax.relim() # Automatic axis scaling self.ax.autoscale_view() # Redraw figure canvas self.canvas.draw() self.get_limits() @QtCore.pyqtSlot() def on_pushButtonAddPlot_clicked(self): # Add a new line-plot to lines list, if the last wasn't empty # or if there is no lines if self.lines <= 0 or len(self.ax.lines[-1].get_xdata()) > 0: self.ax.plot([], []) self.lines += 1 # Set focus on edit box of equation self.lineEditEq.setText("") self.lineEditEq.setFocus() @QtCore.pyqtSlot() def on_pushButtonDelPlot_clicked(self): if self.lines > 0: # Remove last line self.ax.lines.pop() # Redraw figure canvas self.canvas.draw() # Decrease number of curves self.lines -= 1 # Get the last line path self.path = self.ax.lines[-1].get_path() @QtCore.pyqtSlot() def on_pushButtonRect_clicked(self): self.MC.set_active(False) self.SSv.set_active(False) self.SSh.set_active(False) self.RS.set_active(True) self.canvas.draw() @QtCore.pyqtSlot() def on_pushButtonHor_clicked(self): self.MC.set_active(False) self.RS.set_active(False) self.SSv.set_active(False) self.SSh.set_active(True) self.canvas.draw() @QtCore.pyqtSlot() def on_pushButtonVert_clicked(self): self.MC.set_active(False) self.RS.set_active(False) self.SSh.set_active(False) self.SSv.set_active(True) self.canvas.draw() @QtCore.pyqtSlot() def on_lineEditDeltaT_editingFinished(self): self.update_Dt() @QtCore.pyqtSlot(str) def on_lineEditDeltaT_textChanged(self): self.update_Dt() @QtCore.pyqtSlot() def on_lineEditDeltaT_returnPressed(self): self.update_Dt() @QtCore.pyqtSlot() def on_pushButtonPlayMovie_clicked(self): if not self.running: self.running = True self.pushButtonPlayMovie.setText("Pause Movie \n( ▍▍)") xt = self.path.vertices[:, 0] yt = self.path.vertices[:, 1] if all(self.path.vertices[-1, :] == self.ax.lines[-1].get_path().vertices[-1, :]): self.ax.lines[-1].set_data([], []) temp_path = self.ax.lines[-1].get_path() x = temp_path.vertices[:, 0] y = temp_path.vertices[:, 1] start_loop = time() intervals = [] i = len(x) while self.running and i < len(self.path.vertices[:, 1]): i += 1 x = xt[0:i] y = yt[0:i] self.ax.lines[-1].set_data(x, y) sleep(1) self.canvas.start_event_loop( 1) #max([Dt-(time()-start_loop),1e-30])) # sleep(max([Dt-(time()-start_loop),1e-30])) # --> nao funciona # plt.pause(max([Dt-(time()-start_loop),1e-30])) # --> nao funciona intervals.append("Step " + str(i) + ": " + str(time() - start_loop)) print(intervals[-1]) start_loop = time() self.canvas.draw() self.running = False print(array(intervals)) self.pushButtonPlayMovie.setText("Play Movie \n in last plot\n(►)") else: self.running = False def update_Dt(self): global Dt try: Dt = max([float(self.lineEditDeltaT.text()), 1e-30]) except: Dt = 1.0 print("Δt = ", Dt)
class LSFQDialg(QWidget): def __init__(self): QWidget.__init__(self) self.handles = [] self.create_canvas() self.segments = [] vbox = QVBoxLayout() vbox.addWidget(self.canvas) self.setLayout(vbox) self.resize(800, 600) self.move(320, 75) self.setWindowTitle("Least Square Fitting (2D)") def create_canvas(self): self.fig = plt.figure() self.canvas = FigureCanvas(self.fig) self.axes = plt.subplot(111) self.axes.set_xlabel("Scans") self.axes.set_ylabel("Instensity") self.axes.set_title("Least Square Fitting(2D)", fontsize=9) self.axes.tick_params(axis='both', labelsize=8) plt.subplots_adjust(bottom=0.22, top=0.90, left=0.08, right=0.9) self.span = SpanSelector(self.axes, self.span_select_callback, 'horizontal', minspan=0.002, useblit=True, rectprops=dict(alpha=0.5, facecolor='red'), onmove_callback=None, button=[1]) axspan = plt.axes([0.09, 0.04, 0.08, 0.075]) axundo = plt.axes([0.2, 0.04, 0.08, 0.075]) axstar = plt.axes([0.31, 0.04, 0.08, 0.075]) self.btnspan = Button(axspan, 'span') self.btnundo = Button(axundo, 'undo') self.btnstar = Button(axstar, 'start') self.btnspan.on_clicked(self.span_mode) self.btnundo.on_clicked(self.undo_mode) self.btnstar.on_clicked(self.star_mode) self.span.set_active(True) self.redraw() ymino, ymaxo = self.axes.get_ylim() xmino, xmaxo = self.axes.get_xlim() self.oxy = [(xmino, xmaxo), (ymino, ymaxo)] def redraw(self): self.canvas.draw() self.update() def span_mode(self, event): self.span.connect_event('motion_notify_event', self.span.onmove) self.span.connect_event('button_press_event', self.span.press) self.span.connect_event('button_release_event', self.span.release) self.span.connect_event('draw_event', self.span.update_background) self.leftdblclick = False self.rightdblclick = False self.redraw() print "span" def undo_mode(self, event): self.span.disconnect_events() if len(self.segments) >= 1: del self.axes.collections[:] self.segments = self.segments[:-1] self.select_inter(self.segments) self.redraw() print "undo" def star_mode(self, event): if len(self.segments) == 0: msgBox = QMessageBox() msgBox.setText("No selected noise region") msgBox.exec_() else: fit, bas = self.backremv(self.segments) self.show_bas(bas) self.show_fit(fit) self.emit(SIGNAL('after_baseline'), fit) def show_bas(self, bas): self.axes.plot(np.sum(bas, axis=1), lw=2, c='k', alpha=.7, picker=5) def show_fit(self, fit): self.axes.plot(np.sum(fit, axis=1), lw=2, c='r', alpha=.7, picker=5) def show_org(self, x): self.axes.plot(np.sum(x, axis=0), lw=2, c='b', alpha=.7, picker=5) def span_select_callback(self, xmin, xmax): cc = np.arange(0, self.x.shape[0]) indmin, indmax = np.searchsorted(cc, (xmin, xmax)) indmax = min(len(self.x) - 1, indmax) self.segments.append((indmin, indmax)) self.axes.vlines(xmin, self.oxy[1][0], self.oxy[1][1], color='r', linestyles='--') self.axes.vlines(xmax, self.oxy[1][0], self.oxy[1][1], color='r', linestyles='--') self.redraw() def updata_data(self, x): self.xx = x self.axes.clear() self.axes.set_xlabel("Scans") self.axes.set_ylabel("Instensity") self.axes.set_title("Least Square Fitting(2D)", fontsize=9) self.x = x['d'] self.y = np.sum(self.x, axis=1) self.axes.plot(self.y, lw=1, c='b', alpha=.7, picker=5) diff_y = max(self.y) - min(self.y) self.axes.set_xlim(0, len(self.y)) self.axes.set_ylim(0, max(self.y) * 1.1) ymino, ymaxo = self.axes.get_ylim() xmino, xmaxo = self.axes.get_xlim() self.oxy = [(xmino, xmaxo), (ymino, ymaxo)] self.plotorg = True self.redraw() def select_inter(self, segments): for i in range(0, len(segments)): indmin, indmax = segments[i] self.axes.vlines(self.x[indmin], self.oxy[1][0], self.oxy[1][1], color='r', linestyles='--') self.axes.vlines(self.x[indmax], self.oxy[1][0], self.oxy[1][1], color='r', linestyles='--') def backremv(self, seg): mn = np.shape(self.x) bak2 = np.zeros(mn) for i in range(0, mn[1]): tiab = [] reg = [] for j in range(0, len(seg)): tt = range(seg[j][0], seg[j][1]) tiab.extend(self.x[tt, i]) reg.extend(np.arange(seg[j][0], seg[j][1])) rm = reg - np.mean(reg) tm = tiab - np.mean(tiab) b = np.dot(np.dot(float(1) / np.dot(rm.T, rm), rm.T), tm) s = np.mean(tiab) - np.dot(np.mean(reg), b) b_est = s + b * np.arange(mn[0]) bak2[:, i] = self.x[:, i] - b_est bak = self.x - bak2 self.yy = bak2 return bak2, bak def accept(self): self.xx['d'] = self.yy self.close()
class TICPlot(QWidget): def __init__(self): QWidget.__init__(self) self.handles = [] self.ncr = dict() self.fileno = 0 self.segments = [] self.create_canvas() def create_canvas(self): self.fig = plt.figure() self.canvas = FigureCanvas(self.fig) self.axes = plt.subplot(111) self.axes.set_xlabel("Retention Time") self.axes.set_ylabel("Instensity") self.axes.tick_params(axis='both', labelsize=8) plt.subplots_adjust(bottom=0.25, top=0.90, left=0.08, right=0.9) self.zoom = RectangleSelector(self.axes, self.rectangle_select_callback, drawtype='box', useblit=True, button=[1], minspanx=5, minspany=5, spancoords='pixels') self.span = SpanSelector(self.axes, self.span_select_callback, 'horizontal', minspan=0.002, useblit=True, rectprops=dict(alpha=0.5, facecolor='red'), onmove_callback=None, button=[1]) axbasic = plt.axes([0.59, 0.04, 0.08, 0.075]) axPan = plt.axes([0.7, 0.04, 0.08, 0.075]) axPick = plt.axes([0.81, 0.04, 0.08, 0.075]) self.btnBasic = Button(axbasic, 'Zoom') self.btnPan = Button(axPan, 'Span') self.btnPick = Button(axPick, 'Undo') axtic = plt.axes([0.92, 0.825, 0.06, 0.075]) axext = plt.axes([0.92, 0.725, 0.06, 0.075]) axres = plt.axes([0.92, 0.625, 0.06, 0.075]) self.TICbutton = Button(axtic, 'TIC') self.EXTbutton = Button(axext, 'EXT') self.RESbutton = Button(axres, 'RES') vbox = QVBoxLayout() vbox.addWidget(self.canvas) self.setLayout(vbox) self.btnBasic.on_clicked(self.zoom_mode) self.btnPan.on_clicked(self.span_mode) self.btnPick.on_clicked(self.undo_mode) self.TICbutton.on_clicked(self.slot_tic) self.EXTbutton.on_clicked(self.slot_ext) self.RESbutton.on_clicked(self.slot_res) self.zoom_mode(True) self.redraw() ymino, ymaxo = self.axes.get_ylim() xmino, xmaxo = self.axes.get_xlim() self.oxy = [(xmino, xmaxo), (ymino, ymaxo)] def slot_tic(self, event): self.add_tic(self.ncr, self.fileno) def slot_ext(self, event): self.emit(SIGNAL("ext_plot")) def slot_res(self, event): self.emit(SIGNAL("res_plot"), ) def add_tic(self, ncr, fn): if not len(self.segments): self.fn = fn self.ncr = ncr tic = self.ncr.tic() self.x = tic['rt'] self.y = tic['val'] self.axes.clear() self.axes.set_xlabel("Retention Time") self.axes.set_ylabel("Instensity") self.axes.set_title(str(fn), fontsize=9) self.axes.plot(self.x, self.y, lw=1, c='b', alpha=.7, picker=5) self.axes.set_xlim(min(self.x), max(self.x)) self.axes.set_ylim(min(self.y), max(self.y) * 1.1) ymino, ymaxo = self.axes.get_ylim() xmino, xmaxo = self.axes.get_xlim() self.oxy = [(xmino, xmaxo), (ymino, ymaxo)] self.redraw() # def add_ext(self): def clear_data(self): self.axes.clear() self.axes.set_xlabel("Retention Time") self.axes.set_ylabel("Instensity") self.redraw() def redraw(self): self.canvas.draw() self.update() def zoom_mode(self, event): self.zoom.set_active(True) self.span.set_active(False) self.cidPress = self.canvas.mpl_connect('button_press_event', self.mouse_press_callback) self.cidRelease = self.canvas.mpl_connect('button_release_event', self.mouse_release_callback) self.span.disconnect_events() self.leftdblclick = False self.rightdblclick = False self.redraw() print "zoom" def span_mode(self, event): self.zoom.set_active(False) self.span.set_active(True) self.span.connect_event('motion_notify_event', self.span.onmove) self.span.connect_event('button_press_event', self.span.press) self.span.connect_event('button_release_event', self.span.release) self.span.connect_event('draw_event', self.span.update_background) # self.span.connect_event('button_press_event', self.mouse_press_callback) self.rightdblclick = False self.leftdblclick = False self.rightdblclick = False self.redraw() print "span" def undo_mode(self, event): self.zoom.set_active(True) self.span.disconnect_events() self.cidPress = self.canvas.mpl_connect('button_press_event', self.mouse_press_callback) if len(self.segments) >= 1: self.emit(SIGNAL("delete_SELECT"), self.segments[-1]) del self.axes.collections[:] self.segments = self.segments[:-1] self.select_inter(self.segments) if self.ind_right_press != 0: self.axes.vlines(self.xdata, self.oxy[1][0], self.oxy[1][1], color='g', linestyles='-') self.redraw() print "undo" def mouse_press_callback(self, event): if (event.button == 1 and event.dblclick == True): self.leftdblclick = True if event.button == 3: self.xdata = event.xdata self.ind_right_press = np.searchsorted(self.x, event.xdata) del self.axes.collections[:] self.axes.vlines(event.xdata, self.oxy[1][0], self.oxy[1][1], color='g', linestyles='-') self.select_inter(self.segments) self.redraw() self.emit(SIGNAL("MASS_SELECT"), self.ncr, self.ind_right_press) def select_inter(self, segments): for i in range(0, len(segments)): indmin, indmax = segments[i] self.axes.vlines(self.x[indmin], self.oxy[1][0], self.oxy[1][1], color='r', linestyles='--') self.axes.vlines(self.x[indmax], self.oxy[1][0], self.oxy[1][1], color='r', linestyles='--') def mouse_release_callback(self, event): if (self.leftdblclick): self.leftdblclick = False self.axes.set_xlim(self.oxy[0]) self.axes.set_ylim(self.oxy[1]) self.redraw() if (self.rightdblclick): self.rightdblclick = False del self.axes.collections[:] self.redraw() def rectangle_select_callback(self, eclick, erelease): x1, y1 = eclick.xdata, eclick.ydata x2, y2 = erelease.xdata, erelease.ydata if eclick.button == 1 and erelease.button == 1: self.axes.set_xlim(min(x1, x2), max(x1, x2)) self.axes.set_ylim(min(y1, y2), max(y1, y2)) self.redraw() def span_select_callback(self, xmin, xmax): indmin, indmax = np.searchsorted(self.x, (xmin, xmax)) indmax = min(len(self.x) - 1, indmax) self.segments.append((indmin, indmax)) self.axes.vlines(xmin, self.oxy[1][0], self.oxy[1][1], color='r', linestyles='--') self.axes.vlines(xmax, self.oxy[1][0], self.oxy[1][1], color='r', linestyles='--') self.redraw() self.emit(SIGNAL("range_SELECT"), self.ncr, (indmin, indmax)) def loading(self): self.axes.clear() self.axes.set_xlabel("Retention Time") self.axes.set_ylabel("Instensity") self.redraw() self.zoom_mode(True) ymino, ymaxo = self.axes.get_ylim() xmino, xmaxo = self.axes.get_xlim() self.oxy = [(xmino, xmaxo), (ymino, ymaxo)]
class TrackChart(wx.Panel): def __init__(self, parent, main_window): wx.Panel.__init__(self, parent, size=(100, 100)) self.main_window = main_window self.parent = parent self.zoom_ctrl = self.parent.GetParent().chart_zoom self.main_box = wx.StaticBox(self, label="Spotfinding Chart") self.main_fig_sizer = wx.StaticBoxSizer(self.main_box, wx.VERTICAL) self.SetSizer(self.main_fig_sizer) self.track_figure = Figure() self.track_axes = self.track_figure.add_subplot(111) self.track_axes.set_ylabel("Found Spots") self.track_axes.set_xlabel("Frame") self.track_figure.set_tight_layout(True) self.track_canvas = FigureCanvas(self, -1, self.track_figure) self.track_axes.patch.set_visible(False) self.plot_sb = wx.ScrollBar(self) self.plot_sb.Hide() self.main_fig_sizer.Add(self.track_canvas, 1, wx.EXPAND) self.main_fig_sizer.Add(self.plot_sb, flag=wx.EXPAND) # Scroll bar binding self.Bind(wx.EVT_SCROLL, self.onScroll, self.plot_sb) # Zoom control binding self.Bind(EVT_ZOOM, self.onZoomControl) # Plot bindings self.track_figure.canvas.mpl_connect("button_press_event", self.onPress) # initialize chart self.reset_chart() def onSelect(self, xmin, xmax): """ Called when SpanSelector is used (i.e. click-drag-release) """ if int(xmax) - int(xmin) >= 5: self.x_min = int(xmin) self.x_max = int(xmax) self.plot_zoom = True self.max_lock = False self.chart_range = int(self.x_max - self.x_min) sb_center = self.x_min + self.chart_range / 2 self.plot_sb.SetScrollbar( position=sb_center, thumbSize=self.chart_range, range=np.max(self.xdata), pageSize=self.chart_range, ) self.plot_sb.Show() self.zoom_ctrl.set_control(max_lock=False, plot_zoom=True, chart_range=self.chart_range) self.draw_plot() def onZoomControl(self, e): zoom_dict = e.GetInfo() self.max_lock = zoom_dict["max_lock"] self.plot_zoom = zoom_dict["plot_zoom"] self.chart_range = zoom_dict["chart_range"] self.x_max += zoom_dict["move"] self.x_min += zoom_dict["move"] try: assert self.chart_range == int(self.x_max - self.x_min) except AssertionError: self.x_min = int(self.x_max - self.chart_range) if self.plot_zoom is False: self.plot_sb.Hide() else: self.plot_sb.Show() sb_center = self.x_min + self.chart_range / 2 range = np.max(self.xdata) if self.xdata.size else self.chart_range self.plot_sb.SetScrollbar( position=sb_center, thumbSize=self.chart_range, range=range, pageSize=self.chart_range, ) self.draw_plot() def onScroll(self, e): sb_center = self.plot_sb.GetThumbPosition() half_span = (self.x_max - self.x_min) / 2 if sb_center - half_span == 0: self.x_min = 0 self.x_max = half_span * 2 else: self.x_min = sb_center - half_span self.x_max = sb_center + half_span if (self.plot_sb.GetThumbPosition() >= self.plot_sb.GetRange() - self.plot_sb.GetThumbSize()): self.max_lock = True else: self.max_lock = False self.draw_plot() def onPress(self, e): """ If left mouse button is pressed, activates the SpanSelector; otherwise, makes the span invisible """ if e.button != 1: self.zoom_span.set_visible(False) self.bracket_set = False self.plot_zoom = False self.plot_sb.Hide() self.zoom_ctrl.set_control( max_lock=False, plot_zoom=False, ) self.draw_plot() else: self.zoom_span.set_visible(True) def reset_chart(self): self.track_axes.clear() self.track_figure.patch.set_visible(False) self.track_axes.patch.set_visible(False) self.xdata = np.array([]).astype(np.double) self.ydata = np.array([]).astype(np.double) self.idata = np.array([]).astype(np.double) self.rdata = [] self.x_min = 0 self.x_max = 1 self.y_max = 1 self.bracket_set = False self.button_hold = False self.plot_zoom = False self.chart_range = None self.selector = None self.max_lock = True self.patch_x = 0 self.patch_x_last = 1 self.patch_width = 1 self.start_edge = 0 self.end_edge = 1 self.acc_plot = self.track_axes.plot([], [], "o", color="#4575b4")[0] self.rej_plot = self.track_axes.plot([], [], "o", color="#d73027")[0] self.idx_plot = self.track_axes.plot([], [], "wo", ms=2)[0] self.bragg_line = self.track_axes.axhline(0, c="#4575b4", ls=":", alpha=0) self.highlight = self.track_axes.axvspan(0.5, 0.5, ls="--", alpha=0, fc="#deebf7", ec="#2171b5") self.track_axes.set_autoscaley_on(True) self.zoom_span = SpanSelector( ax=self.track_axes, onselect=self.onSelect, direction="horizontal", rectprops=dict(alpha=0.5, ls=":", fc="#ffffd4", ec="#8c2d04"), ) self.zoom_span.set_active(True) self._update_canvas(canvas=self.track_canvas) def draw_bragg_line(self): min_bragg = self.main_window.tracker_panel.min_bragg.ctr.GetValue() if min_bragg > 0: self.bragg_line.set_alpha(1) else: self.bragg_line.set_alpha(0) self.bragg_line.set_ydata(min_bragg) try: self.draw_plot() except AttributeError: pass def draw_plot(self, new_data=None, new_res=None, new_x=None, new_y=None, new_i=None): """ Draw plot from acquired data; called on every timer event or forced when the Bragg spot count cutoff line is moved, or when current run tab is clicked on :param new_data: a list of tuples containing (frame_idx, no_spots, hres) :param new_res: a list of resolutions (hres, deprecated) :param new_x: a list of x-values (frame_idx, deprecated) :param new_y: a list of y-values (no_spots, deprecated) :param new_i: a list of x-values for indexed frames """ # get Bragg spots count cutoff line from UI widget min_bragg = self.main_window.tracker_panel.min_bragg.ctr.GetValue() # append new data (if available) to data lists if new_data: new_x, new_y, new_i, new_res = list(zip(*new_data)) if new_x and new_y: new_x_arr = np.array(new_x).astype(np.double) nref_x = np.append(self.xdata, new_x_arr) self.xdata = nref_x new_y_arr = np.array(new_y).astype(np.double) nref_y = np.append(self.ydata, new_y_arr) self.ydata = nref_y else: nref_x = self.xdata nref_y = self.ydata if new_res: new_res_arr = np.array(new_res).astype(np.double) self.rdata = np.append(self.rdata, new_res_arr) if new_i: new_i_arr = np.array(new_i).astype(np.double) nref_i = np.append(self.idata, new_i_arr) self.idata = nref_i else: nref_i = self.idata nref_xy = list(zip(nref_x, nref_y)) # identify plotted data boundaries if nref_x != [] and nref_y != []: if self.plot_zoom: if self.max_lock: self.x_max = np.max(nref_x) self.x_min = self.x_max - self.chart_range else: if self.x_max >= np.max(nref_x): self.x_max = np.max(nref_x) self.max_lock = True else: self.max_lock = False if self.x_min <= 0: self.x_min = 0 else: self.x_min = 0 self.x_max = np.max(nref_x) + 1 if min_bragg > np.max(nref_y): self.y_max = min_bragg + int(0.1 * min_bragg) else: self.y_max = np.max(nref_y) + int(0.1 * np.max(nref_y)) self.track_axes.set_xlim(self.x_min, self.x_max) self.track_axes.set_ylim(0, self.y_max) else: self.x_min = -1 self.x_max = 1 # select results that are a) within the plotted boundaries and b) are above # (acc) or below (rej) the minimum found Bragg spots cutoff acc = [ i for i in nref_xy if (self.x_min < i[0] < self.x_max and i[1] >= min_bragg) ] rej = [ i for i in nref_xy if (self.x_min < i[0] < self.x_max and i[1] <= min_bragg) ] # exit if there's nothing to plot if not acc and not rej: return # split acc/rej lists into x and y lists acc_x = [int(i[0]) for i in acc] acc_y = [int(i[1]) for i in acc] rej_x = [int(i[0]) for i in rej] rej_y = [int(i[1]) for i in rej] # update plot data if acc_x: self.acc_plot.set_xdata(acc_x) self.acc_plot.set_ydata(acc_y) if rej_x: self.rej_plot.set_xdata(rej_x) self.rej_plot.set_ydata(rej_y) # plot indexed if new_i is not None: self.idx_plot.set_xdata(nref_x) self.idx_plot.set_ydata(nref_i) idx_count = "{}".format(len(nref_i[~np.isnan(nref_i)])) self.main_window.tracker_panel.idx_count_txt.SetLabel(idx_count) self.Layout() # update run stats # hit count count = "{}".format(len(acc)) self.main_window.tracker_panel.count_txt.SetLabel(count) self.main_window.tracker_panel.info_sizer.Layout() # indexed count idx_count = "{}".format(len(nref_i[~np.isnan(nref_i)])) self.main_window.tracker_panel.idx_count_txt.SetLabel(idx_count) # Median resolution median_res = np.median(self.rdata) res_label = "{:.2f} Å".format(median_res) self.main_window.tracker_panel.res_txt.SetLabel(res_label) # Draw extended plots self.track_axes.draw_artist(self.acc_plot) self.track_axes.draw_artist(self.rej_plot) # If zoomed update navigation tools if self.chart_range: # Adjust scrollbar rng = np.max(self.xdata) pos = rng if self.max_lock else self.plot_sb.GetThumbPosition() self.plot_sb.SetScrollbar( position=pos, thumbSize=self.chart_range, range=rng, pageSize=self.chart_range, ) # Update Zoom control self.zoom_ctrl.set_control(max_lock=self.max_lock, ) # Redraw canvas self._update_canvas(self.track_canvas) def _update_canvas(self, canvas, draw_idle=True): """ Update a canvas (passed as arg) :param canvas: A canvas to be updated via draw_idle """ # Draw_idle is useful for regular updating of the chart; straight-up draw # without flush_events() will have to be used when buttons are clicked to # avoid recursive calling of wxYield if draw_idle: canvas.draw_idle() try: canvas.flush_events() except (NotImplementedError, AssertionError): pass else: canvas.draw() canvas.Refresh()
class AudioTrace(QtCore.QObject): ax = None defaults = dict(ymax=1., maxn=100000) ymax = defaults['ymax'] maxn = defaults['maxn'] timeframe = None events = None envelope = None bads = None def __init__(self, main, debug=0, parent=None): QtCore.QObject.__init__(self, parent) self.main = main self.create_actions() # THE PLOT self.fig = plt.figure() params = { 'axes.labelsize': 22, 'font.size': 16, 'ytick.labelsize': 16, 'xtick.labelsize': 16 } plt.rcParams.update(params) self.canvas = Canvas(self.fig, parent=self) # self.canvas.setMaximumHeight(400) # self.toolbar = NavigationToolbar(self.canvas) self.main.main_layout.addWidget(self.canvas) self.label = QtGui.QLabel('') self.label_layout = QtGui.QHBoxLayout() self.label_layout.addStretch(0) self.label_layout.addWidget(self.label) self.label_layout.addStretch(0) self.main.main_layout.addLayout(self.label_layout) self.tfedit = TimeFrameEditor(self) def set_data(self, tdata, data, env): # init if self.ax is None: gs = gridspec.GridSpec(1, 1) gs.update(left=0.1, right=0.98, top=0.94, bottom=0.12, hspace=0.2, wspace=0.2) self.ax = self.fig.add_subplot(gs[0, 0]) self.trace_artist, = self.ax.plot(tdata, data, '-k', lw=1.5) self.envelope_artist, = self.ax.plot(tdata, env, '-', c='orangered', lw=1.5) self.ax.set_xlabel('Time [s]', labelpad=0, fontsize=14) # selector for timeframes self.span = SpanSelector(self.ax, self.onselect, 'horizontal', useblit=False, rectprops=dict(alpha=0.5, facecolor='red')) self.span.set_active(False) else: self.trace_artist.set_data(tdata, data) self.envelope_artist.set_data(tdata, env) # clean up if self.timeframe is not None: self.timeframe.remove() self.timeframe = None if self.events is not None: for e in self.events: e.remove() self.events = None if self.bads is not None: for b in self.bads: b.remove() self.bads = None # indicate timeframe if self.main.timeframes is not None: start, stop = self.main.timeframes[self.main.ti] self.timeframe = self.ax.axvspan(start, stop, facecolor='lightgray', zorder=-10) # indicate events if self.main.events is not None: self.events = list() eve = self.main.events events = eve[(eve >= tdata[0]) & (eve <= tdata[-1])] for e in events: self.events.append( self.ax.axvline(e, color='dodgerblue', zorder=10, lw=1.5)) # indicate bad ranges if len(self.tfedit.bad_ranges): self.bads = list() for a, b in self.tfedit.bad_ranges: self.bads.append( self.ax.axvspan(a, b, facecolor='lightgreen', zorder=-8, alpha=0.3)) self.ax.set_title('Timeframe: {:.3f} -- {:.3f} s'.format( tdata[0], tdata[-1]), fontsize=14) self.ax.set_ylim(-self.ymax, self.ymax) self.ax.set_xlim(tdata[0], tdata[-1]) self.fig.canvas.draw() def update(self, draw=False): data = self.main.data.get_data() env = self.main.data.env tdata = self.main.data.tdata if data.size > self.maxn: # print('interpolation !!') step = data.size / self.maxn data = data[::step] env = env[::step] tdata = tdata[::step] # tmax = 1.*data.size/self.main.data.audio.samplerate # tdata_new = np.linspace(0., tmax, self.maxn) # data = np.interp(tdata_new, tdata, data) # tdata = tdata_new self.set_data(tdata, data, env) if draw: self.fig.canvas.draw() def create_actions(self): # Change Y-scale self.actionIncrease = QtGui.QAction('Increase Y', self) self.actionIncrease.setShortcut(Qt.Qt.SHIFT + Qt.Qt.Key_Y) self.actionIncrease.triggered.connect(self.increaseY) self.main.addAction(self.actionIncrease) # Change Y-scale self.actionDecrease = QtGui.QAction('Decrease Y', self) self.actionDecrease.setShortcut(Qt.Qt.Key_Y) self.actionDecrease.triggered.connect(self.decreaseY) self.main.addAction(self.actionDecrease) def increaseY(self): # print('increase') self.ymax *= 2. self.ymax = min((self.ymax, 1.)) self.ax.set_ylim(-self.ymax, self.ymax) self.fig.canvas.draw() def decreaseY(self): # print('decrease') self.ymax /= 2. self.ax.set_ylim(-self.ymax, self.ymax) self.fig.canvas.draw() def onselect(self, xmin, xmax): self.tfedit.bad_ranges.append((xmin, xmax)) self.update(draw=True) self.spanselector_toggle() def spanselector_toggle(self): if self.span.active: self.span.set_active(False) self.label.setText('') else: self.span.set_active(True) self.label.setText('Select bad range!') def cutout(self, inx, out='./'): data = self.main.data.get_data() env = self.main.data.env tdata = self.main.data.tdata if data.size > self.maxn: step = data.size / self.maxn data = data[::step] env = env[::step] tdata = tdata[::step] fig = plt.figure(figsize=(18. / 2.54, 8. / 2.54)) params = { 'font.size': 16, 'axes.labelsize': 16, 'axes.linewidth': .4, 'ytick.labelsize': 14, 'xtick.labelsize': 14 } plt.rcParams.update(params) gs = gridspec.GridSpec(1, 1) gs.update(left=0.18, right=0.98, top=0.9, bottom=0.15, hspace=0.2, wspace=0.2) ax = fig.add_subplot(gs[0, 0]) ax.plot(tdata, data, '-k', lw=.5) ax.plot(tdata, env, '-', c='orangered', lw=.5) ax.set_xlabel('Time [s]', labelpad=0, fontsize=14) # indicate timeframe if self.main.timeframes is not None: start, stop = self.main.timeframes[self.main.ti] ax.axvspan(start, stop, facecolor='lightgray', zorder=-10) # indicate events if self.main.events is not None: self.events = list() eve = self.main.events events = eve[(eve >= tdata[0]) & (eve <= tdata[-1])] for e in events: self.events.append( ax.axvline(e, color='dodgerblue', zorder=10, lw=1.5)) # indicate bad ranges if len(self.tfedit.bad_ranges): self.bads = list() for a, b in self.tfedit.bad_ranges: self.bads.append( ax.axvspan(a, b, facecolor='lightgreen', zorder=-8, alpha=0.3)) ax.set_title('Timeframe: {:.3f} -- {:.3f} s'.format( tdata[0], tdata[-1]), fontsize=14) ax.set_ylim(-self.ymax, self.ymax) ax.set_xlim(tdata[0], tdata[-1]) fn = os.path.join(out, 'cutout_{:04d}_trace.png'.format(inx)) fig.savefig(fn, dpi=300) plt.close()
def gui_solution(pixels, flux, fig, ax, line_list=None): # map_dict = dict() # map_dict['wavelength'] = [] # map_dict['pixel'] = [] # line_widths = [] # for auto-solving lines # FOR TESTING: map_dict = { 'wavelength': [ 5460.7399999999998, 7245.1665999999996, 6717.0429999999997, 6678.2762000000002, 6598.9529000000002, 6532.8822 ], 'pixel': [ 1226.9646056472734, 349.38080535972756, 610.93127457855871, 630.09556101866531, 668.9871368080278, 701.444940640303 ] } line_widths = [1.5] # for auto-solving lines # Add a side menu for specifying the wavelength of the selected line panel = QtWidgets.QWidget() label = QtWidgets.QLabel("Enter wavelength [Å]:", panel) help_label = QtWidgets.QLabel( "Enter a wavelength value, zoom in, then select the region " "containing the emission line at the specified wavelength.", panel) help_label.setStyleSheet("font-style: italic;") textbox = QtWidgets.QLineEdit(parent=panel) panel.layout = QtWidgets.QGridLayout(panel) panel.layout.addWidget(label, 0, 0, 1, 1) panel.layout.addWidget(textbox, 0, 1, 1, 1) panel.layout.addWidget(help_label, 1, 0, 1, 2, Qt.AlignCenter) main_window = fig.canvas.manager.window dock = QtWidgets.QDockWidget("Enter wavelength:", main_window) main_window.addDockWidget(Qt.BottomDockWidgetArea, dock) dock.setWidget(panel) # ------------------------------------------------------- def on_select(xmin, xmax): wvln = textbox.text().strip() if wvln == '': textbox.setText( 'Error: please enter a wavelength value before selecting') return wave_val = float(wvln) # if line_list specified, find closest line from list: if line_list is not None: absdiff = np.abs(np.array(line_list) - wave_val) idx = absdiff.argmin() if absdiff[idx] > 1.: logger.error("Couldn't find precise line corresponding to " "input {:.3f}".format(wave_val)) return logger.info("Snapping input wavelength {:.3f} to line list " "value {:.3f}".format(wave_val, line_list[idx])) wave_val = line_list[idx] line_props = get_line_props(pixels, flux, xmin, xmax) draw_line_marker(line_props, wave_val, ax) fig.suptitle('') plt.draw() fig.canvas.draw() map_dict['wavelength'].append(wave_val) map_dict['pixel'].append(line_props['centroid']) line_widths.append(line_props['stddev']) # A 1D span selector to highlight a given line span = SpanSelector(ax, on_select, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='red')) span.set_active(False) def enable_span(): tb = fig.canvas.manager.toolbar if span.active: span.set_active(False) else: span.set_active(True) if tb._active == 'PAN': tb.pan() tb._actions['pan'].setChecked(False) if tb._active == 'ZOOM': tb.zoom() tb._actions['zoom'].setChecked(False) span_control = QtWidgets.QPushButton('λ') span_control.setCheckable(True) span_control.clicked.connect(enable_span) span_control.setStyleSheet("color: #de2d26; font-weight: bold;") fig.canvas.manager.toolbar.addWidget(span_control) if line_list is not None: def auto_identify(): _idx = np.argsort(map_dict['wavelength']) wvln = np.array(map_dict['wavelength'])[_idx] pixl = np.array(map_dict['pixel'])[_idx] # build an approximate wavelength solution to predict where lines are spl = InterpolatedUnivariateSpline(wvln, pixl, k=3) predicted_pixels = spl(line_list) new_waves = [] new_pixels = [] lw = np.median(line_widths) for pix_ctr, xmin, xmax, wave in zip(predicted_pixels, predicted_pixels - 3 * lw, predicted_pixels + 3 * lw, line_list): lp = get_line_props(pixels, flux, xmin, xmax, sigma0=lw) if lp is None or lp['amp'] < 1000.: # HACK # logger.error("Failed to fit predicted line at {:.3f}A, {:.2f}pix" # .format(wave, pix_ctr)) continue draw_line_marker(lp, wave, ax) new_waves.append(wave) new_pixels.append(pix_ctr) fig.canvas.draw() fig2, axes2 = plt.subplots(2, 1, figsize=(6, 10)) axes2[0].plot(new_pixels, new_waves, linestyle='none', marker='o') coef = np.polynomial.chebyshev.chebfit(new_pixels, new_waves, deg=5) pred = np.polynomial.chebyshev.chebval(new_pixels, coef) axes2[1].plot(new_pixels, new_waves - pred, linestyle='none', marker='o') plt.show() autoid_control = QtWidgets.QPushButton('auto-identify') autoid_control.clicked.connect(auto_identify) fig.canvas.manager.toolbar.addWidget(autoid_control) plt.show() return map_dict
class FittingDataPlot1D(DataPlotEditorBase): nplots = 2 range_axvspn = Any(transient=True) peaks_axvspn = List([],transient=True) frange = Tuple((0.0,0.0),transient=True) peaks = List([],transient=True) range_selector = Any(transient=True) #Instance(SpanSelector) peaks_selector = Any(transient=True) #(SpanSelector) editing = Enum('Peaks',['Range','Peaks'],transient=True) has_frange = Property(Bool) has_peaks = Property(Bool) def _get_has_frange(self): if (self.frange[1]-self.frange[0])>10: return True else: return False def _get_has_peaks(self): if len(self.peaks): return True else: return False def clear_spans(self,frange=True,peaks=True): if frange: try: self.range_axvspn.remove() except: pass if peaks: for axvspn in self.peaks_axvspn: try: axvspn.remove() except: pass def clear_selections(self): self.clear_spans(frange=True,peaks=False) self.peaks = [] #self.frange = (0.0,0.0) def draw(self,frange=True,peaks=True): if all([frange, len(self.axs), len(self.frange)]): self.range_axvspn = self.axs[0].axvspan(self.frange[0], self.frange[1], color='g', alpha=0.1) if all([peaks, len(self.axs)]): for xmin,xmax in self.peaks: self.peaks_axvspn.append(self.axs[0].axvspan(xmin, xmax, color='red', alpha=0.4)) if self.figure is not None: if self.figure.canvas is not None: self.figure.canvas.draw() def mpl_setup(self): self.add_subplots(self.nplots) self.configure_selector(peaks=True) #self.figure.canvas.draw() #self.activate_selector() def onselect(self,xmin,xmax): if self.editing=='Range': self.frange = (xmin,xmax) self.clear_spans(peaks=False) self.draw(peaks=False) #self.figure.canvas.draw() elif self.editing=='Peaks': self.peaks.append((xmin,xmax)) self.clear_spans(frange=False) self.draw(frange=False) #self.figure.canvas.draw() def configure_selector(self,frange=False,peaks=False): self.peaks_selector = SpanSelector(self.axs[0], self.onselect, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='red')) self.peaks_selector.set_active(peaks) self.range_selector = SpanSelector(self.axs[0], self.onselect, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='g')) self.range_selector.set_active(frange) def activate_selector(self,frange=False,peaks=False): if self.peaks_selector is not None: self.peaks_selector.set_active(peaks) if self.range_selector is not None: self.range_selector.set_active(frange) def _editing_changed(self,new): if new=='Range': self.configure_selector(frange=True,peaks=False) elif new=='Peaks': self.configure_selector(frange=False, peaks=True)