def empirical_SVD(stream_list, linear=True): """ Empirical subspace detector generation function. Takes a list of \ templates and computes the stack as the first order subspace detector, \ and the differential of this as the second order subspace detector \ following the empirical subspace method of `Barrett & Beroza, 2014 - SRL <http://srl.geoscienceworld.org/content/85/3/594.extract>`_. :type stream_list: list :param stream_list: list of streams to compute the subspace detectors from, where streams are :class:`obspy.core.stream.Stream` objects. :type linear: bool :param linear: Set to true by default to compute the linear stack as the \ first subspace vector, False will use the phase-weighted stack as the \ first subspace vector. :returns: list of two :class:`obspy.core.stream.Stream` s """ from eqcorrscan.utils import stacking # Run a check to ensure all traces are the same length stachans = list( set([(tr.stats.station, tr.stats.channel) for st in stream_list for tr in st])) for stachan in stachans: lengths = [] for st in stream_list: lengths.append( len(st.select(station=stachan[0], channel=stachan[1])[0])) min_length = min(lengths) for st in stream_list: tr = st.select(station=stachan[0], channel=stachan[1])[0] if len(tr.data) > min_length: if abs(len(tr.data) - min_length) > (0.1 * tr.stats.sampling_rate): raise IndexError('More than 0.1 s length ' 'difference, align and fix') warnings.warn( str(tr) + ' is not the same length as others, ' + 'trimming the end') tr.data = tr.data[0:min_length] if linear: first_subspace = stacking.linstack(stream_list) else: first_subspace = stacking.PWS_stack(streams=stream_list) second_subspace = first_subspace.copy() for i in range(len(second_subspace)): second_subspace[i].data = np.diff(second_subspace[i].data) second_subspace[i].stats.starttime += 0.5 * \ second_subspace[i].stats.delta return [first_subspace, second_subspace]
def multi_event_singlechan(streams, picks, clip=10.0, pre_pick=2.0,\ freqmin=False, freqmax=False, realign=False, \ cut=(-3.0,5.0), PWS=False, title=False): """ Function to plot data from a single channel at a single station for multiple events - data will be alligned by their pick-time given in the picks :type streams: List of :class:obspy.stream :param streams: List of the streams to use, can contain more traces than\ you plan on plotting :type picks: List of :class:PICK :param picks: List of picks, one for each stream :type clip: float :param clip: Length in seconds to plot, defaults to 10.0 :type pre_pick: Float :param pre_pick: Length in seconds to extract and plot before the pick,\ defaults to 2.0 :type freqmin: float :param freqmin: Low cut for bandpass in Hz :type freqmax: float :param freqmax: High cut for bandpass in Hz :type realign: Bool :param realign: To compute best alignement based on correlation or not. :type cut: tuple: :param cut: tuple of start and end times for cut in seconds from the pick :type PWS: bool :param PWS: compute Phase Weighted Stack, if False, will compute linear stack :type title: str :param title: Plot title. :returns: Alligned and cut traces, and new picks """ from eqcorrscan.utils import stacking import copy from eqcorrscan.core.match_filter import normxcorr2 from obspy import Stream fig, axes = plt.subplots(len(picks) + 1, 1, sharex=True, figsize=(7, 12)) axes = axes.ravel() traces = [] al_traces = [] # Keep input safe plist = copy.deepcopy(picks) st_list = copy.deepcopy(streams) for i, pick in enumerate(plist): if st_list[i].select(station=pick.station, \ channel='*'+pick.channel[-1]): tr=st_list[i].select(station=pick.station, \ channel='*'+pick.channel[-1])[0] else: print 'No data for ' + pick.station + '.' + pick.channel continue tr.detrend('linear') if freqmin: tr.filter('bandpass', freqmin=freqmin, freqmax=freqmax) if realign: tr_cut = tr.copy() tr_cut.trim(pick.time+cut[0], pick.time+cut[1],\ nearest_sample=False) if len(tr_cut.data) <= 0.5 * (cut[1] - cut[0]) * tr_cut.stats.sampling_rate: print 'Not enough in the trace for ' + pick.station + '.' + pick.channel print 'Suggest removing pick from sfile at time ' + str( pick.time) else: al_traces.append(tr_cut) else: tr.trim(pick.time-pre_pick, pick.time+clip-pre_pick,\ nearest_sample=False) if len(tr.data) == 0: print 'No data in the trace for ' + pick.station + '.' + pick.channel print 'Suggest removing pick from sfile at time ' + str(pick.time) continue traces.append(tr) if realign: shift_len = int(0.25 * (cut[1] - cut[0]) * al_traces[0].stats.sampling_rate) shifts = stacking.align_traces(al_traces, shift_len) for i in xrange(len(shifts)): print 'Shifting by ' + str(shifts[i]) + ' seconds' pick.time -= shifts[i] traces[i].trim(pick.time - pre_pick, pick.time + clip-pre_pick,\ nearest_sample=False) # We now have a list of traces traces = [(trace, trace.stats.starttime.datetime) for trace in traces] traces.sort(key=lambda tup: tup[1]) traces = [trace[0] for trace in traces] # Plot the traces for i, tr in enumerate(traces): y = tr.data x = np.arange(len(y)) x = x / tr.stats.sampling_rate # convert to seconds axes[i + 1].plot(x, y, 'k', linewidth=1.1) # axes[i+1].set_ylabel(tr.stats.starttime.datetime.strftime('%Y/%m/%d %H:%M'),\ # rotation=0) axes[i + 1].yaxis.set_ticks([]) traces = [Stream(trace) for trace in traces] if PWS: linstack = stacking.PWS_stack(traces) else: linstack = stacking.linstack(traces) tr=linstack.select(station=picks[0].station, \ channel='*'+picks[0].channel[-1])[0] y = tr.data x = np.arange(len(y)) x = x / tr.stats.sampling_rate axes[0].plot(x, y, 'r', linewidth=2.0) axes[0].set_ylabel('Stack', rotation=0) axes[0].yaxis.set_ticks([]) for i, slave in enumerate(traces): cc = normxcorr2(tr.data, slave[0].data) axes[i + 1].set_ylabel('cc=' + str(round(np.max(cc), 2)), rotation=0) axes[i+1].text(0.9, 0.15, str(round(np.max(slave[0].data))), \ bbox=dict(facecolor='white', alpha=0.95),\ transform=axes[i+1].transAxes) axes[i+1].text(0.7, 0.85, slave[0].stats.starttime.datetime.strftime('%Y/%m/%d %H:%M:%S'), \ bbox=dict(facecolor='white', alpha=0.95),\ transform=axes[i+1].transAxes) axes[-1].set_xlabel('Time (s)') if title: axes[0].set_title(title) plt.subplots_adjust(hspace=0) plt.show() return traces, plist
def multi_event_singlechan(streams, catalog, clip=10.0, pre_pick=2.0, freqmin=False, freqmax=False, realign=False, cut=(-3.0, 5.0), PWS=False, title=False, save=False, savefile=None): r"""Function to plot data from a single channel at a single station for \ multiple events - data will be alligned by their pick-time given in the \ picks. :type streams: list of :class:obspy.stream :param streams: List of the streams to use, can contain more traces than \ you plan on plotting :type catalog: obspy.core.event.Catalog :param catalog: Catalog of events, one for each trace, with a single pick :type clip: float :param clip: Length in seconds to plot, defaults to 10.0 :type pre_pick: float :param pre_pick: Length in seconds to extract and plot before the pick, \ defaults to 2.0 :type freqmin: float :param freqmin: Low cut for bandpass in Hz :type freqmax: float :param freqmax: High cut for bandpass in Hz :type realign: bool :param realign: To compute best alignement based on correlation or not. :type cut: tuple :param cut: tuple of start and end times for cut in seconds from the pick :type PWS: bool :param PWS: compute Phase Weighted Stack, if False, will compute linear \ stack. :type title: str :param title: Plot title. :type save: bool :param save: False will plot to screen, true will save plot and not show \ to screen. :type savefile: str :param savefile: Filename to save to, required for save=True :returns: Alligned and cut traces, and new picks """ _check_save_args(save, savefile) from eqcorrscan.utils import stacking import copy from eqcorrscan.core.match_filter import normxcorr2 from obspy import Stream import warnings fig, axes = plt.subplots(len(catalog) + 1, 1, sharex=True, figsize=(7, 12)) axes = axes.ravel() traces = [] al_traces = [] # Keep input safe clist = copy.deepcopy(catalog) st_list = copy.deepcopy(streams) for i, event in enumerate(clist): if st_list[i].select(station=event.picks[0].waveform_id.station_code, channel='*' + event.picks[0].waveform_id.channel_code[-1]): tr = st_list[i].select( station=event.picks[0].waveforms_id.station_code, channel='*' + event.picks[0].waveform_id.channel_code[-1])[0] else: print('No data for ' + event.pick[0].waveform_id) continue tr.detrend('linear') if freqmin: tr.filter('bandpass', freqmin=freqmin, freqmax=freqmax) if realign: tr_cut = tr.copy() tr_cut.trim(event.picks[0].time + cut[0], event.picks[0].time + cut[1], nearest_sample=False) if len(tr_cut.data) <= (0.5 * (cut[1] - cut[0]) * tr_cut.stats.sampling_rate): msg = ''.join([ 'Not enough in the trace for ', tr.stats.station, '.', tr.stats.channel, '\n', 'Suggest removing pick from sfile at time ', str(event.picks[0].time) ]) warnings.warn(msg) else: al_traces.append(tr_cut) else: tr.trim(event.picks[0].time - pre_pick, event.picks[0].time + clip - pre_pick, nearest_sample=False) if len(tr.data) == 0: msg = ''.join([ 'No data in the trace for ', tr.stats.station, '.', tr.stats.channel, '\n', 'Suggest removing pick from sfile at time ', str(event.picks[0].time) ]) warnings.warn(msg) continue traces.append(tr) if realign: shift_len = int(0.25 * (cut[1] - cut[0]) * al_traces[0].stats.sampling_rate) shifts = stacking.align_traces(al_traces, shift_len) for i in xrange(len(shifts)): print('Shifting by ' + str(shifts[i]) + ' seconds') event.picks[0].time -= shifts[i] traces[i].trim(event.picks[0].time - pre_pick, event.picks[0].time + clip - pre_pick, nearest_sample=False) # We now have a list of traces traces = [(trace, trace.stats.starttime.datetime) for trace in traces] traces.sort(key=lambda tup: tup[1]) traces = [trace[0] for trace in traces] # Plot the traces for i, tr in enumerate(traces): y = tr.data x = np.arange(len(y)) x = x / tr.stats.sampling_rate # convert to seconds axes[i + 1].plot(x, y, 'k', linewidth=1.1) axes[i + 1].yaxis.set_ticks([]) traces = [Stream(trace) for trace in traces] if PWS: linstack = stacking.PWS_stack(traces) else: linstack = stacking.linstack(traces) tr = linstack.select(station=event[0].picks[0].waveform_id.station_code, channel='*' + event[0].picks[0].waveform_id.channel_code[-1])[0] y = tr.data x = np.arange(len(y)) x = x / tr.stats.sampling_rate axes[0].plot(x, y, 'r', linewidth=2.0) axes[0].set_ylabel('Stack', rotation=0) axes[0].yaxis.set_ticks([]) for i, slave in enumerate(traces): cc = normxcorr2(tr.data, slave[0].data) axes[i + 1].set_ylabel('cc=' + str(round(np.max(cc), 2)), rotation=0) axes[i + 1].text(0.9, 0.15, str(round(np.max(slave[0].data))), bbox=dict(facecolor='white', alpha=0.95), transform=axes[i + 1].transAxes) axes[i + 1].text( 0.7, 0.85, slave[0].stats.starttime.datetime.strftime('%Y/%m/%d %H:%M:%S'), bbox=dict(facecolor='white', alpha=0.95), transform=axes[i + 1].transAxes) axes[-1].set_xlabel('Time (s)') if title: axes[0].set_title(title) plt.subplots_adjust(hspace=0) if not save: plt.show() else: plt.savefig(savefile) return traces, clist