1# http://pyrocko.org - GPLv3 

2# 

3# The Pyrocko Developers, 21st Century 

4# ---|P------/S----------~Lg---------- 

5 

6''' 

7This module provides basic compatibility between ObsPy and Pyrocko. 

8 

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`). 

13 

14With :func:`pyrocko.obspy_compat.plant` several new methods are attached to 

15Pyrocko and ObsPy classes. 

16 

17**Example, visualize ObsPy stream object with Snuffler:** 

18 

19.. code-block:: python 

20 

21 import obspy 

22 from pyrocko import obspy_compat 

23 obspy_compat.plant() 

24 

25 stream = obspy.read() # returns some example data 

26 stream.snuffle() 

27 

28-- *With best wishes to the ObsPy Team from the Pyrocko Developers!* 

29 

30.. note:: 

31 

32 This is an experimental module, the interface may still be changed. 

33 Feedback and discussion welcome! 

34 

35''' 

36 

37from __future__ import absolute_import 

38 

39 

40def to_pyrocko_trace(trace): 

41 ''' 

42 Convert ObsPy trace object to Pyrocko trace object. 

43 

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 

51 

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) 

61 

62 

63def to_pyrocko_traces(stream): 

64 ''' 

65 Convert ObsPy stream object to list of Pyrocko trace objects. 

66 

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 ''' 

72 

73 obspy_stream = stream 

74 

75 return [to_pyrocko_trace(obspy_trace) for obspy_trace in obspy_stream] 

76 

77 

78def to_pyrocko_events(catalog): 

79 ''' 

80 Convert ObsPy catalog object to list of Pyrocko event objects. 

81 

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 ''' 

88 

89 obspy_catalog = catalog 

90 

91 if obspy_catalog is None: 

92 return None 

93 

94 from pyrocko import model 

95 

96 events = [] 

97 for obspy_event in obspy_catalog: 

98 for origin in obspy_event.origins: 

99 

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)) 

107 

108 return events 

109 

110 

111def to_pyrocko_stations(inventory): 

112 ''' 

113 Convert ObsPy inventory to list of Pyrocko traces. 

114 

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 ''' 

122 

123 obspy_inventory = inventory 

124 

125 if obspy_inventory is None: 

126 return None 

127 

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 )) 

146 

147 return stations 

148 

149 

150def to_obspy_stream(pile): 

151 ''' 

152 Convert Pyrocko pile to ObsPy stream. 

153 

154 :param pile: 

155 :py:class:`pyrocko.pile.Pile` object 

156 :returns: 

157 :py:class:`obspy.Stream <obspy.core.stream.Stream>` object 

158 ''' 

159 

160 pyrocko_pile = pile 

161 

162 import obspy 

163 stream = obspy.Stream() 

164 stream.extend([to_obspy_trace(tr) for tr in pyrocko_pile.iter_all()]) 

165 return stream 

166 

167 

168def to_obspy_trace(trace): 

169 ''' 

170 Convert Pyrocko trace to ObsPy trace. 

171 

172 :param trace: 

173 :py:class:`pyrocko.trace.Trace` 

174 ''' 

175 import obspy 

176 

177 pyrocko_trace = trace 

178 

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 )) 

192 

193 return obspy_trace 

194 

195 

196def snuffle(stream_or_trace, inventory=None, catalog=None, **kwargs): 

197 ''' 

198 Explore ObsPy data with Snuffler. 

199 

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`. 

210 

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. 

215 

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. 

222 

223 See also :py:func:`fiddle` for a variant of this function returning 

224 an interactively modified ObsPy stream object. 

225 ''' 

226 

227 from pyrocko import trace 

228 import obspy 

229 

230 obspy_inventory = inventory 

231 obspy_catalog = catalog 

232 

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 

237 

238 events = to_pyrocko_events(obspy_catalog) 

239 stations = to_pyrocko_stations(obspy_inventory) 

240 

241 return trace.snuffle( 

242 to_pyrocko_traces(obspy_stream), 

243 events=events, 

244 stations=stations, 

245 want_markers=True, 

246 **kwargs) 

247 

248 

249class ObsPyStreamSnufflingLoader(object): 

250 

251 def __init__(self, obspy_stream): 

252 self.obspy_stream = obspy_stream 

253 

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) 

259 

260 def get_snuffling(self): 

261 return self.snuffling 

262 

263 

264def fiddle(stream_or_trace, inventory=None, catalog=None, **kwargs): 

265 ''' 

266 Manipulate ObsPy stream object interactively. 

267 

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`. 

278 

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). 

282 

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. 

287 

288 .. code:: 

289 

290 import obspy 

291 from pyrocko import obspy_compat 

292 

293 obspy_compat.plant() 

294 

295 stream = obspy.read() 

296 stream_filtered = stream.fiddle() # returns once window has been 

297 # closed 

298 ''' 

299 

300 from pyrocko import trace 

301 import obspy 

302 

303 obspy_inventory = inventory 

304 obspy_catalog = catalog 

305 

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 

310 

311 events = to_pyrocko_events(obspy_catalog) 

312 stations = to_pyrocko_stations(obspy_inventory) 

313 

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) 

319 

320 trace.snuffle( 

321 [], 

322 events=events, 

323 stations=stations, 

324 controls=False, 

325 launch_hook=launch_hook, 

326 **kwargs) 

327 

328 new_obspy_stream = snuffling_loader.get_snuffling().get_obspy_stream() 

329 

330 if isinstance(obspy_stream, obspy.Trace): 

331 return new_obspy_stream[0] 

332 else: 

333 return new_obspy_stream 

334 

335 

336def plant(): 

337 ''' 

338 Add conversion functions as methods to ObsPy and Pyrocko classes. 

339 

340 Methods added to ObsPy classes are: 

341 

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 +--------------------------------------+---------------------------------+ 

361 

362 Methods added to Pyrocko classes are: 

363 

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 ''' 

372 

373 import obspy 

374 obspy.Trace.to_pyrocko_trace = to_pyrocko_trace 

375 obspy.Trace.snuffle = snuffle 

376 obspy.Trace.fiddle = fiddle 

377 

378 obspy.Stream.to_pyrocko_traces = to_pyrocko_traces 

379 obspy.Stream.snuffle = snuffle 

380 obspy.Stream.fiddle = fiddle 

381 

382 obspy.core.event.Catalog.to_pyrocko_events = to_pyrocko_events 

383 obspy.core.inventory.inventory.Inventory.to_pyrocko_stations =\ 

384 to_pyrocko_stations 

385 

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 

390 

391 

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']