class TimeFrequencyFrame(BaseFrame, UiTimeFrequencyFrame): def __init__(self): super(TimeFrequencyFrame, self).__init__() self.setupUi(self) self.__stations_dir = None self.__metadata_manager = None self.inventory = {} self._stations_info = {} self.tr1 = [] self.tr2 = [] self.canvas_plot1 = MatplotlibCanvas(self.widget_plot_up, nrows=2) # self.canvas_plot1.set_xlabel(1, "Time (s)") # self.canvas_plot1.set_ylabel(0, "Amplitude ") # self.canvas_plot1.set_ylabel(1, "Frequency (Hz)") self.canvas_plot2 = MatplotlibCanvas(self.widget_plot_down, nrows=2) # self.canvas_plot2.set_xlabel(1, "Time (s)") # self.canvas_plot2.set_ylabel(0, "Amplitude ") # self.canvas_plot2.set_ylabel(1, "Frequency (Hz)") # Binding self.canvas_plot1.mpl_connect('key_press_event', self.key_pressed) self.canvas_plot2.mpl_connect('key_press_event', self.key_pressed) self.root_path_bind = BindPyqtObject(self.rootPathForm, self.onChange_root_path) self.dataless_path_bind = BindPyqtObject(self.datalessPathForm) self.metadata_path_bind = BindPyqtObject(self.datalessPathForm, self.onChange_metadata_path) # Add file selector to the widget self.file_selector = FilesView( self.root_path_bind.value, parent=self.fileSelectorWidget, on_change_file_callback=lambda file_path: self.onChange_file( file_path)) # Binds self.selectDirBtn.clicked.connect( lambda: self.on_click_select_directory(self.root_path_bind)) self.datalessBtn.clicked.connect( lambda: self.on_click_select_file(self.dataless_path_bind)) # Action Buttons self.actionSettings.triggered.connect( lambda: self.open_parameters_settings()) self.actionOpen_Help.triggered.connect(lambda: self.open_help()) self.actionOpen_Spectral_Analysis.triggered.connect( self.time_frequency_advance) self.plotBtn.clicked.connect(self.plot_seismogram) self.stationsBtn.clicked.connect(self.stations_info) # help Documentation self.help = HelpDoc() # Parameters settings self.parameters = ParametersSettings() # Time Frequency Advance #self.time_frequency_advance = TimeFrequencyAdvance() def filter_error_message(self, msg): md = MessageDialog(self) md.set_info_message(msg) def message_dataless_not_found(self): if len(self.dataless_not_found) > 1: md = MessageDialog(self) md.set_info_message("Metadata not found.") else: for file in self.dataless_not_found: md = MessageDialog(self) md.set_info_message("Metadata for {} not found.".format(file)) self.dataless_not_found.clear() def open_parameters_settings(self): self.parameters.show() def time_frequency_advance(self): self._time_frequency_advance = TimeFrequencyAdvance(self.tr1, self.tr2) self._time_frequency_advance.show() def validate_file(self): if not MseedUtil.is_valid_mseed(self.file_selector.file_path): msg = "The file {} is not a valid mseed. Please, choose a valid format". \ format(self.file_selector.file_name) raise InvalidFile(msg) def onChange_root_path(self, value): """ Fired every time the root_path is changed :param value: The path of the new directory. :return: """ self.file_selector.set_new_rootPath(value) def onChange_file(self, file_path): # Called every time user select a different file pass def on_click_select_directory(self, bind: BindPyqtObject): if "darwin" == platform: dir_path = pw.QFileDialog.getExistingDirectory( self, 'Select Directory', bind.value) else: dir_path = pw.QFileDialog.getExistingDirectory( self, 'Select Directory', bind.value, pw.QFileDialog.DontUseNativeDialog) if dir_path: bind.value = dir_path def on_click_select_file(self, bind: BindPyqtObject): selected = pw.QFileDialog.getOpenFileName(self, "Select metadata file") if isinstance(selected[0], str) and os.path.isfile(selected[0]): bind.value = selected[0] def onChange_metadata_path(self, value): md = MessageDialog(self) try: self.__metadata_manager = MetadataManager(value) self.inventory = self.__metadata_manager.get_inventory() md.set_info_message( "Loaded Metadata, please check your terminal for further details" ) except: md.set_error_message( "Something went wrong. Please check your metada file is a correct one" ) @property def trace(self): return ObspyUtil.get_tracer_from_file(self.file_selector.file_path) def get_data(self): file = self.file_selector.file_path starttime = convert_qdatetime_utcdatetime(self.starttime_date) endtime = convert_qdatetime_utcdatetime(self.endtime_date) diff = endtime - starttime parameters = self.parameters.getParameters() sd = SeismogramDataAdvanced(file) if self.trimCB.isChecked() and diff >= 0: tr = sd.get_waveform_advanced( parameters, self.inventory, filter_error_callback=self.filter_error_message, start_time=starttime, end_time=endtime) else: tr = sd.get_waveform_advanced( parameters, self.inventory, filter_error_callback=self.filter_error_message) t = tr.times() return tr, t def get_time_window(self): t1 = convert_qdatetime_utcdatetime(self.starttime_date) t2 = convert_qdatetime_utcdatetime(self.endtime_date) return t1, t2 def stations_info(self): obsfiles = MseedUtil.get_mseed_files(self.root_path_bind.value) obsfiles.sort() sd = [] for file in obsfiles: st = SeismogramDataAdvanced(file) station = [ st.stats.Network, st.stats.Station, st.stats.Location, st.stats.Channel, st.stats.StartTime, st.stats.EndTime, st.stats.Sampling_rate, st.stats.Npts ] sd.append(station) self._stations_info = StationsInfo(sd, check=False) self._stations_info.show() def plot_seismogram(self): selection = self.selectCB.currentText() if selection == "Seismogram 1": #self.validate_file() [self.tr1, t] = self.get_data() self.canvas_plot1.plot(t, self.tr1.data, 0, clear_plot=True, color="black", linewidth=0.5) self.canvas_plot1.set_xlabel(1, "Time (s)") self.canvas_plot1.set_ylabel(0, "Amplitude ") self.canvas_plot1.set_ylabel(1, "Frequency (Hz)") info = "{}.{}.{}".format(self.tr1.stats.network, self.tr1.stats.station, self.tr1.stats.channel) self.canvas_plot1.set_plot_label(0, info) if self.time_frequencyChB.isChecked(): self.time_frequency(self.tr1, selection) if selection == "Seismogram 2": #self.validate_file() [self.tr2, t] = self.get_data() self.canvas_plot2.plot(t, self.tr2.data, 0, clear_plot=True, color="black", linewidth=0.5) self.canvas_plot2.set_xlabel(1, "Time (s)") self.canvas_plot2.set_ylabel(0, "Amplitude ") self.canvas_plot2.set_ylabel(1, "Frequency (Hz)") info = "{}.{}.{}".format(self.tr2.stats.network, self.tr2.stats.station, self.tr2.stats.channel) self.canvas_plot2.set_plot_label(0, info) if self.time_frequencyChB.isChecked(): self.time_frequency(self.tr2, selection) @AsycTime.run_async() def time_frequency(self, tr, order): selection = self.time_frequencyCB.currentText() ts, te = self.get_time_window() diff = te - ts if selection == "Multitaper Spectrogram": win = int(self.mt_window_lengthDB.value() * tr.stats.sampling_rate) tbp = self.time_bandwidth_DB.value() ntapers = self.number_tapers_mtSB.value() f_min = self.freq_min_mtDB.value() f_max = self.freq_max_mtDB.value() mtspectrogram = MTspectrogram(self.file_selector.file_path, win, tbp, ntapers, f_min, f_max) if self.trimCB.isChecked() and diff >= 0: x, y, log_spectrogram = mtspectrogram.compute_spectrogram( tr, start_time=ts, end_time=te) else: x, y, log_spectrogram = mtspectrogram.compute_spectrogram(tr) log_spectrogram = np.clip(log_spectrogram, a_min=self.minlevelCB.value(), a_max=0) min_log_spectrogram = self.minlevelCB.value() max_log_spectrogram = 0 if order == "Seismogram 1": if self.typeCB.currentText() == 'contourf': self.canvas_plot1.plot_contour(x, y, log_spectrogram, axes_index=1, clabel="Power [dB]", cmap=plt.get_cmap("jet"), vmin=min_log_spectrogram, vmax=max_log_spectrogram) elif self.typeCB.currentText() == 'pcolormesh': print("plotting pcolormesh") self.canvas_plot1.pcolormesh(x, y, log_spectrogram, axes_index=1, clabel="Power [dB]", cmap=plt.get_cmap("jet"), vmin=min_log_spectrogram, vmax=max_log_spectrogram) self.canvas_plot1.set_xlabel(1, "Time (s)") self.canvas_plot1.set_ylabel(0, "Amplitude ") self.canvas_plot1.set_ylabel(1, "Frequency (Hz)") elif order == "Seismogram 2": if self.typeCB.currentText() == 'contourf': self.canvas_plot2.plot_contour(x, y, log_spectrogram, axes_index=1, clear_plot=True, clabel="Power [dB]", cmap=plt.get_cmap("jet"), vmin=min_log_spectrogram, vmax=max_log_spectrogram) elif self.typeCB.currentText() == 'pcolormesh': self.canvas_plot2.pcolormesh(x, y, log_spectrogram, axes_index=1, clear_plot=True, clabel="Power [dB]", cmap=plt.get_cmap("jet"), vmin=min_log_spectrogram, vmax=max_log_spectrogram) self.canvas_plot2.set_xlabel(1, "Time (s)") self.canvas_plot2.set_ylabel(0, "Amplitude ") self.canvas_plot2.set_ylabel(1, "Frequency (Hz)") elif selection == "Wigner Spectrogram": win = int(self.mt_window_lengthDB.value() * tr.stats.sampling_rate) tbp = self.time_bandwidth_DB.value() ntapers = self.number_tapers_mtSB.value() f_min = self.freq_min_mtDB.value() f_max = self.freq_max_mtDB.value() wignerspec = WignerVille(self.file_selector.file_path, win, tbp, ntapers, f_min, f_max) if self.trimCB.isChecked() and diff >= 0: x, y, log_spectrogram = wignerspec.compute_wigner_spectrogram( tr, start_time=ts, end_time=te) else: x, y, log_spectrogram = wignerspec.compute_wigner_spectrogram( tr) if order == "Seismogram 1": if self.typeCB.currentText() == 'contourf': self.canvas_plot1.plot_contour(x, y, log_spectrogram, axes_index=1, clear_plot=True, clabel="Rel Power ", cmap=plt.get_cmap("jet")) elif self.typeCB.currentText() == 'pcolormesh': self.canvas_plot1.pcolormesh(x, y, log_spectrogram, axes_index=1, clear_plot=True, clabel="Rel Power ", cmap=plt.get_cmap("jet")) self.canvas_plot1.set_xlabel(1, "Time (s)") self.canvas_plot1.set_ylabel(0, "Amplitude ") self.canvas_plot1.set_ylabel(1, "Frequency (Hz)") elif order == "Seismogram 2": if self.typeCB.currentText() == 'contourf': self.canvas_plot2.plot_contour(x, y, log_spectrogram, axes_index=1, clear_plot=True, clabel="Power [dB]", cmap=plt.get_cmap("jet")) elif self.typeCB.currentText() == 'pcolormesh': self.canvas_plot2.pcolormesh(x, y, log_spectrogram, axes_index=1, clear_plot=True, clabel="Power [dB]", cmap=plt.get_cmap("jet")) self.canvas_plot2.set_xlabel(1, "Time (s)") self.canvas_plot2.set_ylabel(0, "Amplitude ") self.canvas_plot2.set_ylabel(1, "Frequency (Hz)") elif selection == "Continuous Wavelet Transform": fs = tr.stats.sampling_rate nf = self.atomsSB.value() f_min = self.freq_min_cwtDB.value() f_max = self.freq_max_cwtDB.value() wmin = self.wminSB.value() wmax = self.wminSB.value() #tt = int( self.wavelet_lenghtDB.value()*fs) npts = len(tr.data) t = np.linspace(0, tr.stats.delta * npts, npts) #cw = ConvolveWaveletScipy(self.file_selector.file_path) cw = ConvolveWaveletScipy(tr) wavelet = self.wavelet_typeCB.currentText() m = self.wavelets_param.value() if self.trimCB.isChecked() and diff >= 0: cw.setup_wavelet(ts, te, wmin=wmin, wmax=wmax, tt=int(fs / f_min), fmin=f_min, fmax=f_max, nf=nf, use_wavelet=wavelet, m=m, decimate=False) else: cw.setup_wavelet(wmin=wmin, wmax=wmax, tt=int(fs / f_min), fmin=f_min, fmax=f_max, nf=nf, use_wavelet=wavelet, m=m, decimate=False) scalogram2 = cw.scalogram_in_dbs() scalogram2 = np.clip(scalogram2, a_min=self.minlevelCB.value(), a_max=0) cf = cw.cf_lowpass() freq = np.logspace(np.log10(f_min), np.log10(f_max)) k = wmin / (2 * np.pi * freq) delay = int(fs * np.mean(k)) x, y = np.meshgrid( t, np.logspace(np.log10(f_min), np.log10(f_max), scalogram2.shape[0])) c_f = wmin / 2 * math.pi f = np.linspace((f_min), (f_max), scalogram2.shape[0]) pred = (math.sqrt(2) * c_f / f) - (math.sqrt(2) * c_f / f_max) pred_comp = t[len(t) - 1] - pred min_cwt = self.minlevelCB.value() max_cwt = 0 norm = Normalize(vmin=min_cwt, vmax=max_cwt) tf = t[delay:len(t)] cf = cf[0:len(tf)] if order == "Seismogram 1": #self.canvas_plot1.plot(tf, cf, 0, clear_plot=True, is_twinx=True, color="red", # linewidth=0.5) if self.typeCB.currentText() == 'pcolormesh': self.canvas_plot1.pcolormesh(x, y, scalogram2, axes_index=1, clear_plot=True, clabel="Power [dB]", cmap=plt.get_cmap("jet"), vmin=min_cwt, vmax=max_cwt) elif self.typeCB.currentText() == 'contourf': self.canvas_plot1.plot_contour(x, y, scalogram2, axes_index=1, clear_plot=True, clabel="Power [dB]", cmap=plt.get_cmap("jet"), vmin=min_cwt, vmax=max_cwt) ax_cone = self.canvas_plot1.get_axe(1) ax_cone.fill_between(pred, f, 0, color="black", edgecolor="red", alpha=0.3) ax_cone.fill_between(pred_comp, f, 0, color="black", edgecolor="red", alpha=0.3) self.canvas_plot1.set_xlabel(1, "Time (s)") self.canvas_plot1.set_ylabel(0, "Amplitude ") self.canvas_plot1.set_ylabel(1, "Frequency (Hz)") if order == "Seismogram 2": #self.canvas_plot2.plot(tf, cf, 0, clear_plot=True, is_twinx=True, color="red", # linewidth=0.5) if self.typeCB.currentText() == 'pcolormesh': self.canvas_plot2.pcolormesh(x, y, scalogram2, axes_index=1, clear_plot=True, clabel="Power [dB]", cmap=plt.get_cmap("jet"), vmin=min_cwt, vmax=max_cwt) elif self.typeCB.currentText() == 'contourf': self.canvas_plot2.plot_contour(x, y, scalogram2, axes_index=1, clear_plot=True, clabel="Power [dB]", cmap=plt.get_cmap("jet"), vmin=min_cwt, vmax=max_cwt) ax_cone2 = self.canvas_plot2.get_axe(1) ax_cone2.fill_between(pred, f, 0, color="black", edgecolor="red", alpha=0.3) ax_cone2.fill_between(pred_comp, f, 0, color="black", edgecolor="red", alpha=0.3) self.canvas_plot2.set_xlabel(1, "Time (s)") self.canvas_plot2.set_ylabel(0, "Amplitude ") self.canvas_plot2.set_ylabel(1, "Frequency (Hz)") else: pass def key_pressed(self, event): selection = self.selectCB.currentText() if event.key == 'w': self.plot_seismogram() if event.key == 'q': if selection == "Seismogram 1": [tr, t] = self.get_data() x1, y1 = event.xdata, event.ydata tt = tr.stats.starttime + x1 set_qdatetime(tt, self.starttime_date) self.canvas_plot1.draw_arrow(x1, 0, arrow_label="st", color="purple", linestyles='--', picker=False) elif selection == "Seismogram 2": [tr, t] = self.get_data() x1, y1 = event.xdata, event.ydata tt = tr.stats.starttime + x1 set_qdatetime(tt, self.starttime_date) self.canvas_plot2.draw_arrow(x1, 0, arrow_label="st", color="purple", linestyles='--', picker=False) if event.key == 'e': if selection == "Seismogram 1": [tr, t] = self.get_data() x1, y1 = event.xdata, event.ydata tt = tr.stats.starttime + x1 set_qdatetime(tt, self.endtime_date) self.canvas_plot1.draw_arrow(x1, 0, arrow_label="et", color="purple", linestyles='--', picker=False) elif selection == "Seismogram 2": [tr, t] = self.get_data() x1, y1 = event.xdata, event.ydata tt = tr.stats.starttime + x1 set_qdatetime(tt, self.endtime_date) self.canvas_plot2.draw_arrow(x1, 0, arrow_label="et", color="purple", linestyles='--', picker=False) def open_help(self): self.help.show()
class Earthquake3CFrame(pw.QFrame, UiEarthquake3CFrame): def __init__(self, parent: pw.QWidget): super(Earthquake3CFrame, self).__init__(parent) self.setupUi(self) ParentWidget.set_parent(parent, self) #Initialize parametrs for plot rotation self._z = {} self._r = {} self._t = {} self._st = {} self.inventory = {} #self.filter_3ca = FilterBox(self.toolQFrame, 1) # add filter box component. self.parameters = ParametersSettings() # 3C_Component self.canvas = MatplotlibCanvas(self.plotMatWidget_3C) self.canvas.set_new_subplot(3, ncols=1) self.canvas_pol = MatplotlibCanvas(self.Widget_polarization) self.canvas.mpl_connect('key_press_event', self.key_pressed) # binds self.root_path_bind_3C = BindPyqtObject(self.rootPathForm_3C, self.onChange_root_path_3C) self.degreeSB_bind = BindPyqtObject(self.degreeSB) self.vertical_form_bind = BindPyqtObject(self.verticalQLineEdit) self.north_form_bind = BindPyqtObject(self.northQLineEdit) self.east_form_bind = BindPyqtObject(self.eastQLineEdit) # accept drops self.vertical_form_bind.accept_dragFile( drop_event_callback=self.drop_event) self.north_form_bind.accept_dragFile( drop_event_callback=self.drop_event) self.east_form_bind.accept_dragFile( drop_event_callback=self.drop_event) # Add file selector to the widget self.file_selector = FilesView(self.root_path_bind_3C.value, parent=self.fileSelectorWidget) self.file_selector.setDragEnabled(True) self.selectDirBtn_3C.clicked.connect(self.on_click_select_directory_3C) self.rotateplotBtn.clicked.connect( lambda: self.on_click_rotate(self.canvas)) self.rot_macroBtn.clicked.connect( lambda: self.open_parameters_settings()) self.polarizationBtn.clicked.connect(self.on_click_polarization) ### self.plotpolBtn.clicked.connect(self.plot_particle_motion) self.stationsBtn.clicked.connect(self.stationsInfo) self.save_rotatedBtn.clicked.connect(self.save_rotated) ### def open_parameters_settings(self): self.parameters.show() def info_message(self, msg): md = MessageDialog(self) md.set_info_message(msg) @staticmethod def drop_event(event: pqg.QDropEvent, bind_object: BindPyqtObject): data = event.mimeData() url = data.urls()[0] bind_object.value = url.fileName() @property def north_component_file(self): return os.path.join(self.root_path_bind_3C.value, self.north_form_bind.value) @property def vertical_component_file(self): return os.path.join(self.root_path_bind_3C.value, self.vertical_form_bind.value) @property def east_component_file(self): return os.path.join(self.root_path_bind_3C.value, self.east_form_bind.value) def onChange_root_path_3C(self, value): """ Fired every time the root_path is changed :param value: The path of the new directory. :return: """ self.file_selector.set_new_rootPath(value) # Function added for 3C Components def on_click_select_directory_3C(self): if "darwin" == platform: dir_path = pw.QFileDialog.getExistingDirectory( self, 'Select Directory', self.root_path_bind_3C.value) else: dir_path = pw.QFileDialog.getExistingDirectory( self, 'Select Directory', self.root_path_bind_3C.value, pw.QFileDialog.DontUseNativeDialog) if dir_path: self.root_path_bind_3C.value = dir_path def set_times(self, st): max_start = np.max([tr.stats.starttime for tr in st]) min_end = np.min([tr.stats.endtime for tr in st]) return min_end, max_start def on_click_rotate(self, canvas): time1 = convert_qdatetime_utcdatetime(self.dateTimeEdit_4) time2 = convert_qdatetime_utcdatetime(self.dateTimeEdit_5) angle = self.degreeSB.value() incidence_angle = self.incidenceSB.value() method = self.methodCB.currentText() parameters = self.parameters.getParameters() try: sd = PolarizationAnalyis(self.vertical_component_file, self.north_component_file, self.east_component_file) time, z, r, t, st = sd.rotate(self.inventory, time1, time2, angle, incidence_angle, method=method, parameters=parameters, trim=True) self._z = z self._r = r self._t = t self._st = st rotated_seismograms = [z, r, t] for index, data in enumerate(rotated_seismograms): self.canvas.plot(time, data, index, color="black", linewidth=0.5) info = "{}.{}.{}".format(self._st[index].stats.network, self._st[index].stats.station, self._st[index].stats.channel) ax = self.canvas.get_axe(0) ax.set_xlim(sd.t1.matplotlib_date, sd.t2.matplotlib_date) formatter = mdt.DateFormatter('%Y/%m/%d/%H:%M:%S') ax.xaxis.set_major_formatter(formatter) self.canvas.set_plot_label(index, info) canvas.set_xlabel(2, "Time (s)") except InvalidFile: self.info_message( "Invalid mseed files. Please, make sure to select all the three components (Z, N, E) " "for rotate.") except ValueError as error: self.info_message(str(error)) def on_click_polarization(self): time1 = convert_qdatetime_utcdatetime(self.dateTimeEdit_4) time2 = convert_qdatetime_utcdatetime(self.dateTimeEdit_5) sd = PolarizationAnalyis(self.vertical_component_file, self.north_component_file, self.east_component_file) try: var = sd.polarize(time1, time2, self.doubleSpinBox_winlen.value(), self.freq_minDB.value(), self.freq_maxDB.value()) artist = self.canvas_pol.plot( var['time'], var[self.comboBox_yaxis.currentText()], 0, clear_plot=True, linewidth=0.5) self.canvas_pol.set_xlabel(0, "Time [s]") self.canvas_pol.set_ylabel(0, self.comboBox_yaxis.currentText()) self.canvas_pol.set_yaxis_color(self.canvas_pol.get_axe(0), artist.get_color(), is_left=True) self.canvas_pol.plot(var['time'], var[self.comboBox_polarity.currentText()], 0, is_twinx=True, color="red", linewidth=0.5) self.canvas_pol.set_ylabel_twinx( 0, self.comboBox_polarity.currentText()) except InvalidFile: self.info_message( "Invalid mseed files. Please, make sure to select all the three components (Z, N, E) " "for polarization.") except ValueError as error: self.info_message(str(error)) def plot_particle_motion(self): self._plot_polarization = PlotPolarization(self._z, self._r, self._t) self._plot_polarization.show() def stationsInfo(self): files = [] try: if self.vertical_component_file and self.north_component_file and self.east_component_file: files = [ self.vertical_component_file, self.north_component_file, self.east_component_file ] except: pass sd = [] if len(files) == 3: for file in files: try: st = SeismogramDataAdvanced(file) station = [ st.stats.Network, st.stats.Station, st.stats.Location, st.stats.Channel, st.stats.StartTime, st.stats.EndTime, st.stats.Sampling_rate, st.stats.Npts ] sd.append(station) except: pass self._stations_info = StationsInfo(sd) self._stations_info.show() def save_rotated(self): import os root_path = os.path.dirname(os.path.abspath(__file__)) if "darwin" == platform: dir_path = pw.QFileDialog.getExistingDirectory( self, 'Select Directory', root_path) else: dir_path = pw.QFileDialog.getExistingDirectory( self, 'Select Directory', root_path, pw.QFileDialog.DontUseNativeDialog) if self._st: n = len(self._st) for j in range(n): tr = self._st[j] t1 = tr.stats.starttime id = tr.id + "." + "D" + "." + str(t1.year) + "." + str( t1.julday) print(tr.id, "Writing data processed") path_output = os.path.join(dir_path, id) tr.write(path_output, format="MSEED") def key_pressed(self, event): if event.key == 'q': x1, y1 = event.xdata, event.ydata tt = UTCDateTime(mdt.num2date(x1)) set_qdatetime(tt, self.dateTimeEdit_4) self.canvas.draw_arrow(x1, 0, arrow_label="st", color="purple", linestyles='--', picker=False) self.canvas.draw_arrow(x1, 1, arrow_label="st", color="purple", linestyles='--', picker=False) self.canvas.draw_arrow(x1, 2, arrow_label="st", color="purple", linestyles='--', picker=False) if event.key == 'e': x1, y1 = event.xdata, event.ydata tt = UTCDateTime(mdt.num2date(x1)) set_qdatetime(tt, self.dateTimeEdit_5) self.canvas.draw_arrow(x1, 0, arrow_label="et", color="purple", linestyles='--', picker=False) self.canvas.draw_arrow(x1, 1, arrow_label="st", color="purple", linestyles='--', picker=False) self.canvas.draw_arrow(x1, 2, arrow_label="st", color="purple", linestyles='--', picker=False)