Seismic traces

Pyrocko can be used to handle and process seismic waveform data. The following examples describe usage of the module to read and write seismological waveform data and the pyrocko.trace module which offers basic signal processing functionality.

Supported seismological waveform formats are:

format format identifier load save note
MiniSEED mseed yes yes  
SAC sac yes yes [1]
SEG Y rev1 segy some    
SEISAN seisan, seisan.l, seisan.b yes   [2]
KAN kan yes   [3]
YAFF yaff yes yes [4]
ASCII Table text   yes [5]
GSE1 gse1 some    
GSE2 gse2 yes yes  
DATACUBE datacube yes    
SUDS suds some    


[1]For SAC files, the endianness is guessed. Additional header information is stored in the Trace’s meta attribute.
[2]Seisan waveform files can be in little (seisan.l) or big endian (seisan.b) format. seisan currently is an alias for seisan.l.
[3]The KAN file format has only been seen once by the author, and support for it may be removed again.
[4]YAFF is an in-house, experimental file format, which should not be released into the wild.
[5]ASCII tables with two columns (time and amplitude) are output - meta information will be lost.

Load, filter and save

Read a test file test.mseed with, containing a three component seismogram, apply Butterworth lowpass filter to the seismograms and dump the results to a new file with

from pyrocko import io

traces = io.load('test.mseed')

for tr in traces:
    tr.lowpass(4, 0.02)   # 4th order, 0.02 Hz, 'filtered.mseed')

Other filtering methods are pyrocko.trace.Trace.highpass() and pyrocko.trace.Trace.bandpass().

If more than a single file should be read, it is much more convenient to use Pyrocko’s pyrocko.pile module instead of See section Dataset management - The pile for examples on how to use it.

Visual inspection of traces

To visualize a single Trace object, use its snuffle() method. To look at a list of traces, use the pyrocko.trace.snuffle() function. If you want to see the contents of a pile, the pyrocko.pile.Pile.snuffle() method is your friend. Alternatively, you could of course save the traces to file and use the standalone Snuffler - seismogram browser and workbench to look at them.

from pyrocko import io, trace, pile

traces = io.load('test.mseed')
traces[0].snuffle() # look at a single trace
trace.snuffle(traces) # look at a bunch of traces

# do something with the traces:
new_traces = []
for tr in traces:
    new = tr.copy()
    # to allow the viewer to distinguish the traces

trace.snuffle(traces + new_traces)

# it is also possible to 'snuffle' a pile:
p = pile.make_pile(['test.mseed'])

If needed, station meta-information, event information, and marker objects can be passed into any of the snuffle() methods and functions using keyword arguments.

Creating a trace object from scratch

Creates two Trace objects, fills them with noise (using numpy.random.random()) and saves them with save() to a single or to split files. For each Trace object the station name is defined, the channel name, the sampling interval (0.5 s) and the time onset (tmin).


from pyrocko import trace, util, io
import numpy as num

nsamples = 100
tmin = util.str_to_time('2010-02-20 15:15:30.100')
data = num.random.random(nsamples)
t1 = trace.Trace(
    station='TEST', channel='Z', deltat=0.5, tmin=tmin, ydata=data)
t2 = trace.Trace(
    station='TEST', channel='N', deltat=0.5, tmin=tmin, ydata=data)

# all traces in one file[t1, t2], 'my_precious_traces.mseed')

# each file one channel[t1, t2], 'my_precious_trace_%(channel)s.mseed')

Extracting part of a trace (trimming)

Trimming is achieved with the chop() method. Here we cut 10 s from the beginning and the end of the example trace (test.mseed).


from __future__ import print_function
from pyrocko import io
from pyrocko.example import get_example_data


traces = io.load('test.mseed')
t = traces[0]
print('original:', t)

# extract a copy of a part of t
extracted = t.chop(t.tmin+10, t.tmax-10, inplace=False)
print('extracted:', extracted)

# in-place operation modifies t itself
t.chop(t.tmin+10, t.tmax-10)
print('modified:', t)

Time shifting a trace

This example demonstrates how to time shift a trace by a given relative time or to a given absolute onset time with pyrocko.trace.Trace.shift().

from pyrocko import io, util

traces = io.load('test.mseed')
tr = traces[0]

# shift by 10 seconds backward in time

# shift to a new absolute onset time
tmin_new = util.str_to_time('2009-04-06 01:32:42.000')
tr.shift(tmin_new - tr.tmin)

Resampling a trace

Example for downsampling a trace in a file to a sampling rate with pyrocko.trace.Trace.downsample_to().

from pyrocko import io, trace

tr1 = io.load('test.mseed')[0]

tr2 = tr1.copy()

# make them distinguishable

# visualize with Snuffler
trace.snuffle([tr1, tr2])

To overlay the traces in Snuffler, right-click the mouse button and

  • check ‘Subsort … (Grouped by Location)
  • uncheck ‘Show Boxes
  • check ‘Common Scale

Convert SAC to MiniSEED

A very basic SAC to MiniSEED converter:

