# http://pyrocko.org - GPLv3 # # The Pyrocko Developers, 21st Century # ---|P------/S----------~Lg----------
else: polarity_symbols = {1: '+', -1: '-', None: '', 0: '0'}
return int(s)
tt, ms = gmtime_x(timestamp) return mystrftime(None, tt, ms)
''' General purpose marker GUI element and base class for :py:class:`EventMarker` and :py:class:`PhaseMarker`.
:param nslc_ids: list of (network, station, location, channel) tuples (may contain wildcards) :param tmin: start time :param tmax: end time :param kind: (optional) integer to distinguish groups of markers (color-coded) '''
def from_string(line):
def fail(): raise MarkerParseError( 'Unable to create marker from string: "%s"' % line)
def parsedate(ymd, hms, sfs): return calendar.timegm( time.strptime(ymd+' '+hms, '%Y-%m-%d %H:%M:%S')) + float(sfs)
try: toks = line.split() if len(toks) in (4, 5): tmin = parsedate(*toks[:3]) tmax = tmin
elif len(toks) in (8, 9): tmin = parsedate(*toks[:3]) tmax = parsedate(*toks[3:6])
else: fail()
if len(toks) in (5, 9): kind = int(toks[-2]) else: kind = int(toks[-1])
nslc_ids = [] if len(toks) in (5, 9): for snslc in toks[-1].split(','): nslc = snslc.split('.') if len(nslc) != 4: fail()
nslc_ids.append(tuple(nslc))
except MarkerParseError: fail()
return Marker(nslc_ids, tmin, tmax, kind=kind)
'''Static method to write marker objects to file.
:param markers: list of :py:class:`Marker` objects :param fn: filename as string :param fdigits: number of decimal digits to use for sub-second time strings (default 3) ''' else:
def load_markers(fn): ''' Static method to load markers from file.
:param filename: filename as string :returns: list of :py:class:`Marker`, :py:class:`EventMarker` or :py:class:`PhaseMarker` objects ''' f.seek(0) for iline, line in enumerate(f): line = str(line.decode('ascii')) sline = line.strip() if not sline or sline.startswith('#'): continue try: m = Marker.from_string(sline) markers.append(m)
except MarkerParseError: logger.warning( 'Invalid marker definition in line %i of file "%s"' % (iline+1, fn))
f.close()
else:
else: logger.warning('Unsupported Markers File Version')
'aluminium4', 'aluminium5', 'aluminium6')]
'scarletred1', 'scarletred2', 'scarletred3', 'chameleon1', 'chameleon2', 'chameleon3', 'skyblue1', 'skyblue2', 'skyblue3', 'orange1', 'orange2', 'orange3', 'plum1', 'plum2', 'plum3', 'chocolate1', 'chocolate2', 'chocolate3')]
'''Set ``nslc_ids``, start time and end time of :py:class:`Marker`
:param nslc_ids: list or set of (network, station, location, channel) tuples :param tmin: start time :param tmax: end time '''
'''Set kind of :py:class:`Marker`
:param kind: (optional) integer to distinguish groups of markers (color-coded) ''' self.kind = kind
'''Get *start time* of :py:class:`Marker`''' return self.tmin
'''Get *end time* of :py:class:`Marker`''' return self.tmax
'''Get marker's network-station-location-channel pattern.
:returns: list or set of (network, station, location, channel) tuples
The network, station, location, or channel strings may contain wildcard expressions. '''
return self.selected
self.selected = state
'''See documentation of :py:func:`pyrocko.util.match_nslc`''' patterns = ['.'.join(x[:3]) for x in self.nslc_ids] return util.match_nslc(patterns, nsl)
'''See documentation of :py:func:`pyrocko.util.match_nslc`''' patterns = ['.'.join(x) for x in self.nslc_ids] return util.match_nslc(patterns, nslc)
'''If one *nslc_id* defines this marker return this id. If more than one *nslc_id* is defined in the :py:class:`Marker`s *nslc_ids* raise :py:exc:`MarkerOneNSLCRequired`.''' if len(self.nslc_ids) != 1: raise MarkerOneNSLCRequired()
return list(self.nslc_ids)[0]
return ''
''' Get a copy of this marker. ''' return copy.deepcopy(self)
def __str__(self): traces = ','.join(['.'.join(nslc_id) for nslc_id in self.nslc_ids]) st = myctime if self.tmin == self.tmax: return '%s %i %s' % (st(self.tmin), self.kind, traces) else: return '%s %s %g %i %s' % ( st(self.tmin), st(self.tmax), self.tmax-self.tmin, self.kind, traces)
t, format='%Y-%m-%d %H:%M:%S.'+'%iFRAC' % fdigits)
def parse_attributes(vals):
nslc_ids = [] else: [tuple(nslc_id.split('.')) for nslc_id in traces.split(',')])
def from_attributes(vals):
def cl(x): return colorlist[(self.kind*3+x) % len(colorlist)]
if self.selected: return cl(1)
if self.alerted: return cl(1)
return cl(2)
self, p, time_projection, y_projection, draw_line=True, draw_triangle=False, **kwargs):
from .qt_compat import qc, qg from . import util as gui_util
if self.selected or self.alerted or not self.nslc_ids:
color = self.select_color(self.color_b) pen = qg.QPen(qg.QColor(*color)) pen.setWidth(2) linepen = qg.QPen(pen) if self.selected or self.alerted: linepen.setStyle(qc.Qt.CustomDashLine) pat = [5., 3.] linepen.setDashPattern(pat) if self.alerted and not self.selected: linepen.setColor(qg.QColor(150, 150, 150))
s = 9. utriangle = gui_util.make_QPolygonF( [-0.577*s, 0., 0.577*s], [0., 1.*s, 0.]) ltriangle = gui_util.make_QPolygonF( [-0.577*s, 0., 0.577*s], [0., -1.*s, 0.])
def drawline(t): u = time_projection(t) v0, v1 = y_projection.get_out_range() line = qc.QLineF(u, v0, u, v1) p.drawLine(line)
def drawtriangles(t): u = time_projection(t) v0, v1 = y_projection.get_out_range() t = qg.QPolygonF(utriangle) t.translate(u, v0) p.drawConvexPolygon(t) t = qg.QPolygonF(ltriangle) t.translate(u, v1) p.drawConvexPolygon(t)
if draw_line or self.selected or self.alerted: p.setPen(linepen) drawline(self.tmin) drawline(self.tmax)
if draw_triangle: pen.setStyle(qc.Qt.SolidLine) pen.setJoinStyle(qc.Qt.MiterJoin) pen.setWidth(2) p.setPen(pen) p.setBrush(qg.QColor(*color)) drawtriangles(self.tmin)
self, viewer, p, tr, time_projection, track_projection, gain, outline_label=False):
from .qt_compat import qc, qg from . import util as gui_util
if self.nslc_ids and not self.match_nslc(tr.nslc_id): return
color = self.select_color(self.color_b) pen = qg.QPen(qg.QColor(*color)) pen.setWidth(2) p.setPen(pen) p.setBrush(qc.Qt.NoBrush)
def drawpoint(t, y): u = time_projection(t) v = track_projection(y) rect = qc.QRectF(u-2, v-2, 4, 4) p.drawRect(rect)
def drawline(t): u = time_projection(t) v0, v1 = track_projection.get_out_range() line = qc.QLineF(u, v0, u, v1) p.drawLine(line)
try: snippet = tr.chop( self.tmin, self.tmax, inplace=False, include_last=True, snap=(math.ceil, math.floor))
vdata = track_projection(gain*snippet.get_ydata()) udata_min = float( time_projection(snippet.tmin)) udata_max = float( time_projection(snippet.tmin+snippet.deltat*(vdata.size-1))) udata = num.linspace(udata_min, udata_max, vdata.size) qpoints = gui_util.make_QPolygonF(udata, vdata) pen.setWidth(1) p.setPen(pen) p.drawPolyline(qpoints) pen.setWidth(2) p.setPen(pen) drawpoint(*tr(self.tmin, clip=True, snap=math.ceil)) drawpoint(*tr(self.tmax, clip=True, snap=math.floor))
except trace.NoData: pass
color = self.select_color(self.color_b) pen = qg.QPen(qg.QColor(*color)) pen.setWidth(2) p.setPen(pen)
drawline(self.tmin) drawline(self.tmax)
label = self.get_label() if label: label_bg = qg.QBrush(qg.QColor(255, 255, 255))
u = time_projection(self.tmin) v0, v1 = track_projection.get_out_range() if outline_label: du = -7 else: du = -5 gui_util.draw_label( p, u+du, v0, label, label_bg, 'TR', outline=outline_label)
if self.tmin == self.tmax: try: drawpoint(self.tmin, tr.interpolate(self.tmin))
except IndexError: pass
return None
self, event=None, phasename=None, polarity=None, automatic=None, incidence_angle=None, takeoff_angle=None):
if isinstance(self, PhaseMarker): return
self.__class__ = PhaseMarker self._event = event self._phasename = phasename self._polarity = polarity self._automatic = automatic self._incidence_angle = incidence_angle self._takeoff_angle = takeoff_angle if self._event: self._event_hash = event.get_hash() self._event_time = event.time else: self._event_hash = None self._event_time = None
if isinstance(self, EventMarker): return
if isinstance(self, PhaseMarker): self.convert_to_marker()
self.__class__ = EventMarker self._event = model.Event(lat, lon, time=self.tmin, name='Event') self._event_hash = self._event.get_hash() self._active = False self.tmax = self.tmin self.nslc_ids = []
""" An EventMarker is a GUI element representing a seismological event
:param event: A :py:class:`pyrocko.model.Event` object containing meta information of a seismological event :param kind: (optional) integer to distinguish groups of markers :param event_hash: (optional) hash code of event (see: :py:meth:`pyrocko.model.Event.get_hash`) """
else: return self._event.get_hash()
self._active = active
t = [] mag = self._event.magnitude if mag is not None: t.append('M%3.1f' % mag)
reg = self._event.region if reg is not None: t.append(reg)
nam = self._event.name if nam is not None: t.append(nam)
s = ' '.join(t) if not s: s = '(Event)' return s
Marker.draw( self, p, time_projection, y_projection, draw_line=False, draw_triangle=True)
if with_label: self.draw_label(p, time_projection, y_projection)
from .qt_compat import qg from . import util as gui_util
u = time_projection(self.tmin) v0, v1 = y_projection.get_out_range() label_bg = qg.QBrush(qg.QColor(255, 255, 255)) gui_util.draw_label( p, u, v0-10., self.label(), label_bg, 'CB', outline=self._active)
'''Return an instance of the :py:class:`pyrocko.model.Event` associated to this :py:class:`EventMarker`'''
gain): pass
ev = self.get_event() evs = [] for k in 'magnitude lat lon depth name region catalog'.split(): if ev.__dict__[k] is not None and ev.__dict__[k] != '': if k == 'depth': sv = '%g km' % (ev.depth * 0.001) else: sv = '%s' % ev.__dict__[k] evs.append('%s = %s' % (k, sv))
return ', '.join(evs)
e.get_hash(), e.lat, e.lon, e.depth, e.magnitude, e.catalog, e.name, e.region])
def from_attributes(vals):
vals[1:] + ['None']) str_to_float_or_none(x) for x in vals[5:9]] str_to_str_or_none(x) for x in vals[9:]] lat, lon, time=tmin, name=name, depth=depth, magnitude=magnitude, region=region, catalog=catalog) e, kind, event_hash=str_to_str_or_none(vals[4]))
''' A PhaseMarker is a GUI-element representing a seismological phase arrival
:param nslc_ids: list of (network, station, location, channel) tuples (may contain wildcards) :param tmin: start time :param tmax: end time :param kind: (optional) integer to distinguish groups of markers (color-coded) :param event: a :py:class:`pyrocko.model.Event` object containing meta information of a seismological event :param event_hash: (optional) hash code of event (see: :py:meth:`pyrocko.model.Event.get_hash`) :param event_time: (optional) time of the associated event :param phasename: (optional) name of the phase associated with the marker :param polarity: (optional) polarity of arriving phase :param automatic: (optional) :param incident_angle: (optional) incident angle of phase :param takeoff_angle: (optional) take off angle of phase ''' self, nslc_ids, tmin, tmax, kind=0, event=None, event_hash=None, event_time=None, phasename=None, polarity=None, automatic=None, incidence_angle=None, takeoff_angle=None):
gain):
Marker.draw_trace( self, viewer, p, tr, time_projection, track_projection, gain, outline_label=( self._event is not None and self._event == viewer.get_active_event()))
t = [] if self._phasename is not None: t.append(self._phasename) if self._polarity is not None: t.append(self.get_polarity_symbol())
if self._automatic: t.append('@')
return ''.join(t)
'''Return an instance of the :py:class:`pyrocko.model.Event` associated to this :py:class:`EventMarker`'''
else: return None else:
else:
return self._phasename
self._phasename = phasename
raise ValueError('polarity has to be 1, -1, 0 or None')
return polarity_symbols.get(self._polarity, '')
return self._polarity
del self._event del self._event_hash del self._phasename del self._polarity del self._automatic del self._incidence_angle del self._takeoff_angle self.__class__ = Marker
toks = [] for k in 'incidence_angle takeoff_angle polarity'.split(): v = getattr(self, '_' + k) if v is not None: toks.append('%s = %s' % (k, v))
return ', '.join(toks)
elif self._event_time: et = self._st(self._event_time, fdigits).split()
self.get_event_hash(), et[0], et[1], self._phasename, self._polarity, self._automatic])
t, format='%Y-%m-%d %H:%M:%S.'+'%iFRAC' % fdigits)
def from_attributes(vals): else: nbasicvals = 4 vals[1:1+nbasicvals])
else: event_time = None
event_hash=event_hash, event_time=event_time, phasename=phasename, polarity=polarity, automatic=automatic)
''' Load markers from file.
:param filename: filename as string :returns: list of :py:class:`Marker` Objects '''
''' Save markers to file.
:param markers: list of :py:class:`Marker` Objects :param filename: filename as string :param fdigits: number of decimal digits to use for sub-second time strings '''
''' Reassociate phases to events after import from markers file. '''
elif t is not None and t in time_to_events: marker.set_event(time_to_events[t]) marker.set_event_hash(None) |