"""meca - Plot focal mechanisms."""importnumpyasnpimportpandasaspdfrompygmt.clibimportSessionfrompygmt.exceptionsimportGMTError,GMTInvalidInputfrompygmt.helpersimportbuild_arg_string,fmt_docstring,kwargs_to_strings,use_aliasdefdata_format_code(convention,component="full"):""" Determine the data format code for meca's -S option. See the meca() method for explanations of the parameters. Examples -------- >>> data_format_code("aki") 'a' >>> data_format_code("gcmt") 'c' >>> data_format_code("partial") 'p' >>> data_format_code("mt", component="full") 'm' >>> data_format_code("mt", component="deviatoric") 'z' >>> data_format_code("mt", component="dc") 'd' >>> data_format_code("principal_axis", component="full") 'x' >>> data_format_code("principal_axis", component="deviatoric") 't' >>> data_format_code("principal_axis", component="dc") 'y' >>> for code in ["a", "c", "m", "d", "z", "p", "x", "y", "t"]: ... assert data_format_code(code) == code ... >>> data_format_code("invalid") Traceback (most recent call last): ... pygmt.exceptions.GMTInvalidInput: Invalid convention 'invalid'. >>> data_format_code("mt", "invalid") # doctest: +NORMALIZE_WHITESPACE Traceback (most recent call last): ... pygmt.exceptions.GMTInvalidInput: Invalid component 'invalid' for convention 'mt'. """# Codes for focal mechanism formats determined by "convention"codes1={"aki":"a","gcmt":"c","partial":"p"}# Codes for focal mechanism formats determined by both "convention" and# "component"codes2={"mt":{"deviatoric":"z","dc":"d","full":"m"},"principal_axis":{"deviatoric":"t","dc":"y","full":"x"},}ifconventionincodes1:returncodes1[convention]ifconventionincodes2:ifcomponentnotincodes2[convention]:raiseGMTInvalidInput(f"Invalid component '{component}' for convention '{convention}'.")returncodes2[convention][component]ifconventionin["a","c","m","d","z","p","x","y","t"]:returnconventionraiseGMTInvalidInput(f"Invalid convention '{convention}'.")@fmt_docstring@use_alias(R="region",J="projection",A="offset",B="frame",N="no_clip",V="verbose",X="xshift",Y="yshift",c="panel",p="perspective",t="transparency",)@kwargs_to_strings(R="sequence",c="sequence_comma",p="sequence")defmeca(self,spec,scale,convention=None,component="full",longitude=None,latitude=None,depth=None,plot_longitude=None,plot_latitude=None,event_name=None,**kwargs,):r""" Plot focal mechanisms. Full option list at :gmt-docs:`supplements/seis/meca.html` {aliases} Parameters ---------- spec: str, 1D array, 2D array, dict, or pd.DataFrame Data that contains focal mechanism parameters. ``spec`` can be specified in either of the following types: - ``str``: a file name containing focal mechanism parameters as columns. The meanings of each column is: - Columns 1 and 2: event longitude and latitude - Column 3: event depth (in km) - Columns 4 to 3+n: focal mechanism parameters. The number of columns *n* depends on the choice of ``convection``, which will be described below. - Columns 4+n and 5+n: longitude, latitude at which to place beachball. Using ``0 0`` will plot the beachball at the longitude, latitude given in columns 1 and 2. [optional and requires ``offset=True`` to take effect]. - Text string to appear near the beach ball [optional]. - **1D array**: focal mechanism parameters of a single event. The meanings of columns are the same as above. - **2D array**: focal mechanim parameters of multiple events. The meanings of columns are the same as above. - dict or pd.DataFrame: The dict keys or pd.DataFrame column names determine the focal mechanims convention. For different conventions, the following combination of keys are allowed: - ``"aki"``: *strike, dip, rake, magnitude* - ``"gcmt"``: *strike1, dip1, rake1, strike2, dip2, rake2, mantissa,* *exponent* - ``"mt"``: *mrr, mtt, mff, mrt, mrf, mtf, exponent* - ``"partial"``: *strike1, dip1, strike2, fault_type, magnitude* - ``"principal_axis"``: *t_value, t_azimuth, t_plunge, n_value, n_azimuth, n_plunge, p_value, p_azimuth, p_plunge, exponent* A dict may contain values for a single focal mechanism or lists of values for multiple focal mechanisms. Both dict and pd.DataFrame may optionally contain keys/column names: ``latitude``, ``longitude``, ``depth``, ``plot_longitude``, ``plot_latitude``, and/or ``event_name``. For ``spec`` in either a str, a 1D array or a 2D array, the ``convention`` parameter is required so we know how to interpret the columns. For ``spec`` in a dict or a pd.DataFrame, ``convention`` is not needed and is ignored if specified. scale: str Adjusts the scaling of the radius of the beachball, which is proportional to the magnitude. *scale* defines the size for magnitude = 5 (i.e. scalar seismic moment M0 = 4.0E23 dynes-cm). convention: str Focal mechanism convention. Choose from: - ``"aki"`` (Aki & Richards) - ``"gcmt"`` (global CMT) - ``"mt"`` (seismic moment tensor) - ``"partial"`` (partial focal mechanism) - ``"principal_axis"`` (principal axis). Ignored if ``spec`` is a dictionary or pd.DataFrame. component: str The component of the seismic moment tensor to plot. - ``"full"``: the full seismic moment tensor - ``"dc"``: the closest double couple defined from the moment tensor (zero trace and zero determinant) - ``"deviatoric"``: deviatoric part of the moment tensor (zero trace) longitude: int, float, list, or 1d numpy array Longitude(s) of event location. Must be the same length as the number of events. Will override the ``longitude`` values in ``spec`` if ``spec`` is a dict or pd.DataFrame. latitude: int, float, list, or 1d numpy array Latitude(s) of event location. Must be the same length as the number of events. Will override the ``latitude`` values in ``spec`` if ``spec`` is a dict or pd.DataFrame. depth: int, float, list, or 1d numpy array Depth(s) of event location in kilometers. Must be the same length as the number of events. Will override the ``depth`` values in ``spec`` if ``spec`` is a dict or pd.DataFrame. plot_longitude: int, float, list, or 1d numpy array Longitude(s) at which to place beachball. Must be the same length as the number of events. Will override the ``plot_longitude`` values in ``spec`` if ``spec`` is a dict or pd.DataFrame. plot_latitude: int, float, list, or 1d numpy array Latitude(s) at which to place beachball. List must be the same length as the number of events. Will override the ``plot_latitude`` values in ``spec`` if ``spec`` is a dict or pd.DataFrame. event_name : str or list of str, or 1d numpy array Text strings (e.g., event names) to appear near the beach ball. List must be the same length as the number of events. Will override the ``event_name`` values in ``spec`` if ``spec`` is a dict or pd.DataFrame. offset: bool or str [**+p**\ *pen*][**+s**\ *size]. Offsets beachballs to the longitude, latitude specified in the last two columns of the input file or array, or by ``plot_longitude`` and ``plot_latitude`` if provided. A small circle is plotted at the initial location and a line connects the beachball to the circle. Use **+s**\ *size* to set the diameter of the circle [Default is no circle]. Use **+p**\ *pen* to set the line pen attributes [Default is 0.25p]. no_clip : bool Does NOT skip symbols that fall outside frame boundary specified by *region* [Default is False, i.e. plot symbols inside map frame only]. {J} {R} {B} {V} {XY} {c} {p} {t} """# pylint: disable=too-many-arguments,too-many-locals,too-many-brancheskwargs=self._preprocess(**kwargs)# pylint: disable=protected-accessifisinstance(spec,(dict,pd.DataFrame)):# spec is a dict or pd.DataFrameparam_conventions={"aki":["strike","dip","rake","magnitude"],"gcmt":["strike1","dip1","rake1","strike2","dip2","rake2","mantissa","exponent",],"mt":["mrr","mtt","mff","mrt","mrf","mtf","exponent"],"partial":["strike1","dip1","strike2","fault_type","magnitude"],"pricipal_axis":["t_value","t_azimuth","t_plunge","n_value","n_azimuth","n_plunge","p_value","p_azimuth","p_plunge","exponent",],}# determine convention from dict keys or pd.DataFrame column namesforconv,parasinparam_conventions.items():ifset(paras).issubset(set(spec.keys())):convention=convbreakelse:ifisinstance(spec,dict):msg="Keys in dict 'spec' do not match known conventions."else:msg="Column names in pd.DataFrame 'spec' do not match known conventions."raiseGMTError(msg)# override the values in dict/pd.DataFrame if parameters are explicity# specifiediflongitudeisnotNone:spec["longitude"]=np.atleast_1d(longitude)iflatitudeisnotNone:spec["latitude"]=np.atleast_1d(latitude)ifdepthisnotNone:spec["depth"]=np.atleast_1d(depth)ifplot_longitudeisnotNone:# must be in string typespec["plot_longitude"]=np.atleast_1d(plot_longitude).astype(str)ifplot_latitudeisnotNone:# must be in string typespec["plot_latitude"]=np.atleast_1d(plot_latitude).astype(str)ifevent_nameisnotNone:spec["event_name"]=np.atleast_1d(event_name).astype(str)# convert dict to pd.DataFrame so columns can be reorderedifisinstance(spec,dict):spec=pd.DataFrame(spec)# expected columns are:# longitude, latitude, depth, focal_parameters,# [plot_longitude, plot_latitude] [event_name]newcols=["longitude","latitude","depth"]+param_conventions[convention]if"plot_longitude"inspec.columnsand"plot_latitude"inspec.columns:newcols+=["plot_longitude","plot_latitude"]kwargs["A"]=Trueif"event_name"inspec.columns:newcols+=["event_name"]# reorder columns in DataFramespec=spec.reindex(newcols,axis=1)elifisinstance(spec,np.ndarray)andspec.ndim==1:# Convert 1d array into 2d arrayspec=np.atleast_2d(spec)# determine data_foramt from convection and componentdata_format=data_format_code(convention=convention,component=component)# Assemble -S flagkwargs["S"]=data_format+scalewithSession()aslib:# Choose how data will be passed into the modulefile_context=lib.virtualfile_from_data(check_kind="vector",data=spec)withfile_contextasfname:lib.call_module(module="meca",args=build_arg_string(kwargs,infile=fname))