pysep.recsec ============ .. py:module:: pysep.recsec .. autoapi-nested-parse:: RECord SECtion plotting tool for seismic waveforms (observed and synthetic) This is a refactor of Pysep's Python utility `plotw_rs`, a record section plotting script. The intent of this script is to plot multiple time series' based on source-receiver characteristics (i.e., src-rcv distance, backazimuth). .. note:: Code History: - Written by Carl Tape (11/21/2011) and Yun Wang (11/2011) in Matlab - Translated to Python by Nealy Sims (1/2021) - Upgraded by Aakash Gupta (9/2021) - Refactored by Bryant Chow (3/2022) - Currently maintained by adjTomo Dev Team .. requires:: obspy >= 1.2 (expected to bring in numpy and matplotlib) .. rubric:: 1) Print the help message to see available options and flags $ python recsec.py -h 2) From the command line: The following example code blocks work with pysep to download data for a southern California event. # cd path/to/pysep $ python rungetwaveform.py event_input_mtuq2022 2 # 20200404015318920 a) Plot a record section for the socal event with default values $ python recsec.py --pysep_path 20200404015318920 b) Plot high-passed data with 7 km/s move out (focused on direct arrivals), show direct arrivals through to surface waves for all traces, thin lines to accentuate high frequencies. Overwrite previous figure and split figure onto multiple pages $ python recsec.py --pysep_path 20200404015318920 --move_out 7 --min_period_s 1 --xlim_s 100 175 --linewidth .25 --max_traces_per_rs 60 --overwrite c) Plot bandpassed data with 4 km/s move out (focused on surface waves), horizontal components only (radial, transverse), thicken up default linewidth and increase spacing between adjacent seismograms $ python recsec.py --pysep_path 20200404015318920 --components RT --move_out 4 --min_period_s 2 --max_period_s 50 --xlim_s 50 200 --y_axis_spacing 3 --linewidth 1 --amplitude_scale_factor 4 --overwrite d) Plot bandpassed transverse component, sort by azimuth, scale by the maximum amplitude of ALL traces shown on the figure. Scale amplitudes by factor 2 for better visualization and start azimuth plotting at 180* (as opposed to default 0*). $ python recsec.py --pysep_path 20200404015318920 --sort_by azimuth --scale_by global_norm --components T --min_period_s 2 --max_period_s 30 --move_out 4 --amplitude_scale_factor 2 --azimuth_start_deg 180 --linewidth 1 --overwrite e) Plot bandpassed vertical components sorted by absolute distance. Reduce amplitudes by 1/4 (0.25). Set y label fontsize smaller than default and at the max X value of the figure (far to the right) $ python recsec.py --pysep_path 20200404015318920 --sort_by abs_distance_r --components Z --min_period_s 2 --max_period_s 50 --amplitude_scale_factor 0.25 --y_label_loc x_max --y_label_fontsize 7 --overwrite --linewidth 1 3) From the Python interpreter: this is an example code block that can be written into a Python script or run from inside a Python interactive environment. Code block assumes we have downloaded event data with Pysep >>> import os >>> from glob import glob >>> from obspy import read >>> from recsec import plotw_rs # NOQA >>> st = Stream() >>> for fid in glob(os.path.join("20200404015318920", "*.?")): >>> st += read(fid) >>> plotw_rs(st=st, sort_by="distance_r") Attributes ---------- .. autoapisummary:: pysep.recsec.DEG pysep.recsec.DLT Classes ------- .. autoapisummary:: pysep.recsec.Dict pysep.recsec.RecordSection Functions --------- .. autoapisummary:: pysep.recsec.parse_args pysep.recsec.plotw_rs pysep.recsec.main Module Contents --------------- .. py:data:: DEG :value: '°' .. py:data:: DLT :value: 'Δ' .. py:class:: Dict Bases: :py:obj:`dict` Simple dictionary overload for nicer get/set attribute characteristics Initialize self. See help(type(self)) for accurate signature. .. py:method:: __setattr__(key, value) Implement setattr(self, name, value). .. py:method:: __getattr__(key) .. py:class:: RecordSection(pysep_path=None, wildcard='*', syn_path=None, syn_wildcard=None, stations=None, source=None, synsyn=False, srcfmt=None, remove_locations=False, st=None, st_syn=None, windows=None, sort_by='default', scale_by=None, time_shift_s=None, time_shift_s_syn=None, zero_pad_s=None, amplitude_scale_factor=1, move_out=None, azimuth_start_deg=0.0, distance_units='km', components='ZRTNE12', preprocess=True, min_period_s=None, max_period_s=None, trim=True, taper=True, integrate=0, geometric_spreading_factor=0.5, geometric_spreading_k_val=None, geometric_spreading_exclude=None, geometric_spreading_ymax=None, geometric_spreading_save=None, max_traces_per_rs=None, xlim_s=None, y_axis_spacing=1, y_label_loc='default', tmarks=None, figsize=(9, 11), dpi=100, show=True, save='./record_section.png', export_traces=False, overwrite=True, log_level='DEBUG', **kwargs) Record section plotting tool which takes ObsPy streams and: 1) preprocesses and filters waveforms, 2) sorts source-receiver pairs based on User input, 3) produces record section waveform figures. .. note:: Used for reading in Pysep-generated waveforms :type pysep_path: str :param pysep_path: path to Pysep output, which is expected to contain trace-wise SAC waveform files which will be read in. See `wildcard` for how to find files :type wildcard: str :param wildcard: wildcard fed to glob to determine which files to read from `pysep_path`. Defaults to '*', read ALL files inside the directory. .. note:: Used for reading in SPECFEM-generated synthetic waveforms :type syn_path: str :param syn_path: full path to directory containing synthetic seismograms that have been outputted by SPECFEM. See `syn_wildcard` for how to find files :type syn_wildcard: str :param syn_wildcard: wildcard fed to glob to determine which files to read from `syn_path`. Defaults to `wildcard` unless explicitely provided. :type stations: str :param stations: full path to STATIONS file used to define the station coordinates. Format is dictated by SPECFEM :type source: str :param source: required for synthetics, full path to SPECFEM source file, which was used to generate SPECFEM synthetics. Example filenames are CMTSOLUTION, FORCESOLUTION, SOURCE. :type synsyn: bool :param synsyn: flag to let RecSec know that we are plotting two sets of synthetic seismograms. Such that both `pysep_path` and `syn_path` will be both attempt to read in synthetic data. Both sets of synthetics MUST share the same `source` and `stations` metadata :type srcfmt: str :param srcfmt: source format, optional, allow User to dictate the file format for `source`. Passed to argument `format` of `pysep.utils.io.read_events_plus`. If not given, tries to guess the file format based on the name of the file. :type remove_locations: bool :param remove_locations: remove location code from Trace stats when reading in data to avoid the situation where data and synthetics have mismatched location codes but are meant to correspond to one another (e.g., when MTUQ includes station codes on its outputs). Warning, this strips location codes completely, so corresponding plots and exported traces will NOT match the input data re. location code. .. note:: Used for defining user-input waveforms data :type st: obspy.core.stream.Stream :param st: Stream objects containing observed time series to be plotted on the record section. Can contain any number of traces :type st_syn: obspy.core.stream.Stream :param st_syn: Stream objects containing synthetic time series to be plotted on the record section. Must be same length as `st` :type windows: dict of lists of tuples :param windows: EXPERIMENTAL FEATURE -- plot misfit windows collected by windowing algorithm like Pyflex. Essentially these are provided as start and end times for each trace in the Stream. The dictionary should be formated where keys are the Trace IDs of observed waveforms, and values are lists of tuples, where each tuple represents a window start and end time in seconds. See `pysep.utils.io.read_asdfdataset` for code on how windows are structured .. note:: Waveform plotting organization parameters :type sort_by: str :param sort_by: How to sort the Y-axis of the record section, available: - 'default': Don't sort, just iterate directly through Stream - 'alphabetical': sort alphabetically A->Z. Components sorted separately with parameter `components` - 'azimuth': sort by source-receiver azimuth (deg) with constant vertical spacing on the y-axis. Requires `azimuth_start_deg` - 'backazimuth': sort by source-receiver backazimuth (deg) with constant vertical spacing. Requires `azimuth_start_deg` - 'distance': sort by source-receiver distance (km) with constant vertical spacing. Smallest distances at the top of the figure. Requires `distance_units` - 'abs_distance': absolute vertical spacing of waveforms defined by source-receiver distance. Smallest distance at the top of the figure. Requires `distance_units` - 'abs_azimuth': absolute vertical spacing of waveforms defined by source-receiver azimuth (deg). - 'abs_backazimuth': absolute vertical spacing of waveforms by source-receiver backazimuth (deg). - '*_r': Add a '_r' to any of the values about to REVERSE the sort, e.g., 'alphabetical_r' sort will go Z->A :type scale_by: str :param scale_by: scale amplitude of waveforms by available: - None: Not set, no amplitude scaling, waveforms shown raw - 'normalize': scale each trace by the maximum amplitude, i.e., > a /= max(abs(a)) # where 'a' is time series amplitudes - 'global_norm': scale by the largest amplitude to be displayed on the screen. Will not consider waveforms which have been excluded on other basis (e.g., wrong component) i.e., > st[i].max /= max([max(abs(tr.data)) for tr in st]) - 'rel_norm': relative normalization, used when both `pysep_path` and `syn_path` are provided (or when `st` and `st_syn` are provided). Scales each trace by the maximum amplitude of the pair of matching waveforms, maintaining their relative amplitudes but normalizing pairs of traces to the same value - 'geometric_spreading': scale amplitudes by expected reduction through geometric spreading. Related parameters are: - `geometric_spreading_factor` - `geometric_spreading_k_val` - `geometric_spreading_exclude` - `geometric_spreading_ymax` A Equation is A(d) = k / sin(d) ** f Where A(d) is the amplitude reduction factor as a function of distnace, d. 'k' is the `geometric_spreading_k_val` and 'f' is the `geometric_spreading_factor`. 'k' is calculated automatically if not given. :type time_shift_s: float OR list of float OR str :param time_shift_s: apply static time shift to waveforms, two options: 1. float (e.g., -10.2), will shift ALL waveforms by that number (i.e., -10.2 second time shift applied) 2. list (e.g., [5., -2., ... 11.2]), will apply individual time shifts to EACH trace in the stream. The length of this list MUST be equal to the number of traces in your stream, in the same order as the traces in your stream. Even if your final record section has less traces due to the use of `components`. 3. str: apply time shift based on a theoretical TauP phase arrival if available in the SAC header. These should have been appended by PySEP during data download. If no value is available in the SAC header, defaults to 0. This may have unintended consequences so you should manually check that all values are okay. Available options are: - 'first_arrival_time': shift based on earliest phase arrival - 'p_arrival_time': shift based on earliest P phase arrival - 's_arrival_time': shift based on earliest S phase arrival :type time_shift_s_syn: float OR list of float OR str :param time_shift_s_syn: Optional, apply static time shift to synthetic waveforms stored in `st_syn`. If not given, but synthetics are, time shift will be taken from `time_shift_s` parameter. Set to 0 if no time shift is desired. See available options in `time_shift_s` :type zero_pad_s: list :param zero_pad_s: zero pad data in units of seconsd. applied after tapering and before filtering. Input as a tuple of floats, * (start, end): a list of floats will zero-pad the START and END of the trace. Either can be 0 to ignore zero-padding at either end :type amplitude_scale_factor: float OR list of float :param amplitude_scale_factor: apply scale factor to all amplitudes. Used as a dial to adjust amplitudes manually. Defaults to 1. Two options: 1. float (e.g., 1.2), will multiply ALL waveforms by that number 2. list (e.g., [5., -2., ... 11.2]), will apply individual amplitude scale to EACH trace in the stream. The length of this list MUST match the number of traces in your input stream. :type move_out: float :param move_out: Optional. A velocity value that will be used to calculate move out, which will time shift seismograms based on their source receiver distance. This parameter will be ADDED to time_shift_s/time_shift_s_syn (both float and list), if it is provided. Should be in units of `distance_units`/s :type azimuth_start_deg: float :param azimuth_start_deg: If sorting by azimuth, this defines the azimuthal angle for the waveform at the top of the figure. Set to 0 for default behavior :type distance_units: str :param distance_units: Y-axis units when sorting by epicentral distance 'km': kilometers on the sphere 'deg': degrees on the sphere 'km_utm': kilometers on flat plane, UTM coordinate system :type components: str :param components: a sequence of strings representing acceptable components from the data. Also determines the order these are shown EVEN when sorted by other variables. For example, components=='ZR' would only display Z and R components, and Z components would be should BEFORE R components for the SAME station. .. note:: Data processing parameters :type preprocess: str :param preprocess: choose whether preprocessing steps listed below are applied to waveform data, and if so, which data are procesed: - True: process waveforms in both `st` and `st_syn` (Default) - False: do not run any processing on waveforms - 'st': only process waveforms in `st` - 'st_syn': only process waveforms in `st_syn`. st still required :type min_period_s: float :param min_period_s: minimum filter period in seconds, if not given and `max_period_s` also not given, then no filtering is applied :type max_period_s: float :param max_period_s: maximum filter period in seconds, if not given and `min_period_s` also not given, then no filtering is applied :type trim: bool :param trim: trim waveforms to the shortest length, and if any data gaps are present, fill with mean values by default. :type taper: bool :param taper: if True, taper ends of waveform during preprocessing. Uses keyword arguments `max_percentage` (float) to define the percentage to taper, and `taper_type` (str) to define shape of the taper. See ObsPy's stream.taper() function for acceptable values for these arguments. :type integrate: int :param integrate: apply integration `integrate` times on all traces. acceptable values [-inf, inf], where positive values are integration and negative values are differentiation e.g., if integrate == 2, will integrate each trace twice. or if integrate == -1, will differentiate once or if integrate == 0, do nothing (default) .. note:: Geometric spreading parameters, used for amplitude scaling :type geometric_spreading_factor: float :param geometric_spreading_factor: factor to scale amplitudes by predicting the expected geometric spreading amplitude reduction and correcting for this factor. Related optional parameter: `geometric_spreading_k_val`. For Rayleigh waves, `geometric_spreading_factor` == 0.5 (default) :type geometric_spreading_k_val: float :param geometric_spreading_k_val: Optional constant scaling value used to scale the geometric spreading factor equation. If not given, calculated automatically using max amplitudes Value should be between 0.5 and 1.0 for regional surface waves. :type geometric_spreading_exclude: list :param geometric_spreading_exclude: a list of station names that should match the input stations. Used to exclude stations from the automatic caluclation of the geometric :type geometric_spreading_ymax: float :param geometric_spreading_ymax: Optional value for geometric spreading plot. Sets the max y-value on the plot. If not set, defaults to whatever the peak y-value plotted is. :type geometric_spreading_save: str :param geometric_spreading_save: file id to save separate geometric spreading scatter plot iff `scale_by`=='geometric_spreading'. If NoneType, will not save. By default, turned OFF .. note:: Figure generation control parameters :type max_traces_per_rs: int :param max_traces_per_rs: maximum number of traces to show on a single record section plot. Defaults to all traces in the Stream :type xlim_s: list of float :param xlim_s: [start, stop] in units of time, seconds, to set the xlimits of the figure :type y_axis_spacing: float :param y_axis_spacing: spacing between adjacent seismograms applied to Y-axis on relative (not absolute) scales. Defaults to 1. :type y_label_loc: str :param y_label_loc: Location to place waveform labels on the y-axis - 'default': auto choose the best location based on `sort_by` - 'y_axis': Replace tick labels on the y-axis (left side of figure), This won't work if using absolute sorting and will be over- written by 'default' - 'y_axis_abs': For absolute y-axis only. waveform labels plotted on the left side outside border, with y-axis labels overlapping (showing distance or azimuth) - 'y_axis_abs_right': For absolute y-axis only. waveform labels plotted on the right side outside border, with y-axis labels on the left side of the figure (showing distance or azimuth) - 'y_axis_right': Replace tick labels on the right side of the y-axis. This option won't work with absolute sorting - 'x_min': Place labels on top of the waveforms at the global min x-value on the figure - 'x_max': Place labels on top of the waveforms at the global max x-value on the figure - None: Don't plot any text labels :type tmarks: list of float :param tmarks: place vertical lines at given reference times. Used for marking reference times such as the event origin, or phase arrival. Input as a list of times in units of seconds (where T=0 is the event origin time). For example `tmarks`=[0, 100, 200] would set vertical lines at 0s, 100s and 200s :type figsize: tuple of float :param figsize: size the of the figure, passed into plt.subplots() :type dpi: int :param dpi: resolution of the figure, passed into plt.subplots() Defaults to 100. Higher DPI will result in larger file size. If you want to save a high-resolution figure, set this to 300 or higher. :type show: bool :param show: show the figure as a graphical output :type save: str :param save: path to save output figure, will create the parent directory if it doesn't exist. If None, will not save (default). :type export_traces: bool :param export_traces: export processed `st` and `st_syn` (if available) as SAC files to the `save` directory, so that the User can replot the exact waveforms or use what is shown in RecSec in other analysis. File naming follows PySEP SAC format (pysep._write_sac); Use parameter `legacy_naming` to access the same file name schema that PySEP uses for writing files with legacy naming scheme. .. note:: Internal RecSec parameters :type overwrite: bool :param overwrite: if the path defined by `save` exists, will overwrite the existing figure :type log_level: str :param log_level: level of the internal logger. In order of ascending verbosity: 'CRITICAL', 'WARNING', 'INFO', 'DEBUG'. :raises AssertionError: if any parameters are set incorrectly .. note:: **Keyword Arguments** (for fine-tune control) Processing Kwargs ````````````````` - max_percentage (float): Maximum percentage for ObsPy Stream.taper(). Default 0.05 - taper_type (str): Taper type. Default cosine. - zerophase (bool): Zero phase filter or not. Default True. - fill_value (str): Fill value for ObsPy Stream.trim(fill_value=...) Default 'mean' Azimuth Sorting Kwargs ``````````````````````` - azimuth_binsize (int): Size of azimuth bins in degrees. Default 45 - azimuth_bin_c (str): Color of azimuth bins. Default 'red' - azimuth_bin_lw (int): Linewidth of azimuth bins. Default 0.75 - azimuth_bin_ls (str): Linestyle of azimuth bins. Default '-' - azimuth_bin_zorder (int): Zorder of azimuth lines. Default 5 Plotting Kwargs ````````````````` - linewidth (float): Linewidth of the traces. Default 0.25 - obs_color (str): Color of observed data. Default 'black' - syn_color (str): Color of synthetic data. Default 'blue' - obs_zorder (int): Zorder of observed data. Default 10 - syn_zorder (int): Zorder of synthetic data. Default 10 - window_alpha (float): Alpha value of windows. Default 0.1 - window_color (str): Color of windows. Default 'orange' Tmark Kwargs ````````````` - tmark_c (str): Color of time marks. Default 'red' - tmark_lw (int): Linewidth of time marks. Default 1.5 - tmark_ls (str): Linestyle of time marks. Default '-' - tmark_alpha (float): Alpha value of time marks. Default 0.75 - tmark_zorder (int): Zorder of time marks. Default 5 Plot Aesthetic Kwargs ````````````````````` - y_label_c (str): Color of Y-axis label. Default 'black' - title (str): Overwrite the default title of the figure - ytick_fontsize (float): Font size for labels next to Y-axis ticks. - xtick_fontsize (float): Font size for labels next to X-axis ticks. - xlabel_fontsize (float): Font size for the X-axis main label - ylabel_fontsize (float): Font size for the Y-axis main label - title_fontsize (float): Font size of the main title at the top of the figure. - axis_linewidth (float): Line thickness for the borders of figure. - tick_linewidth (float): Thickness of tick marks for both X and Y axes. - tick_length (float): Length of tick marks for both X and Y axes. - tick_direction (str): 'in' for ticks pointing inwards, 'out' for ticks pointing outwards. - spine_zorder (int): Z order (visibility) of the axis borders (spines). - spine_top (bool): Toggle on/off the top axis border. - spine_bot (bool): Toggle on/off the bottom axis border. - spine_left (bool): Toggle on/off the left axis border. - spine_right (bool): Toggle on/off the right axis border. - xtick_minor (float): How often minor tick marks drawn on X-axis. - xtick_major (float): How often major tick marks drawn on X-axis. - ytick_minor (float): How often minor tick marks drawn on Y-axis. - ytick_major (float): How often major tick marks drawn on Y-axis. - xgrid_minor (bool): Turn on grid lines for each minor X tick. - xgrid_major (bool): Turn on grid lines for each major X tick. - ygrid_minor (bool): Turn on grid lines for each minor Y tick. - ygrid_major (bool): Turn on grid lines for each major Y tick. .. py:attribute:: st .. py:attribute:: sort_by :value: '' .. py:attribute:: y_axis_spacing .. py:attribute:: azimuth_start_deg .. py:attribute:: components :value: '' .. py:attribute:: scale_by :value: None .. py:attribute:: amplitude_scale_factor :value: 1 .. py:attribute:: geometric_spreading_factor .. py:attribute:: geometric_spreading_k_val :value: None .. py:attribute:: geometric_spreading_exclude :value: [] .. py:attribute:: geometric_spreading_ymax :value: None .. py:attribute:: geometric_spreading_save :value: None .. py:attribute:: move_out :value: None .. py:attribute:: zero_pad_s :value: None .. py:attribute:: preprocess :value: True .. py:attribute:: min_period_s :value: None .. py:attribute:: max_period_s :value: None .. py:attribute:: max_traces_per_rs :value: None .. py:attribute:: integrate :value: 0 .. py:attribute:: trim :value: True .. py:attribute:: taper :value: True .. py:attribute:: xlim_s :value: None .. py:attribute:: distance_units :value: '' .. py:attribute:: y_label_loc :value: 'default' .. py:attribute:: tmarks :value: None .. py:attribute:: figsize :value: (9, 11) .. py:attribute:: dpi :value: 100 .. py:attribute:: show :value: True .. py:attribute:: save :value: './record_section.png' .. py:attribute:: export_traces :value: False .. py:attribute:: remove_locations :value: False .. py:attribute:: overwrite :value: True .. py:attribute:: kwargs .. py:attribute:: stats .. py:attribute:: f :value: None .. py:attribute:: ax :value: None .. py:attribute:: idx :value: [] .. py:attribute:: station_ids :value: [] .. py:attribute:: max_amplitudes :value: [] .. py:attribute:: max_amplitudes_syn :value: [] .. py:attribute:: amplitude_scaling :value: [] .. py:attribute:: amplitude_scaling_syn :value: [] .. py:attribute:: y_axis :value: [] .. py:attribute:: xlim :value: [] .. py:attribute:: xlim_syn :value: [] .. py:attribute:: sorted_idx :value: [] .. py:attribute:: windows :value: None .. py:method:: read_data(path, data_type, wildcard='*', source=None, stations=None, srcfmt=None) General function that attempts to read in observed and synthetic data in User-provided format that can either be SAC files or SPECFEM format two-column ASCII files. This function expects that the files in the directory `path` are ONLY of type `data_type`. Files that fail on read will be ignored. :type path: str :param path: full path to directory containing data in question :type data_type: str :param data_type: expected format of the data, 'obs' or 'syn'. Determines the read approach this function will take for addressing the data. :type wildcard: str :param wildcard: wildcard fed to glob to determine files inside `path` that the function will attempt to read. Defaults to '*', read ALL files inside the directory. :type source: str :param source: required iff `data_type`==syn. Path to source file which defined the source that generated the synthetics. Acceptable values are CMTSOLUTION (from SPECFEM3D/GLOBE), and SOURCE (from SPECFEM2D) :type stations: str :param stations: required iff `data_type`==syn. full path to STATIONS file used to define the station coordinates. Format is dictated by SPECFEM :type srcfmt: str :param srcfmt: source format, optional, allow User to dictate the file format for `source`. Passed to argument `format` of `pysep.utils.io.read_events_plus`. If not given, tries to guess the file format based on the name of the file. :rtype: obspy.core.stream.Stream :return: Stream object with synthetic waveforms .. py:method:: write_stream_sac(_st_tag='_st_proc', _syn_tag='_syn_proc', _legacy_naming=True) Export processed streams in SAC format so that User can manipulate or replot exactly what is shown in the Record Section. Naming convention follows original naming schema, but adds a tag to prevent overwriting original data. .. note:: mostly copied from Pysep._write_sac() .. py:method:: check_parameters() Check that parameters are set properly and in line with how they are expected by the program .. note:: Not using assertions here because we want all incorrect parameters to be evaluated together and displayed at once, that way the user doesn't have to run this function multiple times to figure out how to set their parameters correctly :raises AssertionError: If any parameters are not set as expected by plotw_rs functionality .. py:method:: get_skip_idx() Get a list of any traces that don't adhere to user-defined boundaries such as dist, az, baz, id, or component matches. Don't actually remove the traces from the stream but rather just collect indices we can use to skip when plotting. TODO add distance, azi and backazi skip criteria :rtype: np.array :return: returns an indexing list which can be used to skip over traces that don't adhere to certain criteria .. py:method:: get_parameters() Calculate parameters in a specific order and based on the user-defined information. .. note:: The order of function calls here is important! Some of the 'get' functions require the results of other 'get' functions. Calculated Parameters :: np.array idx: a linear indexing of all the traces in the stream np.array station_ids: an ordered list of station ids, used to get station names that match the index defined in `idx` np.array max_amplitudes: abs max amplitudes of each trace, used for normalization np.array amplitude_scaling: An array to scale amplitudes based on user choices np.array time_shift_s: An array to time shift time series based on user choices np.array time_shift_s_syn: An array to time shift synthetic time series np.array y_axis: Y-Axis values based on sorting algorithm, used for plotting np.array distances: source-receiver distances in `distance_units` units np.array azimuths: source-receiver azimuths in degrees np.array backazimuths: source-receiver backazimuths in degrees np.array sorted_idx: sorted indexing on all the traces of the stream based on the chosen sorting algorithm .. py:method:: get_xlims(st=None, time_shift_s=None) The x-limits of each trace depend on the overall time shift (either static or applied through move out), as well as the sampling rate of each trace (which can vary). Retrieve an index-dependent list of x-limits which can be used to truncate the time series during plotting. .. note:: Requires that get_time_shifts() has already been run :type st: obspy.core.stream.Stream :param st: stream object to get xlims for. By default this is the 'data' stored in `st` but it can also be given `st_syn` to get synthetic x limits which may differ :type time_shift_s: float, list, str, or None :param time_shift_s: internal definition of time_shift that is provided from the User input at init. Defaults to the `time_shift_s` but can also be `time_shift_s_syn` if User wants to apply a different time shift to synthetics. :rtype: np.array :return: an array of tuples defining the start and stop indices for EACH trace to be used during plotting. Already includes time shift information so xlim can be applied DIRECTLY to the time shifted data .. py:method:: get_srcrcv_stats() Get source receiver information such as min max values, and count-related numbers (e.g., num stations) to be used mainly for print statements and text information Stats Arguments :: np.array event_names: unique event names taken from the SAC header int nevents: number of unique events in the stream np.array unique_sta_ids: unique station codes taken from trace stats int nstation_ids: number of unique station codes np.array network_codes: unique network codes taken from station ids int nnetwork: number of unique network codes np.array station_codes: unique station codes taken from station ids int nstation: number of unique station codes np.array location_codes: unique location codes taken from station ids int nlocation: number of unique location codes np.array channel_codes: unique channel codes taken from station ids int nchannel: number of unique channel codes bool reverse_sort: determine if the user wants to reverse their sort, they do this by appending '_r' to the end of the `sort_by` argument .. py:method:: get_time_offsets() Find time shift to data constituting difference between trace start time and event origin time. Both synthetics and data should have the correct timing. Time offsets will be used during plotting to make sure all traces have the same T=0 .. note:: Appends time offset directly to the stats header, overwriting any value that might have been there already .. py:method:: get_time_shifts(time_shift_s=None) Very simple function which allows float inputs for time shifts and ensures that time shifts are always per-trace arrays Applies the move out by calculating a time shift using src-rcv distance .. note:: Originally the input of `time_shift_s` was not needed as we just took the internal value but now we allow the User to set time shift for data and synthetics separately so we need some flexibility. See Issue #159 :type time_shift_s: float, list, str, or None :param time_shift_s: internal definition of time_shift that is provided from the User input at init. Defaults to the `time_shift_s` but can also be `time_shift_s_syn` if User wants to apply a different time shift to synthetics. :rtype: np.array :return: a stream-lengthed array of time shifts that can be applied per trace .. py:method:: get_srcrcv_dist_az_baz() Convenience function to wrap _get_srcrcv_dist_az_baz_trace into a loop over the whole stream and return lists of distances, azimuths, and backazimuths :rtype distances: np.array :return distances: source-receiver distances in user-defined units in the original order of Stream :rtype azimuths: np.array :return azimuths: source-receiver azimuths (deg) in the original order of Stream :rtype backazimuths: np.array :return backazimuths: source-receiver azimuths (deg) in the original order of Stream .. py:method:: _get_srcrcv_dist_az_baz_trace(tr=None, idx=0) Check the source-receiver characteristics such as src-rcv distance, azimuth, backazimuth for a given trace. .. note:: This function ASSUMES that SAC headers have been written to the traces. Otherwise we will need more complicated ways to get event lat and lon :type tr: obspy.core.trace.Trace :param tr: trace to get srcrcv information for. If None, will use `idx` :type idx: int :param idx: if `tr`==None, user can provide index of self.st (Stream) defaults to index 0 :rtype gcdist: float :return gcdist: great circle distance in units specified by `distance_units`, can be 'km' or 'deg' :rtype az: float :return az: azimuth (degrees) between source and receiver :rtype baz: float :return baz: azimuth (degrees) between source and receiver .. py:method:: get_amplitude_scaling(_choice='st') Scale the amplitudes of all the waveforms by producing a Stream dependent scale factor based on user choice. It is expected that the output array will be DIVIDED by the data arrays: i.e., st[i].data /= self.amplitude_scaling[i] .. note:: Needs to be run AFTER preprocessing because filtering etc. will affect the final amplitudes of the waveforms :type _choice: str :param _choice: Internal choice only required for 'normalize' scaling. `st` for amplitude scaling w.r.t data array, `st_syn` for amplitude scaling w.r.t synthetics :rtype: np.array :return: an array corresponding to the Stream indexes which provides a per-trace scaling coefficient .. py:method:: calculate_geometric_spreading() Stations with larger source-receiver distances will have their amplitude scaled by a larger value. For information on geometric spreading, see Stein and Wysession, Section 4.3.4, Eq 20 (for Rayleigh waves, geometrical spreading factor = 0.5). For our purposes, this will fold the attenuation factor into the same single factor that accounts for geometric spreading. Equation is for amplitude reduction 'A' as a factor of distance 'd': A(d) = k / sin(d) ** f where 'k' is the `geometric_spreading_k_val` and 'f' is the `geometric_spreading_factor`. 'k' is calculated automatically if not given by the User. In the code, A(d) is represented by `w_vector` .. note:: This does not take into account the variation in amplitude from focal mechanism regions TODO - Look in Stein and Wysession and figure out vector names - Allow ignoring specific components, currently only allowed to exclude on a per-station basis :rtype: list :return: scale factor per trace in the stream based on theoretical geometrical spreading factor. This is meant to be MULTIPLIED by the data arrays .. py:method:: get_sorted_idx() Sort the source-receiver pairs by the chosen parameters. Except for in `default` sorting, always maintains component ordering defined by the user, i.e., for the same station, components will be ordered by the `component` parameter. :rtype: np.array :return: returns an indexing list which is sorted based on the user defined `sort_by` argument. .. py:method:: _sort_by_alphabetical() Sort by full station name in order. That is, network is sorted, then within network, station is sorted, and so on. Components are sorted last and NOT in alphabetical order. They are ordered based on the user-input `components` parameter. :rtype: np.array :return: indexing of networks and stations sorted alphabetically .. py:method:: _get_component_order() When we are sorting, we want components to be sorted by the preferred order (i.e, ZRT, Z index is 0, T is 2), which means the components have to be reordered to adhere to the sorting algorithm. ALSO we need to ensure that we honor component order even if everything else is being sorted reverse alphabetically so the components entry needs to be the opposite of stats.reverse_sort :rtype: list :return: components converted to integer values which can be used for sorting algorithms. .. py:method:: get_y_axis_positions() Determine how seismograms are vertically separated on the Y-Axis when plotting. Allows for constant separation, or absolute separation based on distance or (back)azimuth separation. :rtype: np.array :return: an array of actual y-axis positions that can be passed directly to plt.plot() (or similar) .. py:method:: get_x_axis_tick_values() Determine, based on the length of the plotted traces, how often tick marks should be applied so that they are spaced as aesthetically pleasing values. .. py:method:: process_st(**kwargs) Preprocess the Stream with optional filtering in place. .. note:: Data in memory will be irretrievably altered by running preprocess. .. warning:: if `trim` is False but `zero_pad_s` is True we may run into the issue of filling data gaps with zeros TODO Add feature to allow list-like periods to individually filter seismograms. At the moment we just apply a blanket filter. KWARGS :type max_percentage: float :param max_percentage: percentage of the trace to taper at both ends :type zerophase: bool :param zerophase: whether to apply zero-phase filtering or not, defaults to True :type taper_type: str :param taper_type: type of taper to apply to the waveforms :type fill_value: str or float :param fill_value: value to fill gaps in the data after trimming, defaults to mean of the trace .. py:method:: plot(subset=None, page_num=None, **kwargs) Plot record sections based on all the available information :type subset: list of int :param subset: subset of `sorted_idx` if there are too many waveforms to plot on one page (set by `max_traces_per_rs`). e.g., to get the first 10 entries, subset=[0,10] :type page_num: int :param page_num: If multiple pages are required due to exceeding `max_traces_per_rs`, page_num will make adjustments to the figure name and title to differentiate different pages of the same record section .. py:method:: _log_relative_information(start=0, stop=None) If both `st` and `st_syn` are being plotted, then write some relative information about their amplitudes to the main logger. Related to #116 .. py:method:: _plot_trace(idx, y_index, choice='st') Plot a single trace on the record section, with amplitude scaling, time shifts, etc. Observed waveforms are black, synthetics are red. :type idx: int :param idx: index of the trace to plot and all trace-ordered values like amplitude scaling and time shifts :type y_index: int :param y_index: numerical order which this trace was plotted, as each trace is plotted on top of the previous one. y_index should be iterated linearly in the loop that calls this function. :type choice: str :param choice: choice of 'st' or 'st_syn' depending on whether you want to plot the observed or synthetic waveforms .. py:method:: _plot_tmarks() Plot vertical lines at given reference times based on user input values .. py:method:: _plot_azimuth_bins(start=None, stop=None) If plotting by azimuth, create visual bin separators so the user has a visual understanding of radiation patterns etc. :type start: int :param start: optional starting index to determine the bounds of the azimuth bins :type stop: int :param stop: optional stop index to determine the bounds of the azimuth bins .. py:method:: _plot_axes(start=0, stop=None) Contains the logic in how to handle the x- and y-axis labels, ticks etc. Logic options for how to plot the y-axis: - Relative: Relative plotting means the yticklabels will get replaced by station information. This can either be on the right or left side but will be attached to the actual axis - Absolute: Absolute plotting means the y-axis actual represents something (e.g., distance, azimuth). That means labels can not replace the y-ticks and they have to be placed within the figure .. note:: Relative plotting can also place labels OFF the y-axis, at which point the y-axis is turned off because it contains no usable information :type start: int :param start: optional starting index for creating text labels :type stop: int :param stop: optional stop index for creating text labels .. py:method:: _set_y_axis_absolute() If 'abs_' in sort_by, then the Y-axis should be shown in absolute scale. That means we need to format the text labels, add some labelling etc. .. py:method:: _set_y_axis_text_labels(start=0, stop=-1, loc='y_axis') Plot a text label next to each trace describing the station, azimuth and source-receiver distance. We need to do this all at once because we have to replace all ticks and tick labels at once. .. note:: if using the 'subset' option in plot, need to also tell the y-axis plotter that we are only plotting a subset of data by using the `start` and `stop` parameters :type start: int :param start: starting index for plotting, default to start 0 :type stop: int :param stop: stop index for plotting, default to end -1 :type loc: str :param loc: location to place the y_axis text labels, available: - y_axis: Place labels along the y-axis (left side of the figure) Will replace the actual y-tick labels so not applicable for absolute sorting which requries the y-axis labels - y_axis_abs: for absolute plotting, place waveform labels to the left side of the figure (outside border), co-existing with y-axis labels - y_axis_right: same as `y_axis` but set on the right side of figure - x_min: Place labels on the waveforms at the minimum x value - x_max: Place labels on the waveforms at the maximum x value .. py:method:: _plot_title(nwav=None) Create the title of the plot based on event and station information Allow dynamic creation of title based on user input parameters :type nwav: int :param nwav: if using subset, the title needs to know how many waveforms it's showing on the page. self.plot() should tell it .. py:method:: run() Convenience run function to run the RecordSection workflow in order. No internal logic for breaking the figure up into multiple record sections. For that see main function `plotw_rs`. .. py:function:: parse_args() Parse command line arguments to set record section parameters dynamically This arg parser provides a simplified interface for working with plotw_rs BUT it limits the flexibility of the code because things like long lists are prohibitively verbose and not included in the arguments. Kwargs can be passed in in the same format thanks to: https://stackoverflow.com/questions/37367331/is-it-possible-to-use- argparse-to-capture-an-arbitrary-set-of-optional-arguments .. note:: Not all parameters are set here, some are left as default values Also some parameters are set different than the class defaults, so that when the user runs record_section.py without arguments, they get a reasonable result .. note:: Do NOT use the command line if you want to exploit the expanded capabilities of the record section plotter, rather script it or call from an interactive environment. .. py:function:: plotw_rs(*args, **kwargs) Plot Waveform Record Section (main call function for RecordSection) Instantiates the RecordSection class, runs processing and parameter getting, and then plots record section. Contains additional logic for breaking up figures into multiple pages if requested by the user, while keeping sort order and waveform spacing consistent across multiple reord sections. .. note:: See RecordSection.__init__() for acceptable args and kwargs .. py:function:: main() Convenience 'main' function to play nice with entry scripts .. rubric:: $ recsec -h