Download convert_sac_mseed

#!/usr/bin/env python

from pyrocko import io
import sys

for filename in sys.argv[1:]:
    traces = io.load(filename, format='sac')
    if filename.lower().endswith('.sac'):
        out_filename = filename[:-4] + '.mseed'
        out_filename = filename + '.mseed', out_filename)

Convert MiniSEED to ASCII

An inefficient, non-portable, non-header-preserving, but simple, method to convert some MiniSEED traces to ASCII tables:

from pyrocko import io
from pyrocko.example import get_example_data

traces = io.load('test.mseed')

for it, t in enumerate(traces):
    with open('test-%i.txt' % it, 'w') as f:
        for tim, val in zip(t.get_xdata(), t.get_ydata()):
            f.write('%20f %20g\n' % (tim, val))


Finding the comparative misfits of mulitple traces

Three traces will be created, where one will be the used as a reference trace (rt). Using pyrocko.trace.Trace.misfit(), we can find the misfits of the other two traces (tt1 and tt2) in comparision to rt. Traces rt and tt1 will have the same y-data, so the misfit between them will be zero.


from pyrocko import trace
import numpy as num

# Let's create three traces: One trace as the reference (rt) and two as test
# traces (tt1 and tt2):
ydata1 = num.random.random(1000)
ydata2 = num.random.random(1000)
rt = trace.Trace(station='REF', ydata=ydata1)
candidate1 = trace.Trace(station='TT1', ydata=ydata1)
candidate2 = trace.Trace(station='TT2', ydata=ydata2)

# Define a fader to apply before fft.
taper = trace.CosFader(xfade=5)

# Define a frequency response to apply before performing the inverse fft.
# This can be basically any funtion, as long as it contains a function called
# *evaluate*, which evaluates the frequency response function at a given list
# of frequencies.
# Please refer to the :py:class:`FrequencyResponse` class or its subclasses for
# examples.
# However, we are going to use a butterworth low-pass filter in this example.
bw_filter = trace.ButterworthResponse(

# Combine all information in one misfit setup:
setup = trace.MisfitSetup(
    description='An Example Setup',

# Calculate misfits of each candidate against the reference trace:
for candidate in [candidate1, candidate2]:
    misfit = rt.misfit(candidate=candidate, setup=setup)
    print('misfit: %s, normalization: %s' % misfit)

# Finally, dump the misfit setup that has been used as a yaml file for later
# re-use:

If we wanted to reload our misfit setup, pyrocko.guts provides the iload_all() method for that purpose:

from pyrocko.guts import load
from pyrocko.trace import MisfitSetup

setup = load(filename='my_misfit_setup.txt')

# now we can change, for example, the domain:
setup.domain = 'frequency_domain'


Restitute to displacement using poles and zeros

Often we want to deconvolve instrument responses from seismograms. The method pyrocko.trace.Trace.transfer() implements a convolution with a transfer function in the frequency domain. This method takes as argument a transfer function object which ‘knows’ how to compute values of the transfer function at given frequencies. The trace module provides a few different transfer functions, but it is also possible to write a custom transfer function. For a transfer function given as poles and zeros, we can use instances of the class pyrocko.trace.PoleZeroResponse. There is also a class pyrocko.trace.InverseEvalrespResponse, which uses the common RESP files through the evalresp library.

Here is a complete example using a SAC pole-zero file (STS2-Generic.polezero.txt) to deconvolve the transfer function from an example seismogram:


from pyrocko import pz, io, trace
from pyrocko.example import get_example_data

# Download example data

# read poles and zeros from SAC format pole-zero file
zeros, poles, constant = pz.read_sac_zpk('STS2-Generic.polezero.txt')

# one more zero to convert from velocity->counts to displacement->counts

rest_sts2 = trace.PoleZeroResponse(

traces = io.load('test.mseed')
out_traces = list(traces)
for tr in traces:

    displacement = tr.transfer(
        1000.,                    # rise and fall of time window taper in [s]
        (0.001, 0.002, 5., 10.),  # frequency domain taper in [Hz]
        invert=True)              # to change to (counts->displacement)

    # change channel id, so we can distinguish the traces in a trace viewer.

    out_traces.append(displacement), 'displacement.mseed')

Restitute to displacement using SEED RESP response

In this examples we


import os

from pyrocko import io, trace, evalresp_ext
from pyrocko.example import get_example_data

# Get online data

traces = io.load('1989.072.evt.mseed')
out_traces = []
for tr in traces:
    respfn = tr.fill_template(

    if os.path.exists(respfn):

            resp = trace.InverseEvalresp(respfn, tr, target='dis')

            tr.extend(tr.tmin - 100., tr.tmax, fillmethod='repeat')

            displacement = tr.transfer(
                100.,  # rise and fall of time domain taper in [s]
                (0.005, 0.01, 1., 2.),  # frequency domain taper in [Hz]

            # change channel id, so we can distinguish the traces in a trace
            # viewer.


        except evalresp_ext.EvalrespError:
            pass, 'displacement.mseed')