# http://pyrocko.org - GPLv3 # # The Pyrocko Developers, 21st Century # ---|P------/S----------~Lg----------
PhaseMarker, make_QPolygonF, draw_label, Label, Progressbars)
else: return x, None
qw.QFileDialog.DontUseSheet
macosx = True else:
def __str__(self): if abs(self) >= 10000.: return '%g km' % round(self/1000., 0) elif abs(self) >= 1000.: return '%g km' % round(self/1000., 1) else: return '%.5g m' % self
if other is None: return True return float(self) < float(other)
if other is None: return False return float(self) > float(other)
if x is None: return None else: return m_float(x)
"""Split a list of integers into sublists of consecutive elements.""" enumerate(items), (lambda x: x[1]-x[0]))]
def __str__(self): return '%4.0f' % self
if x is None: return None else: return deg_float(x)
def __str__(self): return '[%i]' % self
snum = m.group(1) + ' × 10<sup>%i</sup>' % int(m.group(2))
else: return tuple([0.] * 5)
for trace in traces: trace.ydata = trace.ydata - trace.ydata.mean() trace.ydata = num.cumsum(trace.ydata)
return traces
'scarletred'.split():
qg.QPen(qg.QColor(*pyrocko.plot.tango_colors[color+'3'])), qg.QBrush(qg.QColor( *(pyrocko.plot.tango_colors[color+'1'] + (box_alpha,)))), ))
syear = 60*60*24*365. # / acceptable_tincs = num.array([ 1, 2, 5, 10, 20, 30, 60, 60*5, 60*10, 60*20, 60*30, 60*60, 60*60*3, 60*60*6, 60*60*12, sday, smonth, syear], dtype=num.float)
hi = now except Exception: break lo = now except Exception: return lo, hi
working_system_time_range = get_working_system_time_range()
return working_system_time_range[0] <= t and \ t <= working_system_time_range[1]
if inc < 0.000001: l0_fmt = '.%n' l0_center = False l1_fmt = '%H:%M:%S' l1_trig = 6 l2_fmt = '%b %d, %Y' elif inc < 0.001: l0_fmt = '.%u' l0_center = False l1_fmt = '%H:%M:%S' l1_trig = 6 l2_fmt = '%b %d, %Y' elif inc < 1: l0_fmt = '.%r' l0_center = False l1_fmt = '%H:%M:%S' l1_trig = 6 l2_fmt = '%b %d, %Y' elif inc < 3600: l0_fmt = '%H:%M' l0_center = False l1_fmt = '%b %d, %Y' elif inc < sday: l0_fmt = '%H:%M' l0_center = False l1_fmt = '%b %d, %Y' elif inc < smonth: l0_fmt = '%a %d' l0_fmt_brief = '%d' l0_center = True l1_fmt = '%b, %Y' l1_trig = 1 l1_trig = 0 return l0_fmt, l0_fmt_brief, l0_center, l1_fmt, l1_trig, l2_fmt, l2_trig
return calendar.timegm(tts)
return calendar.timegm(tts)
return calendar.timegm(tts)
if inc0 < acceptable_tincs[0]: return pyrocko.plot.nice_value(inc0/syear)*syear return acceptable_tincs[i]
self.mode = 'min-max' assert self.mode in ('min-max', 'off'), \ 'mode must be "min-max" or "off" for TimeScaler' is_reverse = (data_range[0] > data_range[1]) nmi = mi - self.space*(ma-mi) nma = ma + self.space*(ma-mi) mi, ma = nmi, nma if mi == ma and self.mode != 'off': mi -= 1.0 ma += 1.0 ma = min(working_system_time_range[1], ma)
if self.inc is not None: inc = self.inc inc = time_nice_value((ma-mi)/self.approx_ticks) else: inc = time_nice_value((ma-mi)*10.) if inc == 0.0: inc = 1.0 if is_reverse: return ma, mi, -inc return mi, ma, inc mi, ma, inc = self.make_scale(data_range) if inc < 0: mi, ma, inc = ma, mi, -inc is_reverse = True ticks = [] if inc < 0.001: mi_day = hpfloat(mi_day) if inc < 0.001: base = hpfloat(base) break i = 0 i += 1 elif inc < smonth: mi_day = day_start(max(mi, working_system_time_range[0]+sday*1.5)) dt_base = datetime.datetime(*time.gmtime(mi_day)[:6]) delta = datetime.timedelta(days=int(round(inc/sday))) if mi_day == mi: dt_base += delta i = 0 while True: current = dt_base + i*delta tick = calendar.timegm(current.timetuple()) if tick > ma: break ticks.append(tick) i += 1 mi_month = month_start(max( mi, working_system_time_range[0]+smonth*1.5)) y, m = y+1, 1 break ticks.append(tick)
mi_year = year_start(max( mi, working_system_time_range[0]+syear*1.5)) y = int(num.floor(time.gmtime(mi_year)[0]/incy)*incy) ticks.append(tick) if is_reverse: ticks.reverse() return ticks, inc
return (0, 1, 1, 0, 0, 0)[l1_trig:] == tt[l1_trig:6] and ms == 0.0
l0_fmt, l0_fmt_brief, l0_center, l1_fmt, l1_trig, l2_fmt, l2_trig = \ fancy_time_ax_format(inc) if need_l1_tick(tt, ms, l2_trig): l2 = mystrftime(l2_fmt, tt, ms) return l0, l0_brief, l0_center, l1, l2
l0_fmt, l0_fmt_brief, l0_center, l1_fmt, l1_trig, l2_fmt, l2_trig = \ fancy_time_ax_format(inc) return l1, l2
TimeScaler.__init__(self, *args) l2_hits = 0 umin = xprojection(tick) umax = xprojection(tick) pinc_approx = umin_approx_next - umin l0, l0_brief, l0_center, l1, l2 = tick_to_labels(tick, inc) if tick == 0.0 and tmax - tmin < 3600*24: if l2: l1 = None ushift = (umin_approx_next-umin)/2. ushift = 0. break if uumin+pad < umin-rect0.width()/2.+ushift and \ umin+rect0.width()/2.+ushift < uumax-pad: p.drawText(qc.QPointF( umin-rect0.width()/2.+ushift, vmin+rect0.height()+ticklen), label0) if uumin+pad < umin-rect1.width()/2. and \ umin+rect1.width()/2. < uumax-pad: p.drawText(qc.QPointF( umin-rect1.width()/2., vmin+rect0.height()+rect1.height()+ticklen), label1) l1_hits += 1 if l2: label2 = l2 rect2 = fm.boundingRect(label2) if uumin+pad < umin-rect2.width()/2. and \ umin+rect2.width()/2. < uumax-pad:
p.drawText(qc.QPointF( umin-rect2.width()/2., vmin+rect0.height()+rect1.height()+rect2.height() + ticklen), label2)
l2_hits += 1 if first_tick_with_label is None: first_tick_with_label = tmin l1, l2 = l1_l2_tick(first_tick_with_label, inc) if -3600.*25 < first_tick_with_label <= 3600.*25 and \ tmax - tmin < 3600*24:
if l2: l1 = None p.drawText(qc.QPointF( uumin+pad, vmin+rect0.height()+rect1.height()+ticklen), label1) l1_hits += 1 if l2_hits == 0 and l2: label2 = l2 rect2 = fm.boundingRect(label2) p.drawText(qc.QPointF( uumin+pad, vmin+rect0.height()+rect1.height()+rect2.height()+ticklen), label2) p.drawLine(qc.QPointF(uumin, v), qc.QPointF(uumax, v))
self.ur = 0., 1. if xmax == xmin: xmax = xmin + 1. self.xr = xmin, xmax return self.xr if umax == umin: umax = umin + 1. self.ur = umin, umax return self.ur return umin + (x-xmin)*((umax-umin)/(xmax-xmin)) return min(umax, max(umin, umin + (x-xmin)*((umax-umin)/(xmax-xmin)))) return xmin + (u-umin)*((xmax-xmin)/(umax-umin)) return copy.copy(self)
k.setChecked(True) return menuitems
actions.sort(key=lambda x: newstr(x.text())) menu.addAction(action)
fkey_map = dict(zip( (qc.Qt.Key_F1, qc.Qt.Key_F2, qc.Qt.Key_F3, qc.Qt.Key_F4, qc.Qt.Key_F5, qc.Qt.Key_F6, qc.Qt.Key_F7, qc.Qt.Key_F8, qc.Qt.Key_F9, qc.Qt.Key_F10, qc.Qt.Key_F11, qc.Qt.Key_F12), range(12)))
pass
def MakePileViewerMainClass(base): class PileViewerMain(base): tracks_range_changed = qc.pyqtSignal(int, int, int) active_event_marker_changed = qc.pyqtSignal(int) if base == qgl.QGLWidget: from OpenGL import GL # noqa
base.__init__( self, qgl.QGLFormat(qgl.QGL.SampleBuffers), *args) base.__init__(self, *args) self.panel_parent = panel_parent self.click_tolerance = 5 self.track_trange = None self.config = pyrocko.config.config('snuffler') poli = qw.QSizePolicy( qw.QSizePolicy.Expanding, qw.QSizePolicy.Expanding) self.setFocusPolicy(qc.Qt.ClickFocus) self.menu = qw.QMenu(self) mi.triggered.connect(self.open_waveforms) mi.triggered.connect(self.open_waveform_directory) mi.triggered.connect(self.open_stations) mi.triggered.connect(self.write_markers) mi.triggered.connect(self.write_selected_markers) mi.triggered.connect(self.read_markers) mi.triggered.connect(self.read_events) self.menu.addSeparator() menudef = [ ('Individual Scale', lambda tr: tr.nslc_id), ('Common Scale', lambda tr: None), ('Common Scale per Station', lambda tr: (tr.network, tr.station)), ('Common Scale per Station Location', lambda tr: (tr.network, tr.station, tr.location)), ('Common Scale per Component', lambda tr: (tr.channel)), ] self.menuitems_scaling = add_radiobuttongroup( self.menu, menudef, self, self.scalingmode_change, default=self.config.trace_scale) self.scalingmode_change() self.menu.addSeparator() menudef = [ ('Scaling based on Minimum and Maximum', 'minmax'), ('Scaling based on Mean +- 2 x Std. Deviation', 2), ('Scaling based on Mean +- 4 x Std. Deviation', 4), ] self.menuitems_scaling_base = add_radiobuttongroup( self.menu, menudef, self, self.scaling_base_change) self.scaling_base = self.menuitems_scaling_base[0][1] self.menu.addSeparator() def sector_dist(sta): if sta.dist_m is None: return None, None else: return ( sector_int(round((sta.azimuth+15.)/30.)), m_float(sta.dist_m)) menudef = [ ('Sort by Names', lambda tr: ()), ('Sort by Distance', lambda tr: self.station_attrib( tr, lambda sta: (m_float_or_none(sta.dist_m),), lambda tr: (None,))), ('Sort by Azimuth', lambda tr: self.station_attrib( tr, lambda sta: (deg_float_or_none(sta.azimuth),), lambda tr: (None,))), ('Sort by Distance in 12 Azimuthal Blocks', lambda tr: self.station_attrib( tr, sector_dist, lambda tr: (None, None))), ('Sort by Backazimuth', lambda tr: self.station_attrib( tr, lambda sta: (deg_float_or_none(sta.backazimuth),), lambda tr: (None,))), self.menuitems_ssorting = add_radiobuttongroup( self.menu, menudef, self, self.s_sortingmode_change) self._ssort = lambda tr: () self.menuitem_distances_3d.toggled.connect( self.distances_3d_changed) self.menu.addAction(self.menuitem_distances_3d) self.menu.addSeparator() menudef = [ ('Subsort by Network, Station, Location, Channel', (lambda tr: self.ssort(tr) + tr.nslc_id, # gathering lambda a: a, # sorting lambda tr: tr.location)), # coloring ('Subsort by Network, Station, Channel, Location', (lambda tr: self.ssort(tr) + ( tr.network, tr.station, tr.channel, tr.location), lambda a: a, lambda tr: tr.channel)), ('Subsort by Station, Network, Channel, Location', (lambda tr: self.ssort(tr) + ( tr.station, tr.network, tr.channel, tr.location), lambda a: a, lambda tr: tr.channel)), ('Subsort by Location, Network, Station, Channel', (lambda tr: self.ssort(tr) + ( tr.location, tr.network, tr.station, tr.channel), lambda a: a, lambda tr: tr.channel)), ('Subsort by Channel, Network, Station, Location', (lambda tr: self.ssort(tr) + ( tr.channel, tr.network, tr.station, tr.location), lambda a: a, lambda tr: (tr.network, tr.station, tr.location))), ('Subsort by Network, Station, Channel (Grouped by Location)', (lambda tr: self.ssort(tr) + ( tr.network, tr.station, tr.channel), lambda a: a, lambda tr: tr.location)), ('Subsort by Station, Network, Channel (Grouped by Location)', (lambda tr: self.ssort(tr) + ( tr.station, tr.network, tr.channel), lambda a: a, lambda tr: tr.location)), ] self.menuitems_sorting = add_radiobuttongroup( self.menu, menudef, self, self.sortingmode_change) self.menu.addSeparator() self.menu.addAction(self.menuitem_antialias) self.menuitem_liberal_fetch = qw.QAction( self.menu.addAction(self.menuitem_liberal_fetch) self.menu.addAction(self.menuitem_cliptraces) self.menuitem_showboxes.setChecked( self.menu.addAction(self.menuitem_showboxes) self.menu.addAction(self.menuitem_colortraces) self.menuitem_showscalerange = qw.QAction( self.menuitem_showscalerange.setChecked( self.menu.addAction(self.menuitem_showscalerange) self.menuitem_showscaleaxis = qw.QAction( self.menuitem_showscaleaxis.setChecked( self.menu.addAction(self.menuitem_showscaleaxis) self.menuitem_showzeroline = qw.QAction( self.menu.addAction(self.menuitem_showzeroline) self.menuitem_fixscalerange = qw.QAction( self.menu.addAction(self.menuitem_fixscalerange) self.menuitem_allowdownsampling = qw.QAction( self.menu.addAction(self.menuitem_allowdownsampling) self.menu.addAction(self.menuitem_degap) self.menu.addAction(self.menuitem_demean) self.menuitem_fft_filtering = qw.QAction( self.menu.addAction(self.menuitem_fft_filtering) self.menuitem_lphp = qw.QAction( self.menu.addAction(self.menuitem_lphp) self.menu.addAction(self.menuitem_watch) self.visible_length_menu = qw.QMenu('Visible Length', self.menu) menudef = [(x.key, x.value) for x in self.config.visible_length_setting] self.menuitems_visible_length = add_radiobuttongroup( self.visible_length_menu, menudef, self, self.visible_length_change) self.menu.addSeparator() self.menu.addMenu(self.snufflings_menu) self.menu.addMenu(self.toggle_panel_menu) self.menuitem_reload.triggered.connect( self.setup_snufflings) self.menu.addSeparator()
# Disable ShadowPileTest if False: self.menuitem_test = qw.QAction('Test', self.menu) self.menuitem_test.setCheckable(True) self.menuitem_test.setChecked(False) self.menu.addAction(self.menuitem_test) self.menuitem_test.triggered.connect( self.toggletest) self.menuitem_print.triggered.connect( self.printit) self.menuitem_svg.triggered.connect( self.savesvg) self.menuitem_help = qw.QAction( self.menuitem_help.triggered.connect(self.help) self.snuffling_help_menu.addSeparator() self.menuitem_about.triggered.connect(self.about) self.menuitem_close.triggered.connect(self.myclose) self.menu.addSeparator() self.menu.triggered.connect(self.update) self.time_projection.set_out_range(0., self.width()) self.gather = None self.blacklist = [] self.track_to_nslc_ids = {} self.old_processed_traces = None self.setMouseTracking(True) self.snufflings = [] self.stations = {} self.time_last_painted = time.time() self.follow_timer = None self.sortingmode_change_delay_time = None self.old_data_ranges = {} self.wheel_pos = 60 self._paths_to_load = [] self.tf_cache = {} self.automatic_updates = True self.paint_timer.start() @qc.pyqtSlot() if not self.updatesEnabled(): self.setUpdatesEnabled(True) def fail(self, reason): box = qw.QMessageBox(self) box.setText(reason) box.exec_() self.sortingmode_change() if self.blacklist: return not pyrocko.util.match_nslc( self.blacklist, tr.nslc_id)
blacklist_func = None self.set_trace_filter(blacklist_func) elif blacklist_func is None: self.set_trace_filter(self.quick_filter) else: self.set_trace_filter( lambda tr: blacklist_func(tr) and self.quick_filter(tr)) def set_quick_filter(self, filter_func): self.quick_filter = filter_func self.update_trace_filter() def set_quick_filter_patterns(self, patterns, inputline=None): if patterns is not None: self.set_quick_filter( lambda tr: pyrocko.util.match_nslc(patterns, tr.nslc_id)) else: self.set_quick_filter(None)
self.quick_filter_patterns = patterns, inputline return self.quick_filter_patterns if pattern == 'empty': keys = set(self.pile.nslc_ids) trs = self.pile.all( tmin=self.tmin, tmax=self.tmax, load_data=False, degap=False)
for tr in trs: if tr.nslc_id in keys: keys.remove(tr.nslc_id)
for key in keys: xpattern = '.'.join(key) if xpattern not in self.blacklist: self.blacklist.append(xpattern)
if pattern in self.blacklist: self.blacklist.remove(pattern) self.blacklist.append(pattern) self.update_trace_filter() self.blacklist.remove(pattern) else: raise PileViewerMainException( 'Pattern not found in blacklist.') self.update_trace_filter() self.update_trace_filter() return self._ssort(tr) def station_key(self, x): return x.network, x.station return [ (x.network, x.station, x.location), (x.network, x.station)] if sk in self.stations: station = self.stations[sk] return getter(station) return default_getter(tr) return self.stations[sk] return True
return False return self.station_attrib( tr, lambda sta: (sta.lat, sta.lon), default_getter) def set_stations(self, stations): self.stations = {} self.add_stations(stations) self.stations[sk] = station if ev: self.set_origin(ev) self.add_marker(marker) self.add_markers(markers) if not selected: self.fail('An event marker must be selected.') return if not isinstance(m, EventMarker): self.fail('Selected marker is not an event.') return self.set_active_event_marker(m) self.active_event_marker.set_active(False) self.active_event_marker = None self.active_event_marker.set_active(False) i_active = self.markers.index(self.active_event_marker) self.active_event_marker_changed.emit(i_active) self.set_active_event_marker(marker) return self.active_event_marker if m is not None: return m.get_event() return None def get_active_markers(self): emarker = self.get_active_event_marker() if emarker is None: return None, []
else: ev = emarker.get_event() pmarkers = [ m for m in self.markers if isinstance(m, PhaseMarker) and m.get_event() is ev]
return emarker, pmarkers station.set_event_relative_data( location, distance_3d=self.menuitem_distances_3d.isChecked()) self.sortingmode_change() def distances_3d_changed(self, ignore): self.set_event_marker_as_origin(ignore) def toggletest(self, checked): if checked: sp = Integrator()
self.add_shadow_pile(sp) else: self.remove_shadow_piles() def add_shadow_pile(self, shadow_pile): shadow_pile.set_basepile(self.pile) shadow_pile.add_listener(self) self.pile = shadow_pile def remove_shadow_piles(self): self.pile = self.pile.get_basepile() for path in self.snuffling_paths: os.mkdir(path) for entry in os.listdir(path): directory = path fn = entry d = pjoin(path, entry) if os.path.isdir(d): directory = d if os.path.isfile( os.path.join(directory, 'snuffling.py')): fn = 'snuffling.py'
if not fn.endswith('.py'): continue
name = fn[:-3]
if (directory, name) not in self.snuffling_modules: self.snuffling_modules[directory, name] = \ pyrocko.gui.snuffling.SnufflingModule( directory, name, self)
yield self.snuffling_modules[directory, name] def setup_snufflings(self): for mod in self.iter_snuffling_modules(): try: mod.load_if_needed() except pyrocko.gui.snuffling.BrokenSnufflingModule as e: logger.warning('Snuffling module "%s" is broken' % e)
self.default_snufflings = pyrocko.gui\ self.add_snuffling(snuffling) def set_panel_parent(self, panel_parent): self.panel_parent = panel_parent return self.panel_parent snuffling.init_gui( self.update() snuffling.pre_destroy() sort_actions(self.snufflings_menu) self.snufflings_menu.removeAction(item) sort_actions(self.snuffling_help_menu) self.snuffling_help_menu.removeAction(item) sort_actions(self.toggle_panel_menu) self.toggle_panel_menu.removeAction(item) def load(self, paths, regex=None, format='from_extension', cache_dir=None, force_cache=False): paths = [paths] fns = pyrocko.util.select_files( paths, selector=None, regex=regex, show_progress=False) return
cache = pyrocko.pile.get_cache(cache_dir)
t = [time.time()]
def update_bar(label, value): pbs = self.parent().get_progressbars() if label.lower() == 'looking at files': label = 'Looking at %i files' % len(fns) else: label = 'Scanning %i files' % len(fns)
return pbs.set_status(label, value)
def update_progress(label, i, n): abort = False
qw.qApp.processEvents() if n != 0: perc = i*100/n else: perc = 100 abort |= update_bar(label, perc) abort |= self.window().is_closing()
tnow = time.time() if t[0] + 1. + self.time_spent_painting * 10. < tnow: self.update() t[0] = tnow
return abort
self.automatic_updates = False
self.pile.load_files( sorted(fns), filename_attributes=regex, cache=cache, fileformat=format, show_progress=False, update_progress=update_progress)
self.automatic_updates = True self.update() def load_queued(self): if not self._paths_to_load: return paths = self._paths_to_load self._paths_to_load = [] self.load(paths) def load_soon(self, paths): self._paths_to_load.extend(paths) qc.QTimer.singleShot(200, self.load_queued) caption = 'Select one or more files to open' fns, _ = fnpatch(qw.QFileDialog.getOpenFileNames( self, caption, options=qfiledialog_options)) if fns: self.load(list(str(fn) for fn in fns)) caption = 'Select directory to scan for waveform files' dn = qw.QFileDialog.getExistingDirectory( self, caption, options=qfiledialog_options) if dn: self.load([str(dn)]) caption = 'Select one or more files to open' fns, _ = fnpatch(qw.QFileDialog.getOpenFileNames( self, caption, options=qfiledialog_options)) self.add_stations(stat) return ticket else: return (None, None) for ticket in tickets: pile, mtf = ticket if pile is not None: pile.remove_file(mtf) if self.pile.reload_modified(): self.update() return self.pile self.update() def set_gathering(self, gather=None, order=None, color=None): return tr.nslc_id return a return tr.location self.set_ntracks(len(keys)) if self.shown_tracks_range is None or \ previous_ntracks == 0 or \ self.show_all: n = high-low
n = high-low self.track_keys = sorted(keys, key=order) pass self.set_tracks_range((low, high)) self.key_to_row = dict( [(key, i) for (i, key) in enumerate(self.track_keys)]) return r[0] <= x and x < r[1] return ( gt in self.key_to_row and inrange(self.key_to_row[gt], self.shown_tracks_range)) self.trace_selector = lambda x: \ self.trace_filter(x) and trace_selector(x) self.trace_selector = trace_selector if self.tmin == working_system_time_range[0] and \ self.tmax == working_system_time_range[1] or \ self.show_all:
tmin, tmax = self.pile.get_tmin(), self.pile.get_tmax() if tmin is not None and tmax is not None: tlen = (tmax - tmin) tpad = tlen * 5./self.width() self.set_time_range(tmin-tpad, tmax+tpad) tmin = working_system_time_range[0] tmax = working_system_time_range[1] if tmin > tmax: tmin, tmax = tmax, tmin if tmin == tmax: tmin -= 1. tmax += 1. tmax = min(working_system_time_range[1], tmax) if (tmax - tmin < min_deltat): m = (tmin + tmax) / 2. tmin = m - min_deltat/2. tmax = m + min_deltat/2. self.tmin, self.tmax = tmin, tmax return self.tmin, self.tmax def ypart(self, y): if y < self.ax_height: return -1 elif y > self.height()-self.ax_height: return 1 else: return 0 return min(9, max(1, int(-math.floor(math.log10(min_deltat)))+2)) fn, _ = fnpatch(qw.QFileDialog.getSaveFileName( Marker.save_markers( sorted(self.markers, key=lambda m: m.tmin), fn, fdigits=self.time_fractional_digits()) fn, _ = fnpatch(qw.QFileDialog.getSaveFileName( Marker.save_markers( sorted(self.selected_markers(), key=lambda m: m.tmin), fn, fdigits=self.time_fractional_digits()) def read_events(self, fn=None): ''' Open QFileDialog to open, read and add :py:class:`pyrocko.model.Event` instances and their marker representation to the pile viewer. fn, _ = fnpatch(qw.QFileDialog.getOpenFileName( self.add_events(pyrocko.model.load_events(fn)) self.associate_phases_to_events() def read_markers(self, fn=None): ''' Open QFileDialog to open, read and add markers to the pile viewer. fn, _ = fnpatch(qw.QFileDialog.getOpenFileName( self.add_markers(Marker.load_markers(fn)) self.associate_phases_to_events() associate_phases_to_events(self.markers) self.markers_added.emit( len(self.markers)-1, len(self.markers)-1) self.markers_added.emit( len_before, len(self.markers)-1) def remove_marker(self, marker): '''Remove a ``marker`` from the :py:class:`PileViewer`.
if marker is self.active_event_marker: self.deactivate_event_marker() self.active_event_marker = None
except ValueError: pass def remove_markers(self, markers): '''Remove a list of ``markers`` from the :py:class:`PileViewer`.
:param markers: list of :py:class:`Marker` (or subclass) indxs = [self.markers.index(m) for m in markers] except ValueError: return about_to_remove = [self.markers[i_m] for i_m in chunk] self.active_event_marker = None
except ValueError: pass self.markers_removed.emit(istart, istop) def set_markers(self, markers): self.markers = markers return [marker for marker in self.markers if marker.is_selected()] return self.markers point = self.mapFromGlobal(mouse_ev.globalPos()) self.picking_down = ( self.time_projection.rev(mouse_ev.x()), mouse_ev.y())
elif marker is not None: if not (mouse_ev.modifiers() & qc.Qt.ShiftModifier): self.deselect_all() marker.set_selected(True) self.emit_selected_markers() self.update() else: self.track_start = mouse_ev.x(), mouse_ev.y() self.track_trange = self.tmin, self.tmax if mouse_ev.button() == qc.Qt.RightButton: self.update_status() return self.emit_selected_markers() if self.track_start: self.update() self.update_status() self.ignore_releases = 1 def mouseMoveEvent(self, mouse_ev): self.setUpdatesEnabled(False) point = self.mapFromGlobal(mouse_ev.globalPos())
if self.picking: self.update_picking(point.x(), point.y())
elif self.track_start is not None: x0, y0 = self.track_start dx = (point.x() - x0)/float(self.width()) dy = (point.y() - y0)/float(self.height()) if self.ypart(y0) == 1: dy = 0
tmin0, tmax0 = self.track_trange
scale = math.exp(-dy*5.) dtr = scale*(tmax0-tmin0) - (tmax0-tmin0) frac = x0/float(self.width()) dt = dx*(tmax0-tmin0)*scale
self.interrupt_following() self.set_time_range( tmin0 - dt - dtr*frac, tmax0 - dt + dtr*(1.-frac))
self.update() else: self.hoovering(point.x(), point.y())
self.update_status() def nslc_ids_under_cursor(self, x, y): ftrack = self.track_to_screen.rev(y) nslc_ids = self.get_nslc_ids_for_track(ftrack) return nslc_ids for marker in self.markers: if marker.kind not in self.visible_marker_kinds: continue
if (abs(mouset-marker.get_tmin()) < deltat or abs(mouset-marker.get_tmax()) < deltat):
if relevant_nslc_ids is None: relevant_nslc_ids = self.nslc_ids_under_cursor(x, y)
marker_nslc_ids = marker.get_nslc_ids() if not marker_nslc_ids: return marker
for nslc_id in marker_nslc_ids: if nslc_id in relevant_nslc_ids: return marker def hoovering(self, x, y): mouset = self.time_projection.rev(x) deltat = (self.tmax-self.tmin)*self.click_tolerance/self.width() needupdate = False haveone = False relevant_nslc_ids = self.nslc_ids_under_cursor(x, y) for marker in self.markers: if marker.kind not in self.visible_marker_kinds: continue
state = abs(mouset-marker.get_tmin()) < deltat or \ abs(mouset-marker.get_tmax()) < deltat and not haveone
if state: xstate = False
marker_nslc_ids = marker.get_nslc_ids() if not marker_nslc_ids: xstate = True
for nslc in relevant_nslc_ids: if marker.match_nslc(nslc): xstate = True
state = xstate
if state: haveone = True oldstate = marker.is_alerted() if oldstate != state: needupdate = True marker.set_alerted(state) if state: self.message = marker.hoover_message()
if not haveone: self.message = None
if needupdate: self.update() if event.type() == qc.QEvent.KeyPress: self.keyPressEvent(event) return True return base.event(self, event) tmid = (self.tmin + self.tmax) / 2. keytext = str(key_event.text()) except UnicodeEncodeError: return self.help() elif keytext == ' ': self.interrupt_following() self.set_time_range(self.tmin+dt, self.tmax+dt) elif key_event.key() == qc.Qt.Key_Up: for m in self.selected_markers(): if isinstance(m, PhaseMarker): if key_event.modifiers() & qc.Qt.ShiftModifier: p = 0 else: p = 1 if m.get_polarity() != 1 else None m.set_polarity(p) elif key_event.key() == qc.Qt.Key_Down: for m in self.selected_markers(): if isinstance(m, PhaseMarker): if key_event.modifiers() & qc.Qt.ShiftModifier: p = 0 else: p = -1 if m.get_polarity() != -1 else None m.set_polarity(p) elif keytext == 'b': dt = self.tmax - self.tmin self.interrupt_following() self.set_time_range(self.tmin-dt, self.tmax-dt) elif key_event.key() in (qc.Qt.Key_Tab, qc.Qt.Key_Backtab): self.interrupt_following()
tgo = None
class TraceDummy(object): def __init__(self, marker): self._marker = marker
@property def nslc_id(self): return self._marker.one_nslc()
def marker_to_itrack(marker): try: return self.key_to_row.get( self.gather(TraceDummy(marker)), -1)
except MarkerOneNSLCRequired: return -1
emarker, pmarkers = self.get_active_markers() pmarkers = [ m for m in pmarkers if m.kind in self.visible_marker_kinds] pmarkers.sort(key=lambda m: ( marker_to_itrack(m), (m.tmin + m.tmax) / 2.0))
if key_event.key() == qc.Qt.Key_Backtab: pmarkers.reverse()
smarkers = self.selected_markers() iselected = [] for sm in smarkers: try: iselected.append(pmarkers.index(sm)) except ValueError: pass
if iselected: icurrent = max(iselected) + 1 else: icurrent = 0
if icurrent < len(pmarkers): self.deselect_all() cmarker = pmarkers[icurrent] cmarker.set_selected(True) tgo = cmarker.tmin if not self.tmin < tgo < self.tmax: self.set_time_range(tgo-dt/2., tgo+dt/2.)
itrack = marker_to_itrack(cmarker) if itrack != -1: if itrack < self.shown_tracks_range[0]: self.scroll_tracks( - (self.shown_tracks_range[0] - itrack)) elif self.shown_tracks_range[1] <= itrack: self.scroll_tracks( itrack - self.shown_tracks_range[1]+1)
if itrack not in self.track_to_nslc_ids: self.go_to_selection() tmid = max(smarker.tmin, tmid) tmid = min(smarker.tmin, tmid) tgo = tmid for marker in sorted( self.markers, key=operator.attrgetter('tmin')): if t > tmid and \ marker.kind in self.visible_marker_kinds and \ (dir == 'n' or isinstance(marker, EventMarker)):
self.deselect_all() marker.set_selected(True) tgo = t break for marker in sorted( self.markers, key=operator.attrgetter('tmin'), reverse=True): if t < tmid and \ marker.kind in self.visible_marker_kinds and \ (dir == 'p' or break self.set_time_range(tgo-dt/2., tgo+dt/2.) self.myclose(keytext) if self.pile.reload_modified(): self.reloaded = True self.setup_snufflings() self.remove_markers(self.selected_markers()) if ((self.tmin <= marker.get_tmin() <= self.tmax or self.tmin <= marker.get_tmax() <= self.tmax) and marker.set_selected(True) else: marker.set_selected(False) marker.set_selected(True) elif keytext == 'd': self.deselect_all() elif keytext == 'E': self.deactivate_event_marker() event_markers_in_spe = [ marker for marker in markers if not isinstance(marker, PhaseMarker)] phase_markers = [ marker for marker in markers if isinstance(marker, PhaseMarker)] elif old is not None: lat, lon = old.lat, old.lon event_marker.convert_to_event_marker(lat, lon) for marker in phase_markers: marker.set_event(event)
else: for marker in event_markers_in_spe: marker.convert_to_event_marker() self.emit_selected_markers() self.handle_fkeys(key_event.key()) elif key_event.key() == qc.Qt.Key_Escape: if self.picking: self.stop_picking(0, 0, abort=True) self.scroll_tracks( self.shown_tracks_range[1]-self.shown_tracks_range[0]) self.scroll_tracks( self.shown_tracks_range[0]-self.shown_tracks_range[1]) self.zoom_tracks(0., 1.) self.zoom_tracks(0., -1.) elif keytext == '=': ntracks_shown = self.shown_tracks_range[1] - \ self.shown_tracks_range[0] dtracks = self.initial_ntracks_shown_max - ntracks_shown self.zoom_tracks(0., dtracks) self.want_input.emit() if self.window().windowState() & qc.Qt.WindowFullScreen or \ self.window().windowState() & qc.Qt.WindowMaximized: self.window().showNormal() if macosx: self.window().showMaximized() self.window().showFullScreen() self.go_to_selection() elif keytext == 'G': self.go_to_selection(tight=True) self.toggle_marker_editor() self.toggle_main_controls() elif key_event.key() in (qc.Qt.Key_Left, qc.Qt.Key_Right): dir = 1 amount = 1 if key_event.key() == qc.Qt.Key_Left: dir = -1 if key_event.modifiers() & qc.Qt.ShiftModifier: amount = 10 self.nudge_selected_markers(dir*amount) self.emit_selected_markers() self.update_status() self.set_phase_kind( self.selected_markers(), self.emit_selected_markers() _indexes.append(markers.index(sm)) self.changed_marker_selection.emit(_indexes) self.panel_parent.toggle_marker_editor() self.panel_parent.toggle_main_controls() def nudge_selected_markers(self, npixels): a, b = self.time_projection.ur c, d = self.time_projection.xr for marker in self.selected_markers(): if not isinstance(marker, EventMarker): marker.tmin += npixels * (d-c)/b marker.tmax += npixels * (d-c)/b def about(self): fn = pyrocko.util.data_file('snuffler.png') with open(pyrocko.util.data_file('snuffler_about.html')) as f: txt = f.read() label = qw.QLabel(txt % {'logo': fn}) label.setAlignment(qc.Qt.AlignVCenter | qc.Qt.AlignHCenter) self.show_doc('About', [label], target='tab') class MyScrollArea(qw.QScrollArea): def sizeHint(self): s = qc.QSize() s.setWidth(self.widget().sizeHint().width()) s.setHeight(self.widget().sizeHint().height()) return s with open(pyrocko.util.data_file( hcheat = qw.QLabel(f.read()) with open(pyrocko.util.data_file( hepilog = qw.QLabel(f.read()) h.setWordWrap(True) self.show_doc('Help', [hcheat, hepilog], target='panel') h.setTextInteractionFlags( h.linkActivated.connect( self.open_link) self.panel_parent.add_panel( name, scroller, True, volatile=False) else: self.panel_parent.add_tab(name, scroller) def open_link(self, link): qg.QDesktopServices.openUrl(qc.QUrl(link)) def wheelEvent(self, wheel_event): if use_pyqt5: self.wheel_pos += wheel_event.angleDelta().y() else: self.wheel_pos += wheel_event.delta()
n = self.wheel_pos // 120 self.wheel_pos = self.wheel_pos % 120 if n == 0: return
amount = max( 1., abs(self.shown_tracks_range[0]-self.shown_tracks_range[1])/5.) wdelta = amount * n
trmin, trmax = self.track_to_screen.get_in_range() anchor = (self.track_to_screen.rev(wheel_event.y())-trmin) \ / (trmax-trmin)
if wheel_event.modifiers() & qc.Qt.ControlModifier: self.zoom_tracks(anchor, wdelta) else: self.scroll_tracks(-wdelta) def dragEnterEvent(self, event): if event.mimeData().hasUrls(): if any(url.toLocalFile() for url in event.mimeData().urls()): event.setDropAction(qc.Qt.LinkAction) event.accept() def dropEvent(self, event): if event.mimeData().hasUrls(): paths = list( str(url.toLocalFile()) for url in event.mimeData().urls()) event.acceptProposedAction() self.load(paths) return self.config.get_phase_name(kind) phasename = self.get_phase_name(kind) marker.convert_to_marker() marker.set_event(self.get_active_event()) elif isinstance(marker, EventMarker): pass
marker.convert_to_phase_marker( event, phasename, None, False) l, h = self.shown_tracks_range else: l, h = 0, self.ntracks self.tracks_range_changed.emit(self.ntracks, l, h) def set_tracks_range(self, range, start=None): high = max(1, high) start = float(low) self.shown_tracks_start = start self.tracks_range_changed.emit(self.ntracks, low, high) shown = shown[0] + shift, shown[1] + shift self.set_tracks_range((int(shown[0]), int(shown[1]))) self.update() ntracks_shown = self.shown_tracks_range[1] \ - self.shown_tracks_range[0] if (ntracks_shown == 1 and delta <= 0) or \ return
ntracks_shown += int(round(delta)) ntracks_shown = min(max(1, ntracks_shown), self.ntracks)
u = self.shown_tracks_start nu = max(0., u-anchor*delta) nv = nu + ntracks_shown if nv > self.ntracks: nu -= nv - self.ntracks nv -= nv - self.ntracks
self.set_tracks_range((int(round(nu)), int(round(nv))), nu)
self.ntracks_shown_max = self.shown_tracks_range[1] \ - self.shown_tracks_range[0]
self.update() if tmin is None: if tmax is None: tmax = working_system_time_range[1] return tmin, tmax pile = self.get_pile() deltatmin, deltatmax = pile.get_deltatmin(), pile.get_deltatmax() deltatmin = 0.001 deltatmax = 1000.0 return deltatmin, deltatmax if tmax < tmin: tmin, tmax = tmax, tmin dt = deltatmin * self.visible_length * 0.95 if dt == 0.0: dt = 1.0 if tight: if tmax != tmin: dtm = tmax - tmin tmin -= dtm*0.1 tmax += dtm*0.1 return tmin, tmax else: tcenter = (tmin + tmax) / 2. tmin = tcenter - 0.5*dt tmax = tcenter + 0.5*dt return tmin, tmax dt = min(vmax - vmin, dt) tmax += dtm*0.1
tmax += dtm*0.1 return tmin, tmax tmax = max(tmax, marker.tmax)
else: if tight: vmin, vmax = self.get_time_range() tmin = tmax = (vmin + vmax) / 2. else: tmin, tmax = self.content_time_range() tmin, tmax = self.make_good_looking_time_range( tmin, tmax, tight=tight) self.update() self.update() if event.name and event.name.lower() == name.lower(): tmin, tmax = self.make_good_looking_time_range( event.time, event.time)
self.interrupt_following() self.set_time_range(tmin, tmax) def printit(self): from .qt_compat import qprint printer = qprint.QPrinter() printer.setOrientation(qprint.QPrinter.Landscape)
dialog = qprint.QPrintDialog(printer, self) dialog.setWindowTitle('Print')
if dialog.exec_() != qw.QDialog.Accepted: return
painter = qg.QPainter() painter.begin(printer) page = printer.pageRect() self.drawit( painter, printmode=False, w=page.width(), h=page.height())
painter.end() def savesvg(self, fn=None): fn, _ = fnpatch(qw.QFileDialog.getSaveFileName( self, 'Save as SVG|PNG', os.path.join(os.environ['HOME'], 'untitled.svg'), 'SVG|PNG (*.svg *.png)', options=qfiledialog_options)) return m = max(w, h)*margin generator.setViewBox(qc.QRectF(-m, -m, w+2*m, h+2*m)) painter.end() pixmap = self.grab() else: pixmap = qg.QPixmap().grabWidget(self) pixmap.save(fn)
else: logger.warning('unsupported file type') def paintEvent(self, paint_ev): painter = qg.QPainter(self) painter.setRenderHint(qg.QPainter.Antialiasing) self.drawit(painter) logger.debug( 'Time spent drawing: %.3f %.3f %.3f %.3f %.3f' % (self.timer_draw - self.timer_cutout)) logger.debug( 'Time spent processing: %.3f %.3f %.3f %.3f %.3f' % self.timer_cutout.get()) self.time_last_painted = time.time() def determine_box_styles(self): if itr > 0: other = traces[itr-1] if not ( other.nslc_id == tr.nslc_id and other.deltat == tr.deltat and abs(other.tmax - tr.tmin) < gap_lap_tolerance*tr.deltat):
istyle += 1 trace_styles[tr.full_id, tr.deltat] = istyle self.trace_styles = trace_styles def draw_trace_boxes(self, p, time_projection, track_projections): v_projection.set_in_range(0., 1.) return x.overlaps(*time_projection.get_in_range()) if self.trace_filter is not None: def tselector(x): return selector(x) and self.trace_filter(x)
tselector = selector traces = list(self.pile.iter_traces( group_selector=selector, trace_selector=tselector)) traces.sort(key=operator.attrgetter('full_id')) dtmax = time_projection.clipped(traces[-1].tmax) p.drawRect(rect) if gt not in self.key_to_row: continue if itrack not in track_projections: continue istyle = self.trace_styles.get((tr.full_id, tr.deltat), 0) drawbox(itrack, istyle, [tr]) else: if (itrack, istyle) not in traces_by_style: traces_by_style[itrack, istyle] = [] traces_by_style[itrack, istyle].append(tr) for (itrack, istyle), traces in traces_by_style.items(): drawbox(itrack, istyle, traces) def tobedrawn(self, markers, uminmax): """Returns two lists of indices: first indicates which markers should be labeled. second indicates which markers should be drawn.""" times = [m.tmin for m in markers] m_projections = num.array(list(map(self.time_projection, times))) m_projections = num.floor(m_projections) u, indx = num.unique(m_projections, return_index=True) a = num.zeros(len(m_projections)+2) umin, umax = uminmax a[0] = umin a[-1] = umax a[1:-1] = m_projections offsets = num.floor_divide(num.diff(a), 30.) with num.errstate(invalid='ignore'): offsets = num.divide(offsets, offsets) congregated = num.zeros(len(a)) congregated[:-1] = offsets congregated[1:] += offsets congregated = num.divide(congregated, congregated) with num.errstate(invalid='ignore'): i_labels = num.where(congregated[1:-1] == 1)[0]
return i_labels, indx def draw_visible_markers(self, markers, p, vcenter_projection): markers = [x for x in self.markers if ( x.get_tmin() < self.tmax and self.tmin < x.get_tmax())] markers = [ x for x in markers if x.kind in self.visible_marker_kinds] if len(markers) > 500: i_labels, i_markers = self.tobedrawn( markers, self.time_projection.get_out_range())
if len(i_markers) != 0: for i_m in i_markers: if i_m in i_labels: with_label = True else: with_label = False markers[i_m].draw(p, self.time_projection, vcenter_projection, with_label=with_label) m.draw(p, self.time_projection, vcenter_projection, with_label=True) def drawit(self, p, printmode=False, w=None, h=None): """This performs the actual drawing.""" self.timer_draw.start() self.set_gathering() if self.pile_has_changed: self.sortingmode_change() if self.menuitem_showboxes.isChecked(): self.determine_box_styles() self.pile_has_changed = False w = float(self.width()) if printmode: primary_color = (0, 0, 0) primary_color = pyrocko.plot.tango_colors['aluminium5'] ax_h = float(self.ax_height) vcenter_projection = Projection() self.track_to_screen.set_out_range(ax_h, h-ax_h) proj.set_out_range( self.track_to_screen(i+0.05), self.track_to_screen(i+1.-0.05)) track_projections[i] = proj vbottom_ax_projection.set_in_range(0, ax_h) self.tax.drawit(p, self.time_projection, vbottom_ax_projection) self.draw_trace_boxes( p, self.time_projection, track_projections) self.floating_marker.draw( p, self.time_projection, vcenter_projection) self.draw_visible_markers( self.markers, p, vcenter_projection) active_marker = self.get_active_event_marker() self.draw_visible_markers( [active_marker], p, vcenter_projection) self.draw_visible_markers( self.selected_markers(), p, vcenter_projection) p.setPen(primary_pen) font.setBold(True) axannotfont.setPointSize(8) label_bg = qg.QBrush(qg.QColor(255, 255, 255, 100)) processed_traces = self.prepare_cutout2( self.tmin, self.tmax, trace_selector=self.trace_selector, degap=self.menuitem_degap.isChecked(), demean=self.menuitem_demean.isChecked()) color_lookup = dict( [(k, i) for (i, k) in enumerate(self.color_keys)]) show_scales = self.menuitem_showscalerange.isChecked() \ or self.menuitem_showscaleaxis.isChecked() trackheight = self.track_to_screen(1.-0.05) \ - self.track_to_screen(0.05) nticks = max(3, min(nlinesavail * 0.5, 15)) nticks = 15 yscaler = pyrocko.plot.AutoScaler( no_exp_interval=(-3, 2), approx_ticks=nticks, snap=show_scales and not self.menuitem_showscaleaxis.isChecked()) data_ranges = pyrocko.trace.minmax( processed_traces, key=self.scaling_key, mode=self.scaling_base) self.old_data_ranges = data_ranges data_ranges.update(self.old_data_ranges) self.apply_scaling_hooks(data_ranges) if gt not in self.key_to_row: continue if itrack not in track_projections: continue trace_to_itrack[trace] = itrack self.track_to_nslc_ids[itrack] = set() self.track_to_nslc_ids[itrack].add(trace.nslc_id) track_scaling_keys[itrack] = set() track_scaling_keys[itrack].add(scaling_key) color = pyrocko.plot.color( color_lookup[self.color_gather(trace)]) if k not in track_scaling_colors \ track_scaling_colors[k] = color track_scaling_colors[k] = primary_color
# y axes, zero lines ymin, ymax, yinc = yscaler.make_scale( trace_projections[itrack, scaling_key] = \ uoffnext = uoff c = qg.QColor(*track_scaling_colors[ itrack, scaling_key]) pen.setColor(c) ny_annot = int( math.floor(ymax/yinc) - math.ceil(ymin/yinc)) + 1 line = qc.QLineF( umax-10-uoff, v, umax-uoff, v) if iy_annot == ny_annot - 1 \ and iexp != 0: sexp = ' × ' \ '10<sup>%i</sup>' % iexp sexp = '' lab = Label( p, umax-20-uoff, v, '%s%s' % (snum, sexp), label_bg=None, anchor='MR', font=axannotfont, color=c) uoffnext = max( lab.rect.width()+30., uoffnext) umax_zeroline = \ umax - 20 \ - lab.rect.width() - 10 \ - uoff else: if not self.menuitem_showboxes\ .isChecked(): qpoints = make_QPolygonF( [umax-20-uoff, umax-10-uoff, umax-10-uoff, umax-20-uoff], [vmax, vmax, vmin, vmin]) p.drawPolyline(qpoints)
snum = num_to_html(ymin) labmin = Label( p, umax-15-uoff, vmax, snum, label_bg=None, anchor='BR', font=axannotfont, color=c)
annot_labels.append(labmin) snum = num_to_html(ymax) labmax = Label( p, umax-15-uoff, vmin, snum, label_bg=None, anchor='TR', font=axannotfont, color=c)
annot_labels.append(labmax)
for lab in (labmin, labmax): uoffnext = max( lab.rect.width()+10., uoffnext) p.drawLine(line) uoff = uoffnext if trace not in trace_to_itrack: continue trace_projection = trace_projections[ itrack, scaling_key] vdata = trace_projection(trace.get_ydata()) udata_max = float(self.time_projection( udata = num.linspace(udata_min, udata_max, vdata.size) qpoints = make_QPolygonF(udata, vdata) vmin, vmax = trace_projection.get_out_range() trackrect = qc.QRectF(umin, vmin, umax-umin, vmax-vmin) p.setClipRect(trackrect) color = pyrocko.plot.color( p.setPen(pen) p.drawPolyline(qpoints) self.floating_marker.draw_trace( self, p, trace, self.time_projection, trace_projection, 1.0) if marker.get_tmin() < self.tmax \ and self.tmin < marker.get_tmax(): marker.draw_trace( self, p, trace, self.time_projection, trace_projection, 1.0) p.setPen(primary_pen) p.setClipRect(0, 0, w, h) p.setPen(primary_pen) trackheight = self.track_to_screen(1.-0.05) \ break
font.setPointSize(font.pointSize()-1) plabel = ' '.join( draw_label(p, lx, ly, plabel, label_bg, 'ML') lab.draw() self.timer_draw.stop() def see_data_params(self):
min_deltat = self.content_deltat_range()[0]
# determine padding and downampling requirements if self.lowpass is not None: deltat_target = 1./self.lowpass * 0.25 ndecimate = min( 50, max(1, int(round(deltat_target / min_deltat)))) tpad = 1./self.lowpass * 2. else: ndecimate = 1 tpad = min_deltat*5.
if self.highpass is not None: tpad = max(1./self.highpass * 2., tpad)
nsee_points_per_trace = 5000*10 tsee = ndecimate*nsee_points_per_trace*min_deltat
return ndecimate, tpad, tsee def clean_update(self): self.old_processed_traces = None self.update() tpad = max(tpad, 1.0/f) if snuffling._post_process_hook_enabled \ or snuffling._pre_process_hook_enabled:
tpad = max(tpad, snuffling.get_tpad()) return tpad def prepare_cutout2( self, tmin, tmax, trace_selector=None, degap=True, demean=True, nmax=6000): if self.pile.is_empty(): return [] nmax = self.visible_length self.timer_cutout.start() min_deltat_w_decimate = min_deltat_wo_decimate / 32. min_deltat_allow = min_deltat_w_decimate min_deltat_allow = math.exp( int(math.floor(math.log(min_deltat_allow)))) tmax_ = tmax
tmax = math.ceil(tmax/tlen) * tlen ads = self.menuitem_allowdownsampling.isChecked() tpad = max(tpad, tsee)
vec = ( tmin, tmax, tpad, trace_selector, degap, demean, self.lowpass, self.highpass, fft_filtering, lphp, min_deltat_allow, self.rotate, self.shown_tracks_range, ads, self.pile.get_update_count()) if (self.old_vec and self.old_vec[0] <= vec[0] and vec[1] <= self.old_vec[1] and vec[2:] == self.old_vec[2:] and not (self.reloaded or self.menuitem_watch.isChecked()) and self.old_processed_traces is not None): processed_traces = self.old_processed_traces
self.old_vec = vec processed_traces = [] if self.pile.deltatmax >= min_deltat_allow: return gr.deltatmax >= min_deltat_allow return tr.deltat >= min_deltat_allow \ and trace_selector(tr) else: def trace_selectorx(tr): return tr.deltat >= min_deltat_allow for traces in self.pile.chopper( tmin=tmin, tmax=tmax, tpad=tpad, want_incomplete=True, degap=degap, maxgap=gap_lap_tolerance, maxlap=gap_lap_tolerance, keep_current_files_open=True, group_selector=group_selector, trace_selector=trace_selectorx, accessor_id=id(self), snap=(math.floor, math.ceil), include_last=True): if (tr.meta and tr.meta.get('tabu', False)): tr.set_ydata(y - num.mean(y)) traces = self.pre_process_hooks(traces) for trace in traces: if not (trace.meta and trace.meta.get('tabu', False)): if self.lowpass is not None \ or self.highpass is not None: it = num.arange( detr_data, m, b = detrend( it, trace.get_ydata()) trace.set_ydata(detr_data) freqs, fdata = trace.spectrum( pad_to_pow2=True, tfade=None) nfreqs = fdata.size key = (trace.deltat, nfreqs) resps.append(but( order=4, corner=self.lowpass, type='low')) resps.append(but( order=4, corner=self.highpass, type='high')) self.tf_cache[key] = \ resp.evaluate(freqs) filtered_data = num.fft.irfft( fdata*self.tf_cache[key] )[:trace.data_len()] retrended_data = retrend( it, filtered_data, m, b) trace.set_ydata(retrended_data)
else: if ads and self.lowpass is not None: while trace.deltat \ < min_deltat_wo_decimate:
trace.downsample(2, demean=False) if not lphp and ( self.lowpass is not None and self.highpass is not None and self.lowpass < fmax and self.highpass < fmax and self.highpass < self.lowpass):
trace.bandpass( 2, self.highpass, self.lowpass) if self.lowpass is not None: if self.lowpass < 0.5/trace.deltat: trace.lowpass( 4, self.lowpass, demean=False) if self.highpass is not None: if self.lowpass is None \ or self.highpass \ < self.lowpass:
if self.highpass < \ 0.5/trace.deltat: trace.highpass( 4, self.highpass, demean=False) processed_traces.append(trace) if self.rotate != 0.0: phi = self.rotate/180.*math.pi cphi = math.cos(phi) sphi = math.sin(phi) for a in processed_traces: for b in processed_traces: if (a.network == b.network and a.station == b.station and a.location == b.location and ((a.channel.lower().endswith('n') and b.channel.lower().endswith('e')) or (a.channel.endswith('1') and b.channel.endswith('2'))) and abs(a.deltat-b.deltat) < a.deltat*0.001 and abs(a.tmin-b.tmin) < a.deltat*0.01 and len(a.get_ydata()) == len(b.get_ydata())):
aydata = a.get_ydata()*cphi+b.get_ydata()*sphi bydata = -a.get_ydata()*sphi+b.get_ydata()*cphi a.set_ydata(aydata) b.set_ydata(bydata) processed_traces = self.post_process_hooks(processed_traces) self.old_processed_traces = processed_traces ctrace = trace.chop( tmin_-trace.deltat*4., tmax_+trace.deltat*4., inplace=False)
except pyrocko.trace.NoData: continue if ctrace.data_len() < 2: continue chopped_traces.append(ctrace) return chopped_traces if snuffling._pre_process_hook_enabled: traces = snuffling.pre_process_hook(traces) return traces if snuffling._post_process_hook_enabled: traces = snuffling.post_process_hook(traces) return traces def visible_length_change(self, ignore=None): for menuitem, vlen in self.menuitems_visible_length: if menuitem.isChecked(): self.visible_length = vlen def scaling_base_change(self, ignore=None): for menuitem, scaling_base in self.menuitems_scaling_base: if menuitem.isChecked(): self.scaling_base = scaling_base self.scaling_key = scaling_key hook(data_ranges) self.scaling_hooks[k] = hook def remove_scaling_hook(self, k): del self.scaling_hooks[k] def remove_scaling_hooks(self): self.scaling_hooks = {} def s_sortingmode_change(self, ignore=None): for menuitem, valfunc in self.menuitems_ssorting: if menuitem.isChecked(): self._ssort = valfunc
self.sortingmode_change() self.set_gathering(gather, order, color) self.sortingmode_change_time = time.time() self.update() self.update() if self.highpass and self.lowpass \ and self.highpass >= self.lowpass:
self.message = 'Corner frequency of highpass larger than ' \ 'corner frequency of lowpass! I will now ' \ 'deactivate the highpass.'
self.update_status() if oldmess is not None: self.update_status() def gain_change(self, value, ignore): self.gain = value self.update() def rot_change(self, value, ignore): self.rotate = value self.update() def set_selected_markers(self, markers): '''Set a list of markers selected
:param markers: list of markers m.set_selected(True) self.update() marker.set_selected(False) def animate_picking(self): point = self.mapFromGlobal(qg.QCursor.pos()) self.update_picking(point.x(), point.y(), doshift=True) return self.track_to_nslc_ids.get(itrack, []) self.emit_selected_markers() self.floating_marker = None def start_picking(self, ignore): point = self.mapFromGlobal(qg.QCursor.pos()) self.picking.setGeometry( t = self.time_projection.rev(point.x()) self.floating_marker.set_selected(True) self.picking_timer.timeout.connect( self.animate_picking) self.picking_timer.start() if mouset < self.tmin or mouset > self.tmax: if mouset < self.tmin: dt = -(self.tmin - mouset) else: dt = mouset - self.tmax ddt = self.tmax-self.tmin dt = max(dt, -ddt/10.) dt = min(dt, ddt/10.) x0 = self.time_projection(self.picking_down[0]) x0 = min(x0, x) tmin, tmax = ( self.time_projection.rev(x0), self.time_projection.rev(x0+w)) tmin, tmax = ( max(working_system_time_range[0], tmin), min(working_system_time_range[1], tmax)) p1 = self.mapToGlobal(qc.QPoint(x0, 0)) self.picking.setGeometry( p1.x(), p1.y(), max(w, 1), self.height()) self.floating_marker.set(nslc_ids, tmin, tmax) if dt != 0.0 and doshift: self.interrupt_following() self.set_time_range(self.tmin+dt, self.tmax+dt) self.update() def update_status(self): point = self.mapFromGlobal(qg.QCursor.pos()) if not is_working_time(mouse_t): return tmi, tma = ( self.floating_marker.tmin, self.floating_marker.tmax) tt, ms = gmtime_x(tmi) message = mystrftime( fmt='Pick: %Y-%m-%d %H:%M:%S .%r', tt=tt, milliseconds=ms) else: srange = '%g s' % (tma-tmi) message = mystrftime( fmt='Start: %Y-%m-%d %H:%M:%S .%r Length: '+srange, tt=tt, milliseconds=ms) tt, ms = gmtime_x(mouse_t) message = mystrftime(fmt=None, tt=tt, milliseconds=ms) else: message = self.message sb.showMessage(message) def set_sortingmode_change_delay_time(self, dt): self.sortingmode_change_delay_time = dt return ( self.sortingmode_change_delay_time is not None and now - self.sortingmode_change_time < self.sortingmode_change_delay_time) self.visible_marker_kinds = tuple(kinds) def following(self): return self.follow_timer is not None \ and not self.following_interrupted() self.interactive_range_change_time = time.time() def following_interrupted(self, now=None): if now is None: now = time.time() return now - self.interactive_range_change_time \ < self.interactive_range_change_delay_time self.follow_timer.timeout.connect( self.interactive_range_change_time = 0.0 self.interactive_range_change_time = 0.0 def follow_update(self): rnow = time.time() if self.follow_lapse is None: now = rnow else: now = self.follow_started + (rnow - self.follow_started) \ * self.follow_lapse
if self.following_interrupted(rnow): return self.set_time_range( now-self.follow_time-self.follow_tshift, now-self.follow_tshift)
self.update() if self.follow_timer is not None: self.window().close() self.remove_snuffling(snuffling) self.return_tag = return_tag def set_error_message(self, key, value): if value is None: if key in self.error_messages: del self.error_messages[key] else: self.error_messages[key] = value pass line = str(text) command = toks[0].lower() quick_filter_commands = { 'n': '%s.*.*.*', 's': '*.%s.*.*', 'l': '*.*.%s.*', 'c': '*.*.*.%s'} if command in quick_filter_commands: if len(toks) >= 2: patterns = [ quick_filter_commands[toks[0]] % pat for pat in toks[1:]] self.set_quick_filter_patterns(patterns, line) else: self.set_quick_filter_patterns(None)
self.update() patterns = [toks[1]] elif len(toks) >= 3: x = { 'n': '%s.*.*.*', 's': '*.%s.*.*', 'l': '*.*.%s.*', 'c': '*.*.*.%s'}
if toks[1] in x: patterns.extend( x[toks[1]] % tok for tok in toks[2:]) self.add_blacklist_pattern(pattern) self.remove_blacklist_pattern(pattern) self.clear_blacklist() clearit = True self.update() kinds = self.all_marker_kinds kinds.append(int(x)) except Exception: pass self.set_visible_marker_kinds(kinds) self.set_visible_marker_kinds(()) self.update() error = 'wrong number of arguments' vmin, vmax = [ pyrocko.model.float_or_none(x) for x in toks[-2:]] d[k] = d[k][0], vmax if len(toks) == 1: self.remove_scaling_hooks() upd(data_ranges, k, vmin, vmax) self.set_scaling_hook('_', hook) elif len(toks) == 4: pattern = toks[1]
def hook(data_ranges): for k in pyrocko.util.match_nslcs( pattern, list(data_ranges.keys())):
upd(data_ranges, k, vmin, vmax)
self.set_scaling_hook(pattern, hook) m = re.match( r'^\d\d\d\d(-\d\d(-\d\d( \d\d(:\d\d' tlen = 60 self.go_to_time(t, tlen=tlen)
elif re.match(r'^\d\d:\d\d(:\d\d(\.\d+)?)?$', arg): supl = '00:00:00' if len(supl) > len(arg): arg = arg + supl[-(len(supl)-len(arg)):] tmin, tmax = self.get_time_range() sdate = pyrocko.util.time_to_str( tmin/2.+tmax/2., format='%Y-%m-%d') t = pyrocko.util.str_to_time(sdate + ' ' + arg) self.go_to_time(t)
else: self.go_to_event_by_name(arg)
else: raise PileViewerMainException( 'No such command: %s' % command) hideit = False return clearit, hideit, error return PileViewerMain
GLPileViewerMain = MakePileViewerMainClass(qgl.QGLWidget)
class LineEditWithAbort(qw.QLineEdit): history_up = qc.pyqtSignal() elif key_event.key() == qc.Qt.Key_Down: elif key_event.key() == qc.Qt.Key_Up: self.history_up.emit() return qw.QLineEdit.keyPressEvent(self, key_event)
class PileViewer(qw.QFrame): '''PileViewerMain + Controls + Inputline''' def __init__( self, pile, ntracks_shown_max=20, use_opengl=False, panel_parent=None, *args): qw.QFrame.__init__(self, *args) if use_opengl: self.viewer = GLPileViewerMain( pile, ntracks_shown_max=ntracks_shown_max, panel_parent=panel_parent) self.viewer = PileViewerMain( pile, ntracks_shown_max=ntracks_shown_max, panel_parent=panel_parent) layout.setSpacing(0) self.setFrameShadow(qw.QFrame.Sunken) self.input_area.setLayout(ia_layout) self.inputline.returnPressed.connect( self.inputline.editingFinished.connect( self.inputline.aborted.connect( self.inputline_aborted) self.inputline.history_down.connect( self.inputline.history_up.connect( lambda: self.step_through_history(-1)) self.inputline.textEdited.connect( self.inputline_changed) self.history = None self.inputline_error_str = None self.inputline_error.hide() layout.addWidget(self.viewer, 1, 0) self.progressbars = pb self.scrollbar.valueChanged.connect( self.scrollbar_changed) self.block_scrollbar_changes = False self.viewer.want_input.connect( self.viewer.tracks_range_changed.connect( self.viewer.pile_has_changed_signal.connect( self.viewer.about_to_close.connect( self.save_inputline_history) def get_progressbars(self): return self.progressbars self.load_inputline_history() self.inputline.selectAll() self.inputline_error.show() self.inputline_error.hide() self.inputline_clear_error() clearit, hideit, error = self.viewer.inputline_finished(line) self.inputline_set_error(error) line = line.strip() self.history.append(line) if clearit: self.inputline.clear() else: self.inputline.blockSignals(False) self.input_area.hide() self.hist_ind = len(self.history) def inputline_aborted(self): self.input_area.hide() def save_inputline_history(self): ''' Save input line history to "$HOME/.pyrocko/.snuffler_history.pf" if not self.history: return f.write('%s\n' % c) def load_inputline_history(self): ''' Load input line history from "$HOME/.pyrocko/.snuffler_history.pf" f.write('\n') self.history = [l.strip() for l in f.readlines()] self.hist_ind = len(self.history) def step_through_history(self, ud=1): ''' Step through input line history and set the input line text. ''' n = len(self.history) self.hist_ind += ud self.hist_ind %= (n + 1) if len(self.history) != 0 and self.hist_ind != n: self.inputline.setText(self.history[self.hist_ind]) else: self.inputline.setText('') pass if self.block_scrollbar_changes: return self.scrollbar.blockSignals(False) def scrollbar_changed(self, value): self.block_scrollbar_changes = True ilo = value ihi = ilo + self.scrollbar.pageStep() self.viewer.set_tracks_range((ilo, ihi)) self.block_scrollbar_changes = False self.update_contents() frame.setLayout(layout) self.lowpass_control.setup( self.highpass_control.setup( self.rot_control.setup('Rotate [deg]:', -180., 180., 0., 3) self.lowpass_control.valchange.connect( self.highpass_control.valchange.connect( self.gain_control.valchange.connect( self.rot_control.valchange.connect( self.viewer.rot_change) for icontrol, control in enumerate(( self.highpass_control, self.lowpass_control, self.gain_control, self.rot_control)): layout.addWidget(widget, icontrol, iwidget) spacer = qw.QSpacerItem( layout.addItem(spacer, 4, 0, 1, 3) return frame editor.get_marker_model().dataChanged.connect( return editor self.highpass_control.set_range(minfreq, maxfreq) self.viewer.setup_snufflings() return self.viewer def update_contents(self): self.viewer.update() def get_pile(self): return self.viewer.get_pile() |