示例#1
0
 def dEmeter(self):
     if self.isMeter():
         return self.dE
     else:
         _, dEmeter = latlon_to_ne(self.llLat, self.llLon, self.llLat,
                                   self.llLon + self.dE)
     return dEmeter
示例#2
0
 def dNmeter(self):
     if self.isMeter():
         return self.dN
     else:
         dNmeter, _ = latlon_to_ne(self.llLat, self.llLon,
                                   self.llLat + self.dN, self.llLon)
     return dNmeter
示例#3
0
    def dEmeter(self):
        if self.isMeter():
            return self.dE

        _, dEmeter = latlon_to_ne(self.llLat, self.llLon, self.llLat,
                                  self.llLon + self.dE * self.cols)
        return dEmeter / self.cols
示例#4
0
 def dNmeter(self):
     if self.isMeter():
         return self.dN
     dNmeter, _ = latlon_to_ne(
         self.llLat, self.llLon, self.llLat + self.dN * self.rows, self.llLon
     )
     return dNmeter / self.rows
示例#5
0
文件: data.py 项目: chaoshunh/pinky
    def extract_labels(self, marker):
        if not self.labeled:
            return UNLABELED

        source = marker.get_event()
        n, e = orthodrome.latlon_to_ne(
            self.config.reference_target.lat, self.config.reference_target.lon,
            source.lat, source.lon)
        return (n, e, source.depth)
def to_cartesian(items):
    res = []
    latlon00 = ortho.Loc(0.,0.)
    for i, item in enumerate(items):

        y, x = ortho.latlon_to_ne(latlon00, item)
        depth = item.depth
        lat = item.lat/180.*num.pi
        res.append((x, y, -depth))
    return res
示例#7
0
def to_cartesian(items, reflatlon):
    res = defaultdict()
    for i, item in enumerate(items):

        y, x = ortho.latlon_to_ne(reflatlon, item)
        depth = item.depth
        elevation = item.elevation
        dz = elevation - depth
        lat = item.lat / 180. * num.pi
        z = r_earth + dz * num.sin(lat)
        res[item.nsl()[:2]] = (x, y, z)
    return res
示例#8
0
def to_cartesian(items, reflatlon):
    res = defaultdict()
    for i, item in enumerate(items):

        y, x = ortho.latlon_to_ne(reflatlon, item)
        depth = item.depth
        elevation = item.elevation
        dz = elevation - depth
        lat = item.lat/180.*num.pi
        z = r_earth+dz*num.sin(lat)
        res[item] = (x, y, z)
    return res
示例#9
0
    def testLocationObjects(self):
        class Dummy(object):
            def __init__(self, lat, lon, depth):
                self.lat = lat
                self.lon = lon
                self.depth = depth

        a0 = Location(lat=10., lon=12., depth=1100.)
        a1 = guts.clone(a0)
        a1.set_origin(lat=9., lon=11)

        b0 = Location(lat=11., lon=13., depth=2100.)
        b1 = guts.clone(b0)
        b1.set_origin(lat=9., lon=11)
        b2 = Dummy(b0.lat, b0.lon, b0.depth)

        dist_ab = orthodrome.distance_accurate50m(a0.lat, a0.lon, b0.lat,
                                                  b0.lon)

        azi_ab, bazi_ab = orthodrome.azibazi(a0.lat, a0.lon, b0.lat, b0.lon)

        def g_to_e(*args):
            return num.array(orthodrome.geodetic_to_ecef(*args))

        a_vec = g_to_e(a0.lat, a0.lon, -a0.depth)
        b_vec = g_to_e(b0.lat, b0.lon, -b0.depth)

        dist_3d_compare = math.sqrt(num.sum((a_vec - b_vec)**2))

        north_shift_compare, east_shift_compare = orthodrome.latlon_to_ne(
            a0.lat, a0.lon, b0.lat, b0.lon)

        for a in [a0, a1]:
            for b in [b0, b1, b2]:
                dist = a.distance_to(b)
                assert_allclose(dist, dist_ab)

                dist_3d = a.distance_3d_to(b)
                assert_allclose(dist_3d, dist_3d_compare, rtol=0.001)

                azi, bazi = a.azibazi_to(b)
                assert_allclose(azi % 360., azi_ab % 360., rtol=1e-2)
                assert_allclose(bazi % 360., bazi_ab % 360., rtol=1e-2)

                north_shift, east_shift = a.offset_to(b)
                assert_allclose((north_shift, east_shift),
                                (north_shift_compare, east_shift_compare),
                                rtol=5e-3)

        for x, y in [(a0, a1), (b0, b1), (b0, b2), (b1, b2)]:
            dist = x.distance_to(y)
            assert_allclose(dist, 0.0)
示例#10
0
def to_cartesian(items, latref=None, lonref=None):
    res = []
    latref = latref or 0.
    lonref = lonref or 0.
    latlon00 = ortho.Loc(latref, lonref)
    for i, item in enumerate(items):

        y, x = ortho.latlon_to_ne(latlon00, item)
        depth = item.depth * 1000
        lat = item.lat / 180. * num.pi
        res.append((x, y, -depth))
    # vielleicht doch als array?!
    #res = num.array(res)
    #res = res.T
    return res
