def test_noise_plot(self): signal = self.st.copy().trim( self.st[0].stats.starttime + 10, self.st[0].stats.starttime + 15) noise = self.st.copy().trim(self.st[0].stats.starttime + 20) fig = noise_plot( signal=signal, noise=noise, show=False, return_figure=True) return fig
def _template_gen(picks, st, length, swin='all', prepick=0.05, all_horiz=False, delayed=True, plot=False, min_snr=None, plotdir=None): """ Master function to generate a multiplexed template for a single event. Function to generate a cut template as :class:`obspy.core.stream.Stream` from a given set of picks and data. Should be given pre-processed data (downsampled and filtered). :type picks: list :param picks: Picks to extract data around, where each pick in the \ list is an obspy.core.event.origin.Pick object. :type st: obspy.core.stream.Stream :param st: Stream to extract templates from :type length: float :param length: Length of template in seconds :type swin: str :param swin: P, S, P_all, S_all or all, defaults to all: see note in :func:`eqcorrscan.core.template_gen.template_gen` :type prepick: float :param prepick: Length in seconds to extract before the pick time default is 0.05 seconds. :type all_horiz: bool :param all_horiz: To use both horizontal channels even if there is only a pick on one of them. Defaults to False. :type delayed: bool :param delayed: If True, each channel will begin relative to it's own pick-time, if set to False, each channel will begin at the same time. :type plot: bool :param plot: To plot the template or not, default is False. Plots are saved as `template-starttime_template.png` and `template-starttime_noise.png`, where `template-starttime` is the start-time of the template :type min_snr: float :param min_snr: Minimum signal-to-noise ratio for a channel to be included in the template, where signal-to-noise ratio is calculated as the ratio of the maximum amplitude in the template window to the rms amplitude in the whole window given. :type plotdir: str  :param plotdir: The path to save plots to. If `plotdir=None` (default) then the figure will be shown on screen. :returns: Newly cut template. :rtype: :class:`obspy.core.stream.Stream` .. note:: By convention templates are generated with P-phases on the vertical channel and S-phases on the horizontal channels, normal seismograph naming conventions are assumed, where Z denotes vertical and N, E, R, T, 1 and 2 denote horizontal channels, either oriented or not. To this end we will **only** use Z channels if they have a P-pick, and will use one or other horizontal channels **only** if there is an S-pick on it. .. note:: swin argument: Setting to `P` will return only data for channels with P picks, starting at the pick time (minus the prepick). Setting to `S` will return only data for channels with S picks, starting at the S-pick time (minus the prepick) (except if `all_horiz=True` when all horizontal channels will be returned if there is an S pick on one of them). Setting to `all` will return channels with either a P or S pick (including both horizontals if `all_horiz=True`) - with this option vertical channels will start at the P-pick (minus the prepick) and horizontal channels will start at the S-pick time (minus the prepick). `P_all` will return cut traces starting at the P-pick time for all channels. `S_all` will return cut traces starting at the S-pick time for all channels. .. warning:: If there is no phase_hint included in picks, and swin=all, all channels with picks will be used. """ from eqcorrscan.utils.plotting import pretty_template_plot as tplot from eqcorrscan.utils.plotting import noise_plot # the users picks intact. if not isinstance(swin, list): swin = [swin] for _swin in swin: assert _swin in ['P', 'all', 'S', 'P_all', 'S_all'] picks_copy = [] for pick in picks: if not pick.waveform_id: Logger.warning( "Pick not associated with waveform, will not use it: " "{0}".format(pick)) continue if not pick.waveform_id.station_code or not \ pick.waveform_id.channel_code: Logger.warning( "Pick not associated with a channel, will not use it:" " {0}".format(pick)) continue picks_copy.append(pick) if len(picks_copy) == 0: return Stream() st_copy = Stream() for tr in st: # Check that the data can be represented by float16, and check they # are not all zeros if np.all(tr.data.astype(np.float16) == 0): Logger.error("Trace is all zeros at float16 level, either gain or " "check. Not using in template: {0}".format(tr)) continue st_copy += tr st = st_copy if len(st) == 0: return st # Get the earliest pick-time and use that if we are not using delayed. picks_copy.sort(key=lambda p: p.time) first_pick = picks_copy[0] if plot: stplot = st.slice(first_pick.time - 20, first_pick.time + length + 90).copy() noise = stplot.copy() # Work out starttimes starttimes = [] for _swin in swin: for tr in st: starttime = { 'station': tr.stats.station, 'channel': tr.stats.channel, 'picks': [] } station_picks = [ pick for pick in picks_copy if pick.waveform_id.station_code == tr.stats.station ] if _swin == 'P_all': p_pick = [ pick for pick in station_picks if pick.phase_hint.upper()[0] == 'P' ] if len(p_pick) == 0: continue starttime.update({'picks': p_pick}) elif _swin == 'S_all': s_pick = [ pick for pick in station_picks if pick.phase_hint.upper()[0] == 'S' ] if len(s_pick) == 0: continue starttime.update({'picks': s_pick}) elif _swin == 'all': if all_horiz and tr.stats.channel[-1] in [ '1', '2', '3', 'N', 'E' ]: # Get all picks on horizontal channels channel_pick = [ pick for pick in station_picks if pick.waveform_id.channel_code[-1] in ['1', '2', '3', 'N', 'E'] ] else: channel_pick = [ pick for pick in station_picks if pick.waveform_id.channel_code == tr.stats.channel ] if len(channel_pick) == 0: continue starttime.update({'picks': channel_pick}) elif _swin == 'P': p_pick = [ pick for pick in station_picks if pick.phase_hint.upper()[0] == 'P' and pick.waveform_id.channel_code == tr.stats.channel ] if len(p_pick) == 0: continue starttime.update({'picks': p_pick}) elif _swin == 'S': if tr.stats.channel[-1] in ['Z', 'U']: continue s_pick = [ pick for pick in station_picks if pick.phase_hint.upper()[0] == 'S' ] if not all_horiz: s_pick = [ pick for pick in s_pick if pick.waveform_id.channel_code == tr.stats.channel ] starttime.update({'picks': s_pick}) if len(starttime['picks']) == 0: continue if not delayed: starttime.update({'picks': [first_pick]}) starttimes.append(starttime) # Cut the data st1 = Stream() for _starttime in starttimes: Logger.info("Working on channel %s.%s" % (_starttime['station'], _starttime['channel'])) tr = st.select(station=_starttime['station'], channel=_starttime['channel'])[0] Logger.info("Found Trace {0}".format(tr)) used_tr = False for pick in _starttime['picks']: if not pick.phase_hint: Logger.warning( "Pick for {0}.{1} has no phase hint given, you should not " "use this template for cross-correlation" " re-picking!".format(pick.waveform_id.station_code, pick.waveform_id.channel_code)) starttime = pick.time - prepick Logger.debug("Cutting {0}".format(tr.id)) noise_amp = _rms( tr.slice(starttime=starttime - 100, endtime=starttime).data) tr_cut = tr.slice(starttime=starttime, endtime=starttime + length, nearest_sample=False).copy() if plot: noise.select(station=_starttime['station'], channel=_starttime['channel']).trim( noise[0].stats.starttime, starttime) if len(tr_cut.data) == 0: Logger.warning( "No data provided for {0}.{1} starting at {2}".format( tr.stats.station, tr.stats.channel, starttime)) continue # Ensure that the template is the correct length if len(tr_cut.data) == (tr_cut.stats.sampling_rate * length) + 1: tr_cut.data = tr_cut.data[0:-1] Logger.debug( 'Cut starttime = %s\nCut endtime %s' % (str(tr_cut.stats.starttime), str(tr_cut.stats.endtime))) if min_snr is not None and \ max(tr_cut.data) / noise_amp < min_snr: Logger.warning( "Signal-to-noise ratio {0} below threshold for {1}.{2}, " "not using".format( max(tr_cut.data) / noise_amp, tr_cut.stats.station, tr_cut.stats.channel)) continue st1 += tr_cut used_tr = True if not used_tr: Logger.warning('No pick for {0}'.format(tr.id)) if plot and len(st1) > 0: plot_kwargs = dict(show=True) if plotdir is not None: if not os.path.isdir(plotdir): os.makedirs(plotdir) plot_kwargs.update(dict(show=False, save=True)) tplot(st1, background=stplot, picks=picks_copy, title='Template for ' + str(st1[0].stats.starttime), savefile="{0}/{1}_template.png".format(plotdir, st1[0].stats.starttime), **plot_kwargs) noise_plot(signal=st1, noise=noise, savefile="{0}/{1}_noise.png".format(plotdir, st1[0].stats.starttime), **plot_kwargs) del stplot return st1