class TSScene(QGraphicsScene): starttimechanged = pyqtSignal(str) endtimechanged = pyqtSignal(str) def __init__(self, parent, width=14, height=12, numofchannel=6): super(TSScene, self).__init__(parent) # set waveform windows figure = Figure() figure.set_size_inches(width, height) self.graphwidth = figure.dpi * width self.canvas = FigureCanvas(figure) self.addWidget(self.canvas) self.canvas.mpl_connect('button_press_event',self.button_press_event) self.canvas.mpl_connect('button_release_event', self.button_release_event) self.canvas.mpl_connect('motion_notify_event', self.motion_notify_event) self.canvas.mpl_connect('scroll_event', self.scroll_event) self.axesavailability = [True for i in range(numofchannel)] self.axes = [] for i in range(numofchannel): self.axes.append(figure.add_subplot(str(numofchannel)+'1'+str(i+1))) # set backend data model self.data = TSData() self.visibleWave = {} self.starttime = None self.endtime = None # prepare for user input self.downxcoord = None self.wheelactive = False self.rect = None self.installEventFilter(self) self.showgap = False self.downbutton = None self.currentxdata = None self.count = 0 self.state = 'ready' self.timeline = QTimeLine(1) self.timeline.setCurrentTime(0) self.timeline.setUpdateInterval(1) self.timeline.finished.connect(self.timeshift) self.timeline.finished.connect(self.animfinished) def animfinished(self): self.state = 'ready' self.timeline.setCurrentTime(0) def togglegap(self): self.showgap = ~self.showgap tmplist = self.visibleWave.copy() for wave in tmplist: self.refreshwave(wave,tmplist[wave][1]) # self.togglewave(wave) # self.togglewave(wave, tmplist[wave][1]) def applytime(self, start: str, end: str): if self.data is None: return for wave in self.visibleWave: if start<self.visibleWave[wave][3]: start = self.visibleWave[wave][3] if end>self.visibleWave[wave][4]: end = self.visibleWave[wave][4] self.starttime = UTCDateTime(start) self.endtime = UTCDateTime(end) print((self.starttime, self.endtime, '-----------------')) tmplist = self.visibleWave.copy() for wave in tmplist: self.refreshwave(wave, tmplist[wave][1]) # self.togglewave(wave) # self.togglewave(wave, tmplist[wave][2]) def loadfile(self, filename: str): self.data.loadFile(filename) def getlist(self): return self.data.getlist() def getsegments(self, item: object): waves = self.data.getsegments(item.text(0)) wavelist = QListWidget() for w in waves: wavelist.addItem(w) # print(w) wavelist.itemDoubleClicked.connect(self.segmentselected) wavelistwindowlayout = QVBoxLayout() wavelistwindowlayout.addWidget(wavelist) self.wavelistwindow = QDialog(self.parent()) self.wavelistwindow.setWindowTitle('segments') self.wavelistwindow.setLayout(wavelistwindowlayout) self.wavelistwindow.resize(800,600) self.wavelistwindow.show() self.segmentsource = item.text(0) self.currentitem = item def segmentselected(self, segment: str): matches = re.match(r'[^ ]+ \| ([^ ]+) - ([^ ]+) \| .*', segment.text(), flags=0) start = UTCDateTime(matches.group(1)) end = UTCDateTime(matches.group(2)) print(start) print(end) if self.segmentsource in self.visibleWave: self.applytime(start, end) else: self.starttime = start self.endtime = end print((self.segmentsource)) self.togglewave(self.segmentsource) self.currentitem.setSelected(True) def refreshwave(self, wave: str, colorcode:int=0): if wave in self.visibleWave: axes, lines, _, _, _, _ = self.visibleWave[wave] self.removewave(axes, lines) self.visibleWave.pop(wave, None) channelid = self.axes.index(axes) self.axesavailability[channelid] = True waveform, wavename, starttime, endtime, gaps = self.data.getwaveform(wave, self.starttime, self.endtime) axes, lines = self.displaywave(wavename, waveform, gaps) if axes is not None: self.visibleWave[wave] = (axes, lines, colorcode, starttime, endtime, gaps) def hidewave(self, wave: str, colorcode:int=0): if wave in self.visibleWave: axes, lines, _, _, _, _ = self.visibleWave[wave] self.removewave(axes, lines) self.visibleWave.pop(wave, None) channelid = self.axes.index(axes) self.axesavailability[channelid] = True if len(self.visibleWave)==0: self.starttime = None self.endtime = None return True def showwave(self, wave: str, starttime=None, endtime=None): if starttime is None or endtime is None: if wave in self.visibleWave: pass else: self.togglewave(wave) else: self.starttime = starttime self.endtime = endtime tmplist = self.visibleWave.copy() for wave in tmplist: self.refreshwave(wave, tmplist[wave][1]) if wave not in self.visibleWave: self.togglewave(wave) def togglewave(self, wave: str, colorcode:int=0): if wave in self.visibleWave: axes, lines, _, _, _, _ = self.visibleWave[wave] self.removewave(axes, lines) self.visibleWave.pop(wave, None) channelid = self.axes.index(axes) self.axesavailability[channelid] = True if len(self.visibleWave)==0: self.starttime = None self.endtime = None else: # print(wave) waveform, wavename, starttime, endtime, gaps = self.data.getwaveform(wave, self.starttime, self.endtime) print((starttime, endtime)) axes, lines = self.displaywave(wavename, waveform, gaps) if axes is not None: self.visibleWave[wave] = (axes, lines, colorcode, starttime, endtime, gaps) #print("togglewave:", starttime, endtime) def displaywave(self, wavename: str, waveform: np.array, gaps, colorcode: int=None): if True not in self.axesavailability: return None, None else: location = self.axesavailability.index(True) axes = self.axes[location] self.axesavailability[location] = False if wavename is not None and waveform is not None: if colorcode is None: colorcode = 'C'+str(location%10) times = waveform[0,:] span = round(len(times)/4) if span<1: span = 1 axes.set_xticks(times[::span]) axes.set_xticklabels([UTCDateTime(t).strftime("%Y-%m-%d %H:%M:%S") for t in times[::span]]) lines = axes.plot(times, waveform[1,:],linestyle="-", label=wavename, color=colorcode) if self.showgap: for g in gaps: if g[4].timestamp>=times[0] and g[5].timestamp<times[-1]: axes.axvspan(g[4],g[5],facecolor='0.2',alpha=0.5) axes.legend() self.canvas.draw() if self.endtime is not None and self.starttime is not None and len(times)>0: timewindow = self.endtime-self.starttime if abs(times[0]-times[-1]-timewindow)/timewindow<0.1: self.starttime = UTCDateTime(times[0]) self.endtime = self.starttime + timewindow elif len(times)>0: self.starttime = UTCDateTime(times[0]) self.endtime = UTCDateTime(times[-1]) self.starttimechanged.emit(self.starttime.strftime("%Y-%m-%d %H:%M:%S")) self.endtimechanged.emit(self.endtime.strftime("%Y-%m-%d %H:%M:%S")) return axes, lines else: lines = None axes.legend([wavename]) return axes, lines def removewave(self, axes: Axes, lines: Line2D): if lines is not None: lines.pop(0).remove() axes.relim() axes.autoscale_view(True, True, True) axes.clear() self.canvas.draw() def timeshift(self): if self.downxcoord is None or self.currentxdata is None: return shift = self.downxcoord-self.currentxdata if shift == 0: print('skipped') return if self.starttime is None: return starttime = self.starttime + shift endtime = self.endtime + shift for wave in self.visibleWave: if starttime<self.visibleWave[wave][3]: starttime = self.visibleWave[wave][3] if endtime>self.visibleWave[wave][4]: endtime = self.visibleWave[wave][4] if starttime!=self.starttime and endtime!=self.endtime: self.starttime = starttime self.endtime = endtime tmplist = self.visibleWave.copy() for wave in tmplist: self.refreshwave(wave, tmplist[wave][1]) # self.togglewave(wave) # self.togglewave(wave, tmplist[wave][2]) return def timescale(self, delta: float): if self.starttime is None: return shift = (self.endtime - self.starttime) * -delta*0.1 starttime = self.starttime + shift endtime = self.endtime - shift for wave in self.visibleWave: if starttime<self.visibleWave[wave][3]: starttime = self.starttime if endtime>self.visibleWave[wave][4]: endtime = self.endtime if endtime-starttime<0.1: pass elif starttime==self.starttime and endtime==self.endtime: pass else: self.starttime = starttime self.endtime = endtime tmplist = self.visibleWave.copy() for wave in tmplist: self.refreshwave(wave, tmplist[wave][1]) # self.togglewave(wave) # self.togglewave(wave, tmplist[wave][1]) def button_press_event(self, event): if self.starttime is None: return self.downxcoord = event.xdata self.downx = event.x self.downbutton = event.button self.count = 0 def motion_notify_event(self, event): # print(event.button, self.starttime, self.downbutton, self.downxcoord, event.xdata) self.count += 1 self.currentxdata = event.xdata #print(self.currentxdata,"+" * 10) if self.starttime is None: return elif self.downxcoord is not None: if self.downbutton == 1 and self.timeline.currentTime()==0: self.state = 'busy' self.timeline.start() elif self.downbutton == 1: pass elif self.downbutton == 3: if self.rect is not None: self.removeItem(self.rect) if self.downx < event.x: self.rect = self.addRect(self.downx, 0, event.x - self.downx, self.height(), pen=QPen(Qt.red)) else: self.rect = self.addRect(event.x, 0, self.downx - event.x, self.height(), pen=QPen(Qt.red)) def button_release_event(self, event): if self.starttime is None: return if event.button == 3: left = 225 right = 1215 if self.downxcoord < event.xdata: start = self.downxcoord end = event.xdata else: start = event.xdata end = self.downxcoord start = UTCDateTime(start) end = UTCDateTime(end) print((start,end,'================')) self.applytime(start, end) # self.downx = None self.downbutton = None self.removeItem(self.rect) self.rect = None self.downxcoord = None self.currentxdata = None #print(self.count,'count!!!!!!!!') self.count=0 def scroll_event(self, event): delta = -event.step if self.wheelactive==False and event.xdata>= self.starttime and event.xdata<= self.endtime: self.wheelactive = True self.timescale(delta) self.wheelactive = False def exportmetadata(self, filename: tuple): wavelist = self.getlist() outfile = open(filename[0]+'.txt','w') for network in wavelist: for station in wavelist[network]: for wave in wavelist[network][station]: for w in wavelist[network][station][wave]: outfile.write("%s\n\n" % w) outfile.close() def exportwaveform(self, filename: tuple): traces = [] for wave in self.visibleWave: fill_value = 'last' waveform, wavename, starttime, endtime, gaps = self.data.readdisc(wave, self.starttime, self.endtime, resample=False, fill_value=fill_value) traces.append(waveform) stream = Stream(traces=traces) if 'MSEED' in filename[1]: stream.write(filename[0] + ".mseed", format='MSEED') elif 'txt' in filename[1]: stream.write(filename[0] + ".txt", format='TSPAIR') def gettimeboundary(self): return self.starttime, self.endtime return False