def to_cartesian(items, latref=None, lonref=None):
    res = []
    latref = latref or 0.
    lonref = lonref or 0.
    latlon00 = ortho.Loc(latref, lonref)
    for i, item in enumerate(items):

        y, x = ortho.latlon_to_ne(latlon00, item)
        depth = item.depth *1000
        lat = item.lat/180.*num.pi
        res.append((x, y, -depth))
    # vielleicht doch als array?!
    #res = num.array(res) 
    #res = res.T
    return res
    def call(self):
        self.cleanup()

        viewer = self.get_viewer()

        master = viewer.get_active_event()

        if master is None:
            self.fail('no master event selected')

        stations = list(viewer.stations.values())
        stations.sort(key=lambda s: (s.network,s.station))

        if not stations:
            self.fail('no station information available')

        # gather events to be processed

        events = []
        for m in viewer.markers:
            if isinstance(m, EventMarker):
                if m.kind == 0:
                    events.append( m.get_event() )

        events.sort(key=lambda ev: ev.time)

        event_to_number = {}
        for iev, ev in enumerate(events):
            event_to_number[ev] = iev

        if self.model_select.startswith('Global'):
            model_key = 'global'
        else:
            model_key = master.lat, master.lon

        if model_key != self.model_key:
            if self.model_select.startswith('Global'):
                self.model = cake.load_model()
            else:
                latlon = master.lat, master.lon
                profile = crust2x2.get_profile(*latlon)
                profile.set_layer_thickness(crust2x2.LWATER, 0.0)
                self.model = cake.LayeredModel.from_scanlines(
                        cake.from_crust2x2_profile(profile))

            self.model_key = model_key

        phases = { 
                'P': ([ cake.PhaseDef(x) for x in 'P p'.split() ], 'Z'),
                'S': ([ cake.PhaseDef(x) for x in 'S s'.split() ], 'NE'),
            }

        phasenames = phases.keys()
        phasenames.sort()

        # synthetic arrivals and ray geometry for master event
        master_depth = master.depth
        if self.master_depth_km is not None:
            master_depth = self.master_depth_km * km

        tt = {}
        g = {}
        for iphase, phasename in enumerate(phasenames):
            for istation, station in enumerate(stations):
                dist = orthodrome.distance_accurate50m(master, station)
                azi = orthodrome.azimuth(master, station)

                arrivals = self.model.arrivals(
                        phases=phases[phasename][0], 
                        distances=[ dist*cake.m2d ],
                        zstart = master_depth,
                        zstop = 0.0)

                if arrivals:
                    first = arrivals[0]
                    tt[station.network, station.station, phasename] = first.t

                    takeoff = first.takeoff_angle()
                    u = first.path.first_straight().u_in(first.endgaps)

                    g[iphase, istation] = num.array([
                            math.cos(azi*d2r) * math.sin(takeoff*d2r) * u,
                            math.sin(azi*d2r) * math.sin(takeoff*d2r) * u,
                            math.cos(takeoff*d2r) * u ])
        
        # gather picks for each event

        for ev in events:
            picks = {}
            for m2 in viewer.markers:
                if isinstance(m2, PhaseMarker) and m2.kind == 0:
                    if m2.get_event() == ev:
                        net, sta, _, _ = m2.one_nslc()
                        picks[net,sta,m2.get_phasename()] = (m2.tmax + m2.tmin) / 2.0

            ev.picks = picks

        # time corrections for extraction windows

        dataobs = []
        datasyn = []
        for phasename in phasenames:
            for station in stations:
                nsp = station.network, station.station, phasename
                datasyn.append(tt.get(nsp,None))
                for ev in events:
                    if nsp in ev.picks: 
                        ttobs = ev.picks[nsp] - ev.time
                    else:
                        ttobs = None

                    dataobs.append(ttobs)

        ttsyn = num.array(datasyn, dtype=num.float).reshape((
            len(phasenames),
            len(stations)))

        ttobs = num.array(dataobs, dtype=num.float).reshape((
            len(phasenames),
            len(stations),
            len(events)))

        ttres = ttobs - ttsyn[:,:,num.newaxis]
        tt_corr_event = num.nansum( ttres, axis=1) /  \
                num.nansum( num.isfinite(ttres), axis=1 )

        tt_corr_event = num.where(num.isfinite(tt_corr_event), tt_corr_event, 0.)

        ttres -= tt_corr_event[:,num.newaxis,:]
        tt_corr_station = num.nansum( ttres, axis=2) /  \
                num.nansum( num.isfinite(ttres), axis=2 )

        tt_corr_station = num.where(num.isfinite(tt_corr_station), tt_corr_station, 0.)

        ttres -= tt_corr_station[:,:, num.newaxis]

        tevents_raw = num.array( [ ev.time for ev in events ] )

        tevents_corr = tevents_raw + num.mean(tt_corr_event, axis=0)

        # print timing information

        print 'timing stats'

        for iphasename, phasename in enumerate(phasenames):
            data = []
            for ev in events:
                iev = event_to_number[ev]
                for istation, station in enumerate(stations):
                    nsp = station.network, station.station, phasename
                    if nsp in tt and nsp in ev.picks: 
                        tarr = ev.time + tt[nsp]
                        tarr_ec = tarr + tt_corr_event[iphasename, iev]
                        tarr_ec_sc = tarr_ec + tt_corr_station[iphasename, istation]
                        tobs = ev.picks[nsp]

                        data.append((tobs-tarr, tobs-tarr_ec, tobs-tarr_ec_sc))

            if data:

                data = num.array(data, dtype=num.float).T

                print 'event %10s %3s %3i %15.2g %15.2g %15.2g' % (
                        (ev.name, phasename, data.shape[1]) + 
                            tuple( num.mean(num.abs(x)) for x in data ))
            else:
                print 'event %10s %3s no picks' % (ev.name, phasename)

        # extract and preprocess waveforms

        tpad = 0.0
        for f in self.corner_highpass, self.corner_lowpass:
            if f is not None:
                tpad = max(tpad, 1.0/f)


        pile = self.get_pile()
        waveforms = {}
        for ev in events:
            iev = event_to_number[ev]
            markers = []
            for iphasename, phasename in enumerate(phasenames):
                for istation, station in enumerate(stations):
                    nsp = station.network, station.station, phasename
                    if nsp in tt:
                        tarr = ev.time + tt[nsp]
                        nslcs = [ ( station.network, station.station, '*', '*' ) ]
                        marker = PhaseMarker( nslcs, tarr, tarr, 1, event=ev,
                                phasename=phasename)
                        markers.append(marker)

                        tarr2 = tarr + tt_corr_station[iphasename, istation] + \
                                tt_corr_event[iphasename, iev]

                        marker = PhaseMarker( nslcs, tarr2, tarr2, 2, event=ev,
                                phasename=phasename)

                        markers.append(marker)

                        tmin = tarr2+self.tstart
                        tmax = tarr2+self.tend

                        marker = PhaseMarker( nslcs, 
                                tmin, tmax, 3, event=ev,
                                phasename=phasename)

                        markers.append(marker)

                        trs = pile.all(tmin, tmax, tpad=tpad, trace_selector=
                                lambda tr: tr.nslc_id[:2] == nsp[:2], 
                                want_incomplete=False)

                        trok = []
                        for tr in trs:
                            if num.all(tr.ydata[0] == tr.ydata):
                                continue

                            if self.corner_highpass:
                                tr.highpass(4, self.corner_highpass)
                            if self.corner_lowpass:
                                tr.lowpass(4, self.corner_lowpass)



                            tr.chop(tmin, tmax)
                            tr.set_location(ev.name)
                            #tr.shift( - (tmin - master.time) )
                            
                            if num.all(num.isfinite(tr.ydata)):
                                trok.append(tr)

                        waveforms[nsp+(iev,)] = trok

            self.add_markers(markers)

        def get_channel(trs, cha):
            for tr in trs:
                if tr.channel == cha:
                    return tr
            return None

        nevents = len(events)
        nstations = len(stations)
        nphases = len(phasenames)

        # correlate waveforms

        coefs = num.zeros((nphases, nstations, nevents, nevents))
        coefs.fill(num.nan)
        tshifts = coefs.copy()
        tshifts_picked = coefs.copy()
        for iphase, phasename in enumerate(phasenames):
            for istation, station in enumerate(stations):
                nsp = station.network, station.station, phasename

                for a in events:
                    ia = event_to_number[a]
                    for b in events:
                        ib = event_to_number[b]

                        if ia == ib:
                            continue

                        if nsp in a.picks and nsp in b.picks:
                            tshifts_picked[iphase,istation,ia,ib] = \
                                    b.picks[nsp] - a.picks[nsp]
                     
                        wa = waveforms[nsp+(ia,)]
                        wb = waveforms[nsp+(ib,)]

                        channels = list(set([ tr.channel for tr in wa + wb ]))
                        channels.sort()

                        tccs = []
                        for cha in channels:
                            if cha[-1] not in phases[phasename][1]:
                                continue

                            ta = get_channel(wa, cha)
                            tb = get_channel(wb, cha)
                            if ta is None or tb is None:
                                continue

                            tcc = trace.correlate(ta,tb, mode='full', normalization='normal',
                                    use_fft=True)
                            
                            tccs.append(tcc)
                        
                        if not tccs:
                            continue

                        tc = None
                        for tcc in tccs:
                            if tc is None:
                                tc = tcc
                            else:
                                tc.add(tcc)

                        tc.ydata *= 1./len(tccs)

                        tmid = tc.tmin*0.5 + tc.tmax*0.5
                        tlen = (tc.tmax - tc.tmin)*0.5
                        tc_cut = tc.chop(tmid-tlen*0.5, tmid+tlen*0.5, inplace=False)

                        tshift, coef = tc_cut.max()

                        if (tshift < tc.tmin + 0.5*tc.deltat or
                                tc.tmax - 0.5*tc.deltat < tshift):
                            continue

                        coefs[iphase,istation,ia,ib] = coef
                        tshifts[iphase,istation,ia,ib] = tshift

                        if self.show_correlation_traces:
                            tc.shift(master.time - (tc.tmax + tc.tmin)/2.)
                            self.add_trace(tc)


        #tshifts = tshifts_picked

        coefssum_sta = num.nansum(coefs, axis=2) / num.sum(num.isfinite(coefs), axis=2)
        csum_sta = num.nansum(coefssum_sta, axis=2) / num.sum(num.isfinite(coefssum_sta), axis=2)

        for iphase, phasename in enumerate(phasenames):
            for istation, station in enumerate(stations):
                print 'station %-5s %s %15.2g' % (station.station, phasename, csum_sta[iphase,istation])

        coefssum = num.nansum(coefs, axis=1) / num.sum(num.isfinite(coefs), axis=1)
        csumevent = num.nansum(coefssum, axis=2) / num.sum(num.isfinite(coefssum), axis=2)
        above = num.where(num.isfinite(coefs), coefs >= self.min_corr, 0)

        csumabove = num.sum(num.sum(above, axis=1), axis=2)

        coefssum = num.ma.masked_invalid(coefssum)

        print 'correlation stats'

        for iphase, phasename in enumerate(phasenames):
            for ievent, event in enumerate(events):
                print 'event %10s %3s %8i %15.2g' % (
                        event.name, phasename, 
                        csumabove[iphase,ievent], csumevent[iphase,ievent])

        # plot event correlation matrix

        fframe = self.figure_frame()
        fig = fframe.gcf()

        for iphase, phasename in enumerate(phasenames):

            p = fig.add_subplot(1,nphases,iphase+1)
            p.set_xlabel('Event number')
            p.set_ylabel('Event number')
            mesh = p.pcolormesh(coefssum[iphase])
            cb = fig.colorbar(mesh, ax=p)
            cb.set_label('Max correlation coefficient')

        if self.save:
            fig.savefig(self.output_filename(dir='correlation.pdf'))

        fig.canvas.draw()


        # setup and solve linear system

        data = []
        rows = []
        weights = []
        for iphase in xrange(nphases):
            for istation in xrange(nstations):
                for ia in xrange(nevents):
                    for ib in xrange(ia+1,nevents):
                        k = iphase, istation, ia, ib
                        w = coefs[k]
                        if not num.isfinite(tshifts[k]) \
                                or not num.isfinite(w) or w < self.min_corr:
                            continue

                        row = num.zeros(nevents*4)
                        row[ia*4:ia*4+3] = g[iphase,istation]
                        row[ia*4+3] = -1.0
                        row[ib*4:ib*4+3] = -g[iphase,istation]
                        row[ib*4+3] = 1.0
                        
                        weights.append(w)

                        rows.append(row)
                        data.append(tshifts[iphase,istation,ia,ib])

        nsamp = len(data)

        for i in range(4):
            row = num.zeros(nevents*4)
            row[i::4] = 1.
            rows.append(row)
            data.append(0.0)

        if self.fix_depth:
            for ievent in range(nevents):
                row = num.zeros(nevents*4)
                row[ievent*4+2] = 1.0 
                rows.append(row)
                data.append(0.0)

        a = num.array(rows, dtype=num.float)
        d = num.array(data, dtype=num.float)
        w = num.array(weights, dtype=num.float)

        if self.weighting == 'equal':
            w[:nsamp] = 1.0
        elif self.weighting == 'linear':
            pass
        elif self.weighting == 'quadratic':
            w[:nsamp] = w[:nsamp]**2

        a[:nsamp,:] *= w[:,num.newaxis]
        d[:nsamp] *= w[:nsamp]

        x, residuals, rank, singular = num.linalg.lstsq(a,d)

        x0 = num.zeros(nevents*4)
        x0[3::4] = tevents_corr
        mean_abs_residual0 = num.mean( 
                num.abs((num.dot(a[:nsamp], x0) - d[:nsamp])/w[:nsamp]))
        
        mean_abs_residual = num.mean( 
                num.abs((num.dot(a[:nsamp],x) - d[:nsamp])/w[:nsamp]))

        print mean_abs_residual0, mean_abs_residual

        # distorted solutions

        npermutations = 100
        noiseamount = mean_abs_residual
        xdistorteds = []
        for i in range(npermutations):
            dnoisy = d.copy()
            dnoisy[:nsamp] += num.random.normal(size=nsamp)*noiseamount*w[:nsamp]
            xdistorted, residuals, rank, singular = num.linalg.lstsq(a,dnoisy)
            xdistorteds.append(xdistorted)

            mean_abs_residual = num.mean(num.abs(num.dot(a,xdistorted)[:nsamp] - dnoisy[:nsamp]))

        tmean = num.mean([ e.time for e in events ])

        north = x[0::4]
        east = x[1::4]
        down = x[2::4] 
        etime = x[3::4] + tmean

        def plot_range(x):
            mi, ma = num.percentile(x, [10., 90.])
            ext = (ma-mi)/5.
            mi -= ext
            ma += ext
            return mi, ma

        lat, lon = orthodrome.ne_to_latlon(master.lat, master.lon, north, east)

        events_out = []
        for ievent, event in enumerate(events):
            event_out = model.Event(time=etime[ievent],
                    lat=lat[ievent],
                    lon=lon[ievent],
                    depth=down[ievent] + master_depth,
                    name = event.name)

            mark = EventMarker(event_out, kind=4)
            self.add_marker(mark)
            events_out.append(event_out)

        model.Event.dump_catalog(events_out, 'events.relocated.txt')

        # plot results

        ned_orig = []
        for event in events:
            n, e = orthodrome.latlon_to_ne(master, event)
            d = event.depth

            ned_orig.append((n,e,d))

        ned_orig = num.array(ned_orig)

        ned_orig[:,0] -= num.mean(ned_orig[:,0])
        ned_orig[:,1] -= num.mean(ned_orig[:,1])
        ned_orig[:,2] -= num.mean(ned_orig[:,2])

        north0, east0, down0 = ned_orig.T

        north2, east2, down2, time2 = num.hstack(xdistorteds).reshape((-1,4)).T

        fframe = self.figure_frame()
        fig = fframe.gcf()

        color_sym = (0.1,0.1,0.0)
        color_scat = (0.3,0.5,1.0,0.2)

        d = u'\u0394 '

        if not self.fix_depth:
            p = fig.add_subplot(2,2,1, aspect=1.0)
        else:
            p = fig.add_subplot(1,1,1, aspect=1.0)

        mi_north, ma_north = plot_range(north)
        mi_east, ma_east = plot_range(east)
        mi_down, ma_down = plot_range(down)

        p.set_xlabel(d+'East [km]')
        p.set_ylabel(d+'North [km]')
        p.plot(east2/km, north2/km, '.', color=color_scat, markersize=2)
        p.plot(east/km, north/km, '+', color=color_sym)
        p.plot(east0/km, north0/km, 'x', color=color_sym)
        p0 = p

        for i,ev in enumerate(events):
            p.text(east[i]/km, north[i]/km, ev.name, clip_on=True)

        if not self.fix_depth:


            p = fig.add_subplot(2,2,2, sharey=p0, aspect=1.0)
            p.set_xlabel(d+'Depth [km]')
            p.set_ylabel(d+'North [km]')
            p.plot(down2/km, north2/km, '.', color=color_scat, markersize=2)
            p.plot(down/km, north/km, '+', color=color_sym)
            for i,ev in enumerate(events):
                p.text(down[i]/km, north[i]/km, ev.name, clip_on=True)


            p1 = p

            p = fig.add_subplot(2,2,3, sharex=p0, aspect=1.0)
            p.set_xlabel(d+'East [km]')
            p.set_ylabel(d+'Depth [km]')
            p.plot(east2/km, down2/km, '.', color=color_scat, markersize=2)
            p.plot(east/km, down/km, '+', color=color_sym)
            for i,ev in enumerate(events):
                p.text(east[i]/km, down[i]/km, ev.name, clip_on=True)


            p.invert_yaxis()
            p2 = p

        p0.set_xlim(mi_east/km, ma_east/km)
        p0.set_ylim(mi_north/km, ma_north/km)

        if not self.fix_depth:
            p1.set_xlim(mi_down/km, ma_down/km)
            p2.set_ylim(mi_down/km, ma_down/km)
            
        if self.save:
            fig.savefig(self.output_filename(dir='locations.pdf'))

        fig.canvas.draw()
