1# http://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
6'''
7This module provides basic compatibility between ObsPy and Pyrocko.
9The functions defined here can be used to translate back and forth some of the
10basic objects in Pyrocko and ObsPy. It also provides shortcuts to quickly look
11at ObsPy waveforms with the Pyrocko's :doc:`Snuffler </apps/snuffler/index>`
12application (:py:func:`snuffle`, :py:func:`fiddle`).
14With :func:`pyrocko.obspy_compat.plant` several new methods are attached to
15Pyrocko and ObsPy classes.
17**Example, visualize ObsPy stream object with Snuffler:**
19.. code-block:: python
21 import obspy
22 from pyrocko import obspy_compat
23 obspy_compat.plant()
25 stream = obspy.read() # returns some example data
26 stream.snuffle()
28-- *With best wishes to the ObsPy Team from the Pyrocko Developers!*
30.. note::
32 This is an experimental module, the interface may still be changed.
33 Feedback and discussion welcome!
35'''
37from __future__ import absolute_import
40def to_pyrocko_trace(trace):
41 '''
42 Convert ObsPy trace object to Pyrocko trace object.
44 :param trace:
45 :py:class:`obspy.Trace <obspy.core.trace.Trace>` object
46 :returns:
47 :py:class:`pyrocko.trace.Trace` object
48 '''
49 obspy_trace = trace
50 from pyrocko import trace
52 return trace.Trace(
53 str(obspy_trace.stats.network),
54 str(obspy_trace.stats.station),
55 str(obspy_trace.stats.location),
56 str(obspy_trace.stats.channel),
57 tmin=obspy_trace.stats.starttime.timestamp,
58 tmax=obspy_trace.stats.endtime.timestamp,
59 ydata=obspy_trace.data,
60 deltat=obspy_trace.stats.delta)
63def to_pyrocko_traces(stream):
64 '''
65 Convert ObsPy stream object to list of Pyrocko trace objects.
67 :param stream:
68 :py:class:`obspy.Stream <obspy.core.stream.Stream>` object
69 :returns:
70 list of :py:class:`pyrocko.trace.Trace` objects
71 '''
73 obspy_stream = stream
75 return [to_pyrocko_trace(obspy_trace) for obspy_trace in obspy_stream]
78def to_pyrocko_events(catalog):
79 '''
80 Convert ObsPy catalog object to list of Pyrocko event objects.
82 :param catalog:
83 :py:class:`obspy.Catalog <obspy.core.event.Catalog>` object
84 :returns:
85 list of :py:class:`pyrocko.model.Event` objects or ``None`` if catalog
86 is ``None``
87 '''
89 obspy_catalog = catalog
91 if obspy_catalog is None:
92 return None
94 from pyrocko import model
96 events = []
97 for obspy_event in obspy_catalog:
98 for origin in obspy_event.origins:
100 events.append(model.Event(
101 name='%s-%s' % (obspy_event.resource_id, origin.resource_id),
102 time=origin.time.timestamp,
103 lat=origin.latitude,
104 lon=origin.longitude,
105 depth=origin.depth,
106 region=origin.region))
108 return events
111def to_pyrocko_stations(inventory):
112 '''
113 Convert ObsPy inventory to list of Pyrocko traces.
115 :param inventory:
116 :py:class:`obspy.Inventory <obspy.core.inventory.inventory.Inventory>`
117 object
118 :returns:
119 list of :py:class:`pyrocko.model.Station` objects or ``None`` if
120 inventory is ``None``
121 '''
123 obspy_inventory = inventory
125 if obspy_inventory is None:
126 return None
128 from pyrocko import model
129 stations = []
130 for net in obspy_inventory.networks:
131 for sta in net.stations:
132 stations.append(
133 model.Station(
134 lat=sta.latitude,
135 lon=sta.longitude,
136 elevation=sta.elevation,
137 network=net.code,
138 station=sta.code,
139 location='',
140 channels=[
141 model.station.Channel(
142 name=cha.code,
143 azimuth=cha.azimuth,
144 dip=cha.dip) for cha in sta.channels]
145 ))
147 return stations
150def to_obspy_stream(pile):
151 '''
152 Convert Pyrocko pile to ObsPy stream.
154 :param pile:
155 :py:class:`pyrocko.pile.Pile` object
156 :returns:
157 :py:class:`obspy.Stream <obspy.core.stream.Stream>` object
158 '''
160 pyrocko_pile = pile
162 import obspy
163 stream = obspy.Stream()
164 stream.extend([to_obspy_trace(tr) for tr in pyrocko_pile.iter_all()])
165 return stream
168def to_obspy_trace(trace):
169 '''
170 Convert Pyrocko trace to ObsPy trace.
172 :param trace:
173 :py:class:`pyrocko.trace.Trace`
174 '''
175 import obspy
177 pyrocko_trace = trace
179 obspy_trace = obspy.Trace(
180 data=pyrocko_trace.ydata,
181 header=obspy.core.trace.Stats(
182 dict(
183 npts=len(pyrocko_trace.ydata),
184 network=pyrocko_trace.network,
185 station=pyrocko_trace.station,
186 location=pyrocko_trace.location,
187 channel=pyrocko_trace.channel,
188 delta=pyrocko_trace.deltat,
189 starttime=pyrocko_trace.tmin,
190 endtime=pyrocko_trace.tmax)
191 ))
193 return obspy_trace
196def snuffle(stream_or_trace, inventory=None, catalog=None, **kwargs):
197 '''
198 Explore ObsPy data with Snuffler.
200 :param stream_or_trace:
201 :py:class:`obspy.Stream <obspy.core.stream.Stream>` or
202 :py:class:`obspy.Trace <obspy.core.trace.Trace>` object
203 :param inventory:
204 :py:class:`obspy.Inventory <obspy.core.inventory.inventory.Inventory>`
205 object
206 :param catalog:
207 :py:class:`obspy.Catalog <obspy.core.event.Catalog>` object
208 :param kwargs:
209 extra arguments passed to :meth:`pyrocko.trace.Trace.snuffle`.
211 :returns:
212 ``(return_tag, markers)``, where ``return_tag`` is the a string to flag
213 how the Snuffler window has been closed and ``markers`` is a list of
214 :py:class:`pyrocko.gui.marker.Marker` objects.
216 This function displays an ObsPy stream object in Snuffler. It returns to
217 the caller once the window has been closed. The ``return_tag`` returned by
218 the function can be used as a primitive way to communicate a user decision
219 to the calling script. By default it returns the key pressed to close the
220 window (if any), either ``'q'`` or ``'x'``, but the value could be
221 customized when the exit is triggered from within a Snuffling.
223 See also :py:func:`fiddle` for a variant of this function returning
224 an interactively modified ObsPy stream object.
225 '''
227 from pyrocko import trace
228 import obspy
230 obspy_inventory = inventory
231 obspy_catalog = catalog
233 if isinstance(stream_or_trace, obspy.Trace):
234 obspy_stream = obspy.core.stream.Stream(traces=[stream_or_trace])
235 else:
236 obspy_stream = stream_or_trace
238 events = to_pyrocko_events(obspy_catalog)
239 stations = to_pyrocko_stations(obspy_inventory)
241 return trace.snuffle(
242 to_pyrocko_traces(obspy_stream),
243 events=events,
244 stations=stations,
245 want_markers=True,
246 **kwargs)
249class ObsPyStreamSnufflingLoader(object):
251 def __init__(self, obspy_stream):
252 self.obspy_stream = obspy_stream
254 def __call__(self, win):
255 from .snuffling import ObsPyStreamSnuffling
256 self.snuffling = ObsPyStreamSnuffling(obspy_stream=self.obspy_stream)
257 self.snuffling.setup()
258 win.pile_viewer.viewer.add_snuffling(self.snuffling, reloaded=True)
260 def get_snuffling(self):
261 return self.snuffling
264def fiddle(stream_or_trace, inventory=None, catalog=None, **kwargs):
265 '''
266 Manipulate ObsPy stream object interactively.
268 :param stream_or_trace:
269 :py:class:`obspy.Stream <obspy.core.stream.Stream>` or
270 :py:class:`obspy.Trace <obspy.core.trace.Trace>` object
271 :param inventory:
272 :py:class:`obspy.Inventory <obspy.core.inventory.inventory.Inventory>`
273 object
274 :param catalog:
275 :py:class:`obspy.Catalog <obspy.core.event.Catalog>` object
276 :param kwargs:
277 extra arguments passed to :meth:`pyrocko.trace.Trace.snuffle`.
279 :returns: :py:class:`obspy.Stream <obspy.core.stream.Stream>` object with
280 changes applied interactively (or :py:class:`obspy.Trace
281 <obspy.core.trace.Trace>` if called with a trace as first argument).
283 This function displays an ObsPy stream object in Snuffler like
284 :py:func:`snuffle`, but additionally adds a Snuffling panel to apply some
285 basic ObsPy signal processing to the contained traces. The applied changes
286 are handed back to the caller as a modified copy of the stream object.
288 .. code::
290 import obspy
291 from pyrocko import obspy_compat
293 obspy_compat.plant()
295 stream = obspy.read()
296 stream_filtered = stream.fiddle() # returns once window has been
297 # closed
298 '''
300 from pyrocko import trace
301 import obspy
303 obspy_inventory = inventory
304 obspy_catalog = catalog
306 if isinstance(stream_or_trace, obspy.Trace):
307 obspy_stream = obspy.core.stream.Stream(traces=[stream_or_trace])
308 else:
309 obspy_stream = stream_or_trace
311 events = to_pyrocko_events(obspy_catalog)
312 stations = to_pyrocko_stations(obspy_inventory)
314 snuffling_loader = ObsPyStreamSnufflingLoader(obspy_stream)
315 launch_hook = kwargs.pop('launch_hook', [])
316 if not isinstance(launch_hook, list):
317 launch_hook = [launch_hook]
318 launch_hook.append(snuffling_loader)
320 trace.snuffle(
321 [],
322 events=events,
323 stations=stations,
324 controls=False,
325 launch_hook=launch_hook,
326 **kwargs)
328 new_obspy_stream = snuffling_loader.get_snuffling().get_obspy_stream()
330 if isinstance(obspy_stream, obspy.Trace):
331 return new_obspy_stream[0]
332 else:
333 return new_obspy_stream
336def plant():
337 '''
338 Add conversion functions as methods to ObsPy and Pyrocko classes.
340 Methods added to ObsPy classes are:
342 +--------------------------------------+---------------------------------+
343 | class | methods |
344 +======================================+=================================+
345 | :py:class:`obspy.Trace` | :py:func:`to_pyrocko_trace` |
346 | +---------------------------------+
347 | | :py:func:`snuffle` |
348 | +---------------------------------+
349 | | :py:func:`fiddle` |
350 +--------------------------------------+---------------------------------+
351 | :py:class:`obspy.Stream` | :py:func:`to_pyrocko_traces` |
352 | +---------------------------------+
353 | | :py:func:`snuffle` |
354 | +---------------------------------+
355 | | :py:func:`fiddle` |
356 +--------------------------------------+---------------------------------+
357 | :py:class:`obspy.Catalog` | :py:func:`to_pyrocko_events` |
358 +--------------------------------------+---------------------------------+
359 | :py:class:`obspy.Inventory` | :py:func:`to_pyrocko_stations` |
360 +--------------------------------------+---------------------------------+
362 Methods added to Pyrocko classes are:
364 +--------------------------------------+---------------------------------+
365 | class | methods |
366 +======================================+=================================+
367 | :py:class:`pyrocko.trace.Trace` | :py:func:`to_obspy_trace` |
368 +--------------------------------------+---------------------------------+
369 | :py:class:`pyrocko.pile.Pile` | :py:func:`to_obspy_stream` |
370 +--------------------------------------+---------------------------------+
371 '''
373 import obspy
374 obspy.Trace.to_pyrocko_trace = to_pyrocko_trace
375 obspy.Trace.snuffle = snuffle
376 obspy.Trace.fiddle = fiddle
378 obspy.Stream.to_pyrocko_traces = to_pyrocko_traces
379 obspy.Stream.snuffle = snuffle
380 obspy.Stream.fiddle = fiddle
382 obspy.core.event.Catalog.to_pyrocko_events = to_pyrocko_events
383 obspy.core.inventory.inventory.Inventory.to_pyrocko_stations =\
384 to_pyrocko_stations
386 import pyrocko.trace
387 import pyrocko.pile
388 pyrocko.trace.Trace.to_obspy_trace = to_obspy_trace
389 pyrocko.pile.Pile.to_obspy_stream = to_obspy_stream
392__all__ = [
393 'to_pyrocko_trace',
394 'to_pyrocko_traces',
395 'to_pyrocko_events',
396 'to_pyrocko_stations',
397 'to_obspy_stream',
398 'to_obspy_trace',
399 'snuffle',
400 'fiddle',
401 'plant']