示例#13
0
    def call(self):
        self.cleanup()

        viewer = self.get_viewer()

        master = viewer.get_active_event()

        if master is None:
            self.fail('no master event selected')

        stations = list(viewer.stations.values())
        stations.sort(key=lambda s: (s.network, s.station))

        if not stations:
            self.fail('no station information available')

        # gather events to be processed

        events = []
        for m in viewer.markers:
            if isinstance(m, EventMarker):
                if m.kind == 0:
                    events.append(m.get_event())

        events.sort(key=lambda ev: ev.time)

        event_to_number = {}
        for iev, ev in enumerate(events):
            event_to_number[ev] = iev

        if self.model_select.startswith('Global'):
            model_key = 'global'
        else:
            model_key = master.lat, master.lon

        if model_key != self.model_key:
            if self.model_select.startswith('Global'):
                self.model = cake.load_model()
            else:
                latlon = master.lat, master.lon
                profile = crust2x2.get_profile(*latlon)
                profile.set_layer_thickness(crust2x2.LWATER, 0.0)
                self.model = cake.LayeredModel.from_scanlines(
                    cake.from_crust2x2_profile(profile))

            self.model_key = model_key

        phases = {
            'P': ([cake.PhaseDef(x) for x in 'P p'.split()], 'Z'),
            'S': ([cake.PhaseDef(x) for x in 'S s'.split()], 'NE'),
        }

        phasenames = list(phases.keys())
        phasenames.sort()

        # synthetic arrivals and ray geometry for master event
        master_depth = master.depth
        if self.master_depth_km is not None:
            master_depth = self.master_depth_km * km

        tt = {}
        g = {}
        for iphase, phasename in enumerate(phasenames):
            for istation, station in enumerate(stations):
                dist = orthodrome.distance_accurate50m(master, station)
                azi = orthodrome.azimuth(master, station)

                arrivals = self.model.arrivals(phases=phases[phasename][0],
                                               distances=[dist * cake.m2d],
                                               zstart=master_depth,
                                               zstop=0.0)

                if arrivals:
                    first = arrivals[0]
                    tt[station.network, station.station, phasename] = first.t

                    takeoff = first.takeoff_angle()
                    u = first.path.first_straight().u_in(first.endgaps)

                    g[iphase, istation] = num.array([
                        math.cos(azi * d2r) * math.sin(takeoff * d2r) * u,
                        math.sin(azi * d2r) * math.sin(takeoff * d2r) * u,
                        math.cos(takeoff * d2r) * u
                    ])

        # gather picks for each event

        for ev in events:
            picks = {}
            for m2 in viewer.markers:
                if isinstance(m2, PhaseMarker) and m2.kind == 0:
                    if m2.get_event() == ev:
                        net, sta, _, _ = m2.one_nslc()
                        picks[net, sta,
                              m2.get_phasename()] = (m2.tmax + m2.tmin) / 2.0

            ev.picks = picks

        # time corrections for extraction windows

        dataobs = []
        datasyn = []
        for phasename in phasenames:
            for station in stations:
                nsp = station.network, station.station, phasename
                datasyn.append(tt.get(nsp, None))
                for ev in events:
                    if nsp in ev.picks:
                        ttobs = ev.picks[nsp] - ev.time
                    else:
                        ttobs = None

                    dataobs.append(ttobs)

        ttsyn = num.array(datasyn, dtype=num.float).reshape(
            (len(phasenames), len(stations)))

        ttobs = num.array(dataobs, dtype=num.float).reshape(
            (len(phasenames), len(stations), len(events)))

        ttres = ttobs - ttsyn[:, :, num.newaxis]
        tt_corr_event = num.nansum( ttres, axis=1) /  \
                num.nansum( num.isfinite(ttres), axis=1 )

        tt_corr_event = num.where(num.isfinite(tt_corr_event), tt_corr_event,
                                  0.)

        ttres -= tt_corr_event[:, num.newaxis, :]
        tt_corr_station = num.nansum( ttres, axis=2) /  \
                num.nansum( num.isfinite(ttres), axis=2 )

        tt_corr_station = num.where(num.isfinite(tt_corr_station),
                                    tt_corr_station, 0.)

        ttres -= tt_corr_station[:, :, num.newaxis]

        tevents_raw = num.array([ev.time for ev in events])

        tevents_corr = tevents_raw + num.mean(tt_corr_event, axis=0)

        # print timing information

        print('timing stats')

        for iphasename, phasename in enumerate(phasenames):
            data = []
            for ev in events:
                iev = event_to_number[ev]
                for istation, station in enumerate(stations):
                    nsp = station.network, station.station, phasename
                    if nsp in tt and nsp in ev.picks:
                        tarr = ev.time + tt[nsp]
                        tarr_ec = tarr + tt_corr_event[iphasename, iev]
                        tarr_ec_sc = tarr_ec + tt_corr_station[iphasename,
                                                               istation]
                        tobs = ev.picks[nsp]

                        data.append(
                            (tobs - tarr, tobs - tarr_ec, tobs - tarr_ec_sc))

            if data:

                data = num.array(data, dtype=num.float).T

                print('event %10s %3s %3i %15.2g %15.2g %15.2g' %
                      ((ev.name, phasename, data.shape[1]) +
                       tuple(num.mean(num.abs(x)) for x in data)))
            else:
                print('event %10s %3s no picks' % (ev.name, phasename))

        # extract and preprocess waveforms

        tpad = 0.0
        for f in self.corner_highpass, self.corner_lowpass:
            if f is not None:
                tpad = max(tpad, 1.0 / f)

        pile = self.get_pile()
        waveforms = {}
        for ev in events:
            iev = event_to_number[ev]
            markers = []
            for iphasename, phasename in enumerate(phasenames):
                for istation, station in enumerate(stations):
                    nsp = station.network, station.station, phasename
                    if nsp in tt:
                        tarr = ev.time + tt[nsp]
                        nslcs = [(station.network, station.station, '*', '*')]
                        marker = PhaseMarker(nslcs,
                                             tarr,
                                             tarr,
                                             1,
                                             event=ev,
                                             phasename=phasename)
                        markers.append(marker)

                        tarr2 = tarr + tt_corr_station[iphasename, istation] + \
                                tt_corr_event[iphasename, iev]

                        marker = PhaseMarker(nslcs,
                                             tarr2,
                                             tarr2,
                                             2,
                                             event=ev,
                                             phasename=phasename)

                        markers.append(marker)

                        tmin = tarr2 + self.tstart
                        tmax = tarr2 + self.tend

                        marker = PhaseMarker(nslcs,
                                             tmin,
                                             tmax,
                                             3,
                                             event=ev,
                                             phasename=phasename)

                        markers.append(marker)

                        trs = pile.all(tmin,
                                       tmax,
                                       tpad=tpad,
                                       trace_selector=lambda tr: tr.nslc_id[:2]
                                       == nsp[:2],
                                       want_incomplete=False)

                        trok = []
                        for tr in trs:
                            if num.all(tr.ydata[0] == tr.ydata):
                                continue

                            if self.corner_highpass:
                                tr.highpass(4, self.corner_highpass)
                            if self.corner_lowpass:
                                tr.lowpass(4, self.corner_lowpass)

                            tr.chop(tmin, tmax)
                            tr.set_location(ev.name)
                            #tr.shift( - (tmin - master.time) )

                            if num.all(num.isfinite(tr.ydata)):
                                trok.append(tr)

                        waveforms[nsp + (iev, )] = trok

            self.add_markers(markers)

        def get_channel(trs, cha):
            for tr in trs:
                if tr.channel == cha:
                    return tr
            return None

        nevents = len(events)
        nstations = len(stations)
        nphases = len(phasenames)

        # correlate waveforms

        coefs = num.zeros((nphases, nstations, nevents, nevents))
        coefs.fill(num.nan)
        tshifts = coefs.copy()
        tshifts_picked = coefs.copy()
        for iphase, phasename in enumerate(phasenames):
            for istation, station in enumerate(stations):
                nsp = station.network, station.station, phasename

                for a in events:
                    ia = event_to_number[a]
                    for b in events:
                        ib = event_to_number[b]

                        if ia == ib:
                            continue

                        if nsp in a.picks and nsp in b.picks:
                            tshifts_picked[iphase,istation,ia,ib] = \
                                    b.picks[nsp] - a.picks[nsp]

                        wa = waveforms[nsp + (ia, )]
                        wb = waveforms[nsp + (ib, )]

                        channels = list(set([tr.channel for tr in wa + wb]))
                        channels.sort()

                        tccs = []
                        for cha in channels:
                            if cha[-1] not in phases[phasename][1]:
                                continue

                            ta = get_channel(wa, cha)
                            tb = get_channel(wb, cha)
                            if ta is None or tb is None:
                                continue

                            tcc = trace.correlate(ta,
                                                  tb,
                                                  mode='full',
                                                  normalization='normal',
                                                  use_fft=True)

                            tccs.append(tcc)

                        if not tccs:
                            continue

                        tc = None
                        for tcc in tccs:
                            if tc is None:
                                tc = tcc
                            else:
                                tc.add(tcc)

                        tc.ydata *= 1. / len(tccs)

                        tmid = tc.tmin * 0.5 + tc.tmax * 0.5
                        tlen = (tc.tmax - tc.tmin) * 0.5
                        tc_cut = tc.chop(tmid - tlen * 0.5,
                                         tmid + tlen * 0.5,
                                         inplace=False)

                        tshift, coef = tc_cut.max()

                        if (tshift < tc.tmin + 0.5 * tc.deltat
                                or tc.tmax - 0.5 * tc.deltat < tshift):
                            continue

                        coefs[iphase, istation, ia, ib] = coef
                        tshifts[iphase, istation, ia, ib] = tshift

                        if self.show_correlation_traces:
                            tc.shift(master.time - (tc.tmax + tc.tmin) / 2.)
                            self.add_trace(tc)

        #tshifts = tshifts_picked

        coefssum_sta = num.nansum(coefs, axis=2) / num.sum(num.isfinite(coefs),
                                                           axis=2)
        csum_sta = num.nansum(coefssum_sta, axis=2) / num.sum(
            num.isfinite(coefssum_sta), axis=2)

        for iphase, phasename in enumerate(phasenames):
            for istation, station in enumerate(stations):
                print('station %-5s %s %15.2g' %
                      (station.station, phasename, csum_sta[iphase, istation]))

        coefssum = num.nansum(coefs, axis=1) / num.sum(num.isfinite(coefs),
                                                       axis=1)
        csumevent = num.nansum(coefssum, axis=2) / num.sum(
            num.isfinite(coefssum), axis=2)
        above = num.where(num.isfinite(coefs), coefs >= self.min_corr, 0)

        csumabove = num.sum(num.sum(above, axis=1), axis=2)

        coefssum = num.ma.masked_invalid(coefssum)

        print('correlation stats')

        for iphase, phasename in enumerate(phasenames):
            for ievent, event in enumerate(events):
                print('event %10s %3s %8i %15.2g' %
                      (event.name, phasename, csumabove[iphase, ievent],
                       csumevent[iphase, ievent]))

        # plot event correlation matrix

        fframe = self.figure_frame()
        fig = fframe.gcf()

        for iphase, phasename in enumerate(phasenames):

            p = fig.add_subplot(1, nphases, iphase + 1)
            p.set_xlabel('Event number')
            p.set_ylabel('Event number')
            mesh = p.pcolormesh(coefssum[iphase])
            cb = fig.colorbar(mesh, ax=p)
            cb.set_label('Max correlation coefficient')

        if self.save:
            fig.savefig(self.output_filename(dir='correlation.pdf'))

        fig.canvas.draw()

        # setup and solve linear system

        data = []
        rows = []
        weights = []
        for iphase in range(nphases):
            for istation in range(nstations):
                for ia in range(nevents):
                    for ib in range(ia + 1, nevents):
                        k = iphase, istation, ia, ib
                        w = coefs[k]
                        if not num.isfinite(tshifts[k]) \
                                or not num.isfinite(w) or w < self.min_corr:
                            continue

                        row = num.zeros(nevents * 4)
                        row[ia * 4:ia * 4 + 3] = g[iphase, istation]
                        row[ia * 4 + 3] = -1.0
                        row[ib * 4:ib * 4 + 3] = -g[iphase, istation]
                        row[ib * 4 + 3] = 1.0
                        weights.append(w)

                        rows.append(row)
                        data.append(tshifts[iphase, istation, ia, ib])

        nsamp = len(data)

        for i in range(4):
            row = num.zeros(nevents * 4)
            row[i::4] = 1.
            rows.append(row)
            data.append(0.0)

        if self.fix_depth:
            for ievent in range(nevents):
                row = num.zeros(nevents * 4)
                row[ievent * 4 + 2] = 1.0
                rows.append(row)
                data.append(0.0)

        a = num.array(rows, dtype=num.float)
        d = num.array(data, dtype=num.float)
        w = num.array(weights, dtype=num.float)

        if self.weighting == 'equal':
            w[:nsamp] = 1.0
        elif self.weighting == 'linear':
            pass
        elif self.weighting == 'quadratic':
            w[:nsamp] = w[:nsamp]**2

        a[:nsamp, :] *= w[:, num.newaxis]
        d[:nsamp] *= w[:nsamp]

        x, residuals, rank, singular = num.linalg.lstsq(a, d)

        x0 = num.zeros(nevents * 4)
        x0[3::4] = tevents_corr
        mean_abs_residual0 = num.mean(
            num.abs((num.dot(a[:nsamp], x0) - d[:nsamp]) / w[:nsamp]))

        mean_abs_residual = num.mean(
            num.abs((num.dot(a[:nsamp], x) - d[:nsamp]) / w[:nsamp]))

        print(mean_abs_residual0, mean_abs_residual)

        # distorted solutions

        npermutations = 100
        noiseamount = mean_abs_residual
        xdistorteds = []
        for i in range(npermutations):
            dnoisy = d.copy()
            dnoisy[:nsamp] += num.random.normal(
                size=nsamp) * noiseamount * w[:nsamp]
            xdistorted, residuals, rank, singular = num.linalg.lstsq(a, dnoisy)
            xdistorteds.append(xdistorted)

            mean_abs_residual = num.mean(
                num.abs(num.dot(a, xdistorted)[:nsamp] - dnoisy[:nsamp]))

        tmean = num.mean([e.time for e in events])

        north = x[0::4]
        east = x[1::4]
        down = x[2::4]
        etime = x[3::4] + tmean

        def plot_range(x):
            mi, ma = num.percentile(x, [10., 90.])
            ext = (ma - mi) / 5.
            mi -= ext
            ma += ext
            return mi, ma

        lat, lon = orthodrome.ne_to_latlon(master.lat, master.lon, north, east)

        events_out = []
        for ievent, event in enumerate(events):
            event_out = model.Event(time=etime[ievent],
                                    lat=lat[ievent],
                                    lon=lon[ievent],
                                    depth=down[ievent] + master_depth,
                                    name=event.name)

            mark = EventMarker(event_out, kind=4)
            self.add_marker(mark)
            events_out.append(event_out)

        model.Event.dump_catalog(events_out, 'events.relocated.txt')

        # plot results

        ned_orig = []
        for event in events:
            n, e = orthodrome.latlon_to_ne(master, event)
            d = event.depth

            ned_orig.append((n, e, d))

        ned_orig = num.array(ned_orig)

        ned_orig[:, 0] -= num.mean(ned_orig[:, 0])
        ned_orig[:, 1] -= num.mean(ned_orig[:, 1])
        ned_orig[:, 2] -= num.mean(ned_orig[:, 2])

        north0, east0, down0 = ned_orig.T

        north2, east2, down2, time2 = num.hstack(xdistorteds).reshape(
            (-1, 4)).T

        fframe = self.figure_frame()
        fig = fframe.gcf()

        color_sym = (0.1, 0.1, 0.0)
        color_scat = (0.3, 0.5, 1.0, 0.2)

        d = u'\u0394 '

        if not self.fix_depth:
            p = fig.add_subplot(2, 2, 1, aspect=1.0)
        else:
            p = fig.add_subplot(1, 1, 1, aspect=1.0)

        mi_north, ma_north = plot_range(north)
        mi_east, ma_east = plot_range(east)
        mi_down, ma_down = plot_range(down)

        p.set_xlabel(d + 'East [km]')
        p.set_ylabel(d + 'North [km]')
        p.plot(east2 / km, north2 / km, '.', color=color_scat, markersize=2)
        p.plot(east / km, north / km, '+', color=color_sym)
        p.plot(east0 / km, north0 / km, 'x', color=color_sym)
        p0 = p

        for i, ev in enumerate(events):
            p.text(east[i] / km, north[i] / km, ev.name, clip_on=True)

        if not self.fix_depth:

            p = fig.add_subplot(2, 2, 2, sharey=p0, aspect=1.0)
            p.set_xlabel(d + 'Depth [km]')
            p.set_ylabel(d + 'North [km]')
            p.plot(down2 / km,
                   north2 / km,
                   '.',
                   color=color_scat,
                   markersize=2)
            p.plot(down / km, north / km, '+', color=color_sym)
            for i, ev in enumerate(events):
                p.text(down[i] / km, north[i] / km, ev.name, clip_on=True)

            p1 = p

            p = fig.add_subplot(2, 2, 3, sharex=p0, aspect=1.0)
            p.set_xlabel(d + 'East [km]')
            p.set_ylabel(d + 'Depth [km]')
            p.plot(east2 / km, down2 / km, '.', color=color_scat, markersize=2)
            p.plot(east / km, down / km, '+', color=color_sym)
            for i, ev in enumerate(events):
                p.text(east[i] / km, down[i] / km, ev.name, clip_on=True)

            p.invert_yaxis()
            p2 = p

        p0.set_xlim(mi_east / km, ma_east / km)
        p0.set_ylim(mi_north / km, ma_north / km)

        if not self.fix_depth:
            p1.set_xlim(mi_down / km, ma_down / km)
            p2.set_ylim(mi_down / km, ma_down / km)

        if self.save:
            fig.savefig(self.output_filename(dir='locations.pdf'))

        fig.canvas.draw()
from pyrocko import orthodrome

# option 1, coordinates as floats
north_m, east_m = orthodrome.latlon_to_ne(
    10.3,   # origin latitude
    12.4,   # origin longitude
    10.5,   # target latitude
    12.6)   # target longitude

print(north_m, east_m)

# >>> 22199.7843582 21821.3511789

# option 2, coordinates from instances with 'lon' and 'lat' attributes

from pyrocko.gf import seismosizer   # noqa

source = seismosizer.DCSource(lat=10.3, lon=12.4)
target = seismosizer.Target(lat=10.5, lon=12.6)

north_m, east_m = orthodrome.latlon_to_ne(source, target)

print(north_m, east_m)

# >>> 22199.7843582 21821.3511789
示例#15
0
from pyrocko import orthodrome

# option 1, coordinates as floats
north_m, east_m = orthodrome.latlon_to_ne(
    10.3,  # origin latitude
    12.4,  # origin longitude
    10.5,  # target latitude
    12.6)  # target longitude

print(north_m, east_m)

# >>> 22199.7843582 21821.3511789

# option 2, coordinates from instances with 'lon' and 'lat' attributes

from pyrocko.gf import seismosizer  # noqa

source = seismosizer.DCSource(lat=10.3, lon=12.4)
target = seismosizer.Target(lat=10.5, lon=12.6)

north_m, east_m = orthodrome.latlon_to_ne(source, target)

print(north_m, east_m)

# >>> 22199.7843582 21821.3511789
示例#16
0
    for m in markers:
        if not isinstance(m, PhaseMarker):
            continue
        if not m.get_phasename().upper() == wanted_phase:
            continue
        event = m.get_event()
        if not event:
            continue

        append_to_dict(by_event, event, m)

    by_station = {}

    coordinates = {}
    for event, markers in by_event.items():
        x,y = orthodrome.latlon_to_ne(min_lat, min_lon,
                                    event.lat, event.lon)


        for m in markers:
                nsl = m.one_nslc()[:3]
                tt_p = m.tmin - event.time
        
                append_to_dict(by_station, nsl, (x,y,event.depth, tt_p))

    #print(by_station)

    # dict containing the not not-picked events for all stations 
    '''
    by_event_nott = {}
    for m in markers:
        if isinstance(m, PhaseMarker):
示例#17
0
    def make_time_line(self, markers, stations=None, cmap=cmap):
        events = [m.get_event() for m in markers]
        kinds = num.array([m.kind for m in markers])
        if self.cli_mode:
            self.fig = plt.figure()
        else:
            fframe = self.figure_frame()
            self.fig = fframe.gcf()
        ax = self.fig.add_subplot(311)
        ax_cum = ax.twinx()
        ax1 = self.fig.add_subplot(323)
        ax2 = self.fig.add_subplot(325, sharex=ax1)
        ax3 = self.fig.add_subplot(324, sharey=ax1)

        num_events = len(events)
        data = num.zeros((num_events, 6))
        column_to_index = dict(zip(['magnitude', 'latitude', 'longitude', 'depth', 'time', 'kind'],
                           range(6)))
        c2i = column_to_index
        for i, e in enumerate(events):
            if e.magnitude:
                mag = e.magnitude
            else:
                mag = 0.
            data[i, :] = mag, e.lat, e.lon, e.depth, e.time, kinds[i]

        s_coords = num.array([])
        s_labels = []
        if stations is not None:
            s_coords = num.array([(s.lon, s.lat, s.elevation-s.depth) for s in stations])
            s_labels = ['.'.join(s.nsl()) for s in stations]

        isorted = num.argsort(data[:, c2i['time']])
        data = data[isorted]

        def _D(key):
            return data[:, c2i[key]]

        tmin = _D('time').min()
        tmax = _D('time').max()
        lon_max = _D('longitude').max()
        lon_min = _D('longitude').min()
        lat_max = _D('latitude').max()
        lat_min = _D('latitude').min()
        depths_min = _D('depth').min()
        depths_max = _D('depth').max()
        mags_min = _D('magnitude').min()
        mags_max = _D('magnitude').max()
        moments = moment_tensor.magnitude_to_moment(_D('magnitude'))
        dates = list(map(datetime.fromtimestamp, _D('time')))

        fds = mdates.date2num(dates)
        tday = 3600*24
        tweek = tday*7
        if tmax-tmin < 1*tday:
            hfmt = mdates.DateFormatter('%Y-%m-%d %H:%M:%S')
        elif tmax-tmin < tweek*52:
            hfmt = mdates.DateFormatter('%Y-%m-%d')
        else:
            hfmt = mdates.DateFormatter('%Y/%m')

        color_values = _D(self.color_by)
        color_args = dict(c=color_values, vmin=color_values.min(),
                    vmax=color_values.max(), cmap=cmap)

        ax.scatter(fds, _D('magnitude'), s=20, **color_args)

        ax.xaxis.set_major_formatter(hfmt)
        ax.spines['top'].set_color('none')
        ax.spines['right'].set_color('none')
        ax.set_ylim((mags_min, mags_max*1.10))
        ax.set_xlim(map(datetime.fromtimestamp, (tmin, tmax)))
        ax.xaxis.set_ticks_position('bottom')
        ax.yaxis.set_ticks_position('left')
        ax.set_ylabel('Magnitude')
        init_pos = ax.get_position()

        ax_cum.plot(fds, num.cumsum(moments), 'grey')
        ax_cum.xaxis.set_major_formatter(hfmt)
        ax_cum.spines['top'].set_color('none')
        ax_cum.spines['right'].set_color('grey')
        ax_cum.set_ylabel('Cumulative seismic moment')

        lats_min = num.array([lat_min for x in range(num_events)])
        lons_min = num.array([lon_min for x in range(num_events)])

        if self.coord_system == 'cartesian':
            lats, lons = orthodrome.latlon_to_ne_numpy(
                lats_min, lons_min, _D('latitude'), _D('longitude'))

            _x = num.empty((len(s_coords), 3))
            for i, (slon, slat, sele) in enumerate(s_coords):
                n, e = orthodrome.latlon_to_ne(lat_min, lon_min, slat, slon)
                _x[i, :] = (e, n, sele)
            s_coords = _x
        else:
            lats = _D('latitude')
            lons = _D('longitude')

        s_coords = s_coords.T

        ax1.scatter(lons, lats, s=20, **color_args)
        ax1.set_aspect('equal')
        ax1.grid(True, which='both')
        ax1.set_ylabel('Northing [m]')
        ax1.get_yaxis().tick_left()

        if len(s_coords):
            ax1.scatter(s_coords[0], s_coords[1], marker='v', s=40, color='black')
            for c, sl in zip(s_coords.T, s_labels):
                ax1.text(c[0], c[1], sl, color='black')

        # bottom left plot
        ax2.scatter(lons, _D('depth'), s=20, **color_args)
        ax2.grid(True)
        ax2.set_xlabel('Easting [m]')
        ax2.set_ylabel('Depth [m]')
        ax2.get_yaxis().tick_left()
        ax2.get_xaxis().tick_bottom()
        ax2.invert_yaxis()

        ax2.text(1.1, 0, 'Origin at:\nlat=%1.3f, lon=%1.3f' %
                 (lat_min, lon_min), transform=ax2.transAxes)

        # top right plot
        ax3.scatter(_D('depth'), lats, s=20, **color_args)
        ax3.set_xlim((depths_min, depths_max))
        ax3.grid(True)
        ax3.set_xlabel('Depth [m]')
        ax3.get_xaxis().tick_bottom()
        ax3.get_yaxis().tick_right()

        self.fig.subplots_adjust(
            bottom=0.05, right=0.95, left=0.075, top=0.95, wspace=0.02, hspace=0.02)
        init_pos.y0 += 0.05
        ax.set_position(init_pos)
        ax_cum.set_position(init_pos)
        if self.cli_mode:
            plt.show()
        else:
            self.fig.canvas.draw()
示例#18
0
文件: qc.py 项目: zhengjing8628/grond
def plot_polarizations(stations,
                       trs,
                       event=None,
                       size_factor=0.05,
                       fontsize=10.,
                       output_filename=None,
                       output_format=None,
                       output_dpi=None):

    if event is None:
        slats = num.array([s.lat for s in stations], dtype=num.float)
        slons = num.array([s.lon for s in stations], dtype=num.float)
        clat, clon = od.geographic_midpoint(slats, slons)
        event = od.Loc(clat, clon)

    nsl_c_to_trs = defaultdict(dict)
    for tr in trs:
        nsl_c_to_trs[tr.nslc_id[:3]][tr.nslc_id[3]] = tr

    nsl_to_station = dict((s.nsl(), s) for s in stations)

    plot.mpl_init(fontsize=fontsize)
    fig = plt.figure(figsize=plot.mpl_papersize('a4', 'landscape'))
    plot.mpl_margins(fig, w=7., h=6., units=fontsize)

    grid = ImageGrid(fig,
                     111,
                     nrows_ncols=(2, 2),
                     axes_pad=0.5,
                     add_all=True,
                     label_mode='L',
                     aspect=True)

    axes_en = grid[0]
    axes_en.set_ylabel('Northing [km]')

    axes_dn = grid[1]
    axes_dn.locator_params(axis='x', nbins=4)
    axes_dn.set_xlabel('Depth [km]')

    axes_ed = grid[2]
    axes_ed.locator_params(axis='y', nbins=4)
    axes_ed.set_ylabel('Depth [km]')
    axes_ed.set_xlabel('Easting [km]')

    if isinstance(event, model.Event):
        axes_en.plot(0., 0., '*')
        axes_dn.plot(event.depth / km, 0., '*')
        axes_ed.plot(0., event.depth / km, '*')

    grid[3].set_axis_off()

    locations = []
    for nsl in sorted(nsl_c_to_trs.keys()):
        station = nsl_to_station[nsl]
        n, e = od.latlon_to_ne(event.lat, event.lon, station.lat, station.lon)

        locations.append((n, e))

    ns, es = num.array(locations, dtype=num.float).T

    n_min = num.min(ns)
    n_max = num.max(ns)
    e_min = num.min(es)
    e_max = num.max(es)

    factor = max((n_max - n_min) * size_factor, (e_max - e_min) * size_factor)

    fontsize_annot = fontsize * 0.7

    data = {}
    for insl, nsl in enumerate(sorted(nsl_c_to_trs.keys())):

        color = plot.mpl_graph_color(insl)

        try:
            tr_e = nsl_c_to_trs[nsl]['E']
            tr_n = nsl_c_to_trs[nsl]['N']
            tr_z = nsl_c_to_trs[nsl]['Z']

        except KeyError:
            continue

        station = nsl_to_station[nsl]

        n, e = od.latlon_to_ne(event.lat, event.lon, station.lat, station.lon)

        d = station.depth

        axes_en.annotate('.'.join(x for x in nsl if x),
                         xy=(e / km, n / km),
                         xycoords='data',
                         xytext=(fontsize_annot / 3., fontsize_annot / 3.),
                         textcoords='offset points',
                         verticalalignment='bottom',
                         horizontalalignment='left',
                         rotation=0.,
                         size=fontsize_annot)

        axes_en.plot(e / km, n / km, '^', mfc=color, mec=darken(color))
        axes_dn.plot(d / km, n / km, '^', mfc=color, mec=darken(color))
        axes_ed.plot(e / km, d / km, '^', mfc=color, mec=darken(color))

        arr_e = tr_e.ydata
        arr_n = tr_n.ydata
        arr_z = tr_z.ydata
        arr_t = tr_z.get_xdata()

        data[nsl] = (arr_e, arr_n, arr_z, arr_t, n, e, d, color)

    amaxs = []
    amax_hors = []
    for nsl in sorted(data.keys()):
        arr_e, arr_n, arr_z, arr_t, n, e, d, color = data[nsl]
        amaxs.append(num.max(num.abs(num.sqrt(arr_e**2 + arr_n**2 +
                                              arr_z**2))))
        amax_hors.append(num.max(num.abs(num.sqrt(arr_e**2 + arr_n**2))))

    amax = num.median(amaxs)
    amax_hor = num.median(amax_hors)

    for nsl in sorted(data.keys()):
        arr_e, arr_n, arr_z, arr_t, n, e, d, color = data[nsl]
        tmin = arr_t.min()
        tmax = arr_t.max()
        plot_color_line(axes_en, (e + arr_e / amax_hor * factor) / km,
                        (n + arr_n / amax_hor * factor) / km, arr_t, color,
                        tmin, tmax)
        plot_color_line(axes_dn, (d - arr_z / amax * factor) / km,
                        (n + arr_n / amax * factor) / km, arr_t, color, tmin,
                        tmax)
        plot_color_line(axes_ed, (e + arr_e / amax * factor) / km,
                        (d - arr_z / amax * factor) / km, arr_t, color, tmin,
                        tmax)

    axes_ed.invert_yaxis()

    for axes in (axes_dn, axes_ed, axes_en):
        axes.autoscale_view(tight=True)

    if output_filename is None:
        plt.show()
    else:
        fig.savefig(output_filename, format=output_format, dpi=output_dpi)