def show(self, dpi=300, width=500, method="static"): """ Display a preview of the figure. Inserts the preview in the Jupyter notebook output. You will need to have IPython installed for this to work. You should have it if you are using the notebook. If ``method='external'``, makes PDF preview instead and opens it in the default viewer for your operating system (falls back to the default web browser). Note that the external viewer does not block the current process, so this won't work in a script. Parameters ---------- dpi : int The image resolution (dots per inch). width : int Width of the figure shown in the notebook in pixels. Ignored if ``method='external'``. method : str How the figure will be displayed. Options are (1) ``'static'``: PNG preview (default); (2) ``'external'``: PDF preview in an external program. Returns ------- img : IPython.display.Image Only if ``method != 'external'``. """ # Module level variable to know which figures had their show method # called. Needed for the sphinx-gallery scraper. SHOWED_FIGURES.append(self) if method not in ["static", "external"]: raise GMTInvalidInput("Invalid show method '{}'.".format(method)) if method == "external": pdf = self._preview(fmt="pdf", dpi=dpi, anti_alias=False, as_bytes=False) launch_external_viewer(pdf) img = None elif method == "static": png = self._preview(fmt="png", dpi=dpi, anti_alias=True, as_bytes=True, transparent=True) if Image is None: raise GMTError(" ".join([ "Cannot find IPython.", "Make sure you have it installed", "or use 'method=\"external\"' to open in an external viewer.", ])) img = Image(data=png, width=width) return img
def show(self, dpi=300, width=500, method=None, waiting=0.5): """ Display a preview of the figure. Inserts the preview in the Jupyter notebook output if available, otherwise opens it in the default viewer for your operating system (falls back to the default web browser). :func:`pygmt.set_display` can select the default display method (**notebook**, **external**, or **none**). The ``method`` parameter can also override the default display method for the current figure. Parameters ``dpi`` and ``width`` can be used to control the resolution and dimension of the figure in the notebook. Note: The external viewer can be disabled by setting the PYGMT_USE_EXTERNAL_DISPLAY environment variable to **false**. This is useful when running unit tests and building the documentation in consoles without a Graphical User Interface. Note that the external viewer does not block the current process, thus it's necessary to suspend the execution of the current process for a short while after launching the external viewer, so that the preview image won't be deleted before the external viewer tries to open it. Set the ``waiting`` parameter to a larger number if your computer is slow. Parameters ---------- dpi : int The image resolution (dots per inch) in Jupyter notebooks. width : int The image width (in pixels) in Jupyter notebooks. method : str How the current figure will be displayed. Options are - **external**: PDF preview in an external program [default] - **notebook**: PNG preview [default in Jupyter notebooks] - **none**: Disable image preview waiting : float Suspend the execution of the current process for a given number of seconds after launching an external viewer. Only works if ``method="external"``. """ # Module level variable to know which figures had their show method # called. Needed for the sphinx-gallery scraper. SHOWED_FIGURES.append(self) # Set the display method if method is None: method = SHOW_CONFIG["method"] if method not in ["external", "notebook", "none"]: raise GMTInvalidInput( (f"Invalid display method '{method}', " "should be either 'notebook', 'external', or 'none'.")) if method in ["notebook", "none"]: if IPython is None: raise GMTError(( "Notebook display is selected, but IPython is not available. " "Make sure you have IPython installed, " "or run the script in a Jupyter notebook.")) png = self._preview(fmt="png", dpi=dpi, anti_alias=True, as_bytes=True) IPython.display.display( IPython.display.Image(data=png, width=width)) if method == "external": pdf = self._preview(fmt="pdf", dpi=dpi, anti_alias=False, as_bytes=False) launch_external_viewer(pdf, waiting=waiting)
def meca( self, # pylint: disable=unused-argument spec, scale, longitude=None, latitude=None, depth=None, convention=None, component="full", plot_longitude=None, plot_latitude=None, **kwargs, ): """ Plot focal mechanisms. Full option list at :gmt-docs:`supplements/seis/meca.html` Note ---- Currently, labeling of beachballs with text strings is only supported via providing a file to `spec` as input. {aliases} Parameters ---------- spec: dict, 1D array, 2D array, pd.DataFrame, or str Either a filename containing focal mechanism parameters as columns, a 1- or 2-D array with the same, or a dictionary. If a filename or array, `convention` is required so we know how to interpret the columns/entries. If a dictionary, the following combinations of keys are supported; these determine the convention. Dictionary may contain values for a single focal mechanism or lists of values for many focal mechanisms. A Pandas DataFrame may optionally contain columns latitude, longitude, depth, plot_longitude, and/or plot_latitude instead of passing them to the meca method. - ``"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_exponent, t_azimuth, t_plunge, n_exponent, n_azimuth, n_plunge, p_exponent, p_azimuth, p_plunge, exponent* 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) longitude: int, float, list, or 1d numpy array Longitude(s) of event location. Ignored if `spec` is not a dictionary. List must be the length of the number of events. Ignored if `spec` is a DataFrame and contains a 'longitude' column. latitude: int, float, list, or 1d numpy array Latitude(s) of event location. Ignored if `spec` is not a dictionary. List must be the length of the number of events. Ignored if `spec` is a DataFrame and contains a 'latitude' column. depth: int, float, list, or 1d numpy array Depth(s) of event location in kilometers. Ignored if `spec` is not a dictionary. List must be the length of the number of events. Ignored if `spec` is a DataFrame and contains a 'depth' column. convention: str ``"aki"`` (Aki & Richards), ``"gcmt"`` (global CMT), ``"mt"`` (seismic moment tensor), ``"partial"`` (partial focal mechanism), or ``"principal_axis"`` (principal axis). Ignored if `spec` is a dictionary or dataframe. component: str The component of the seismic moment tensor to plot. ``"full"`` (the full seismic moment tensor), ``"dc"`` (the closest double couple with zero trace and zero determinant), ``"deviatoric"`` (zero trace) plot_longitude: int, float, list, or 1d numpy array Longitude(s) at which to place beachball, only used if `spec` is a dictionary. List must be the length of the number of events. Ignored if `spec` is a DataFrame and contains a 'plot_longitude' column. plot_latitude: int, float, list, or 1d numpy array Latitude(s) at which to place beachball, only used if `spec` is a dictionary. List must be the length of the number of events. Ignored if `spec` is a DataFrame and contains a 'plot_latitude' column. offset: bool or str 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. Specify pen and optionally append ``+ssize`` to change the line style and/or size of the circle. 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} {p} {t} """ # pylint warnings that need to be fixed # pylint: disable=too-many-locals # pylint: disable=too-many-nested-blocks # pylint: disable=too-many-branches # pylint: disable=too-many-statements def set_pointer(data_pointers, spec): """ Set optional parameter pointers based on DataFrame or dict, if those parameters are present in the DataFrame or dict. """ for param in list(data_pointers.keys()): if param in spec: # set pointer based on param name data_pointers[param] = spec[param] def update_pointers(data_pointers): """ Updates variables based on the location of data, as the following data can be passed as parameters or it can be contained in `spec`. """ # update all pointers longitude = data_pointers["longitude"] latitude = data_pointers["latitude"] depth = data_pointers["depth"] plot_longitude = data_pointers["plot_longitude"] plot_latitude = data_pointers["plot_latitude"] return (longitude, latitude, depth, plot_longitude, plot_latitude) # Check the spec and parse the data according to the specified # convention if isinstance(spec, (dict, pd.DataFrame)): # dicts and DataFrames are handed similarly but not identically if (longitude is None or latitude is None or depth is None) and not isinstance(spec, (dict, pd.DataFrame)): raise GMTError("Location not fully specified.") param_conventions = { "AKI": ["strike", "dip", "rake", "magnitude"], "GCMT": ["strike1", "dip1", "dip2", "rake2", "mantissa", "exponent"], "MT": ["mrr", "mtt", "mff", "mrt", "mrf", "mtf", "exponent"], "PARTIAL": ["strike1", "dip1", "strike2", "fault_type", "magnitude"], "PRINCIPAL_AXIS": [ "t_exponent", "t_azimuth", "t_plunge", "n_exponent", "n_azimuth", "n_plunge", "p_exponent", "p_azimuth", "p_plunge", "exponent", ], } # to keep track of where optional parameters exist data_pointers = { "longitude": longitude, "latitude": latitude, "depth": depth, "plot_longitude": plot_longitude, "plot_latitude": plot_latitude, } # make a DataFrame copy to check convention if it contains # other parameters if isinstance(spec, (dict, pd.DataFrame)): # check if a copy is necessary copy = False drop_list = [] for pointer in data_pointers: if pointer in spec: copy = True drop_list.append(pointer) if copy: spec_conv = spec.copy() # delete optional parameters from copy for convention check for item in drop_list: del spec_conv[item] else: spec_conv = spec # set convention and focal parameters based on spec convention convention_assigned = False for conv in param_conventions: if set(spec_conv.keys()) == set(param_conventions[conv]): convention = conv.lower() foc_params = param_conventions[conv] convention_assigned = True break if not convention_assigned: raise GMTError("Parameters in spec dictionary do not match known " "conventions.") # create a dict type pointer for easier to read code if isinstance(spec, dict): dict_type_pointer = list(spec.values())[0] elif isinstance(spec, pd.DataFrame): # use df.values as pointer for DataFrame behavior dict_type_pointer = spec.values # assemble the 1D array for the case of floats and ints as values if isinstance(dict_type_pointer, (int, float)): # update pointers set_pointer(data_pointers, spec) # look for optional parameters in the right place ( longitude, latitude, depth, plot_longitude, plot_latitude, ) = update_pointers(data_pointers) # Construct the array (order matters) spec = [longitude, latitude, depth ] + [spec[key] for key in foc_params] # Add in plotting options, if given, otherwise add 0s for arg in plot_longitude, plot_latitude: if arg is None: spec.append(0) else: if "C" not in kwargs: kwargs["C"] = True spec.append(arg) # or assemble the 2D array for the case of lists as values elif isinstance(dict_type_pointer, list): # update pointers set_pointer(data_pointers, spec) # look for optional parameters in the right place ( longitude, latitude, depth, plot_longitude, plot_latitude, ) = update_pointers(data_pointers) # before constructing the 2D array lets check that each key # of the dict has the same quantity of values to avoid bugs list_length = len(list(spec.values())[0]) for value in list(spec.values()): if len(value) != list_length: raise GMTError("Unequal number of focal mechanism " "parameters supplied in 'spec'.") # lets also check the inputs for longitude, latitude, # and depth if it is a list or array if (isinstance(longitude, (list, np.ndarray)) or isinstance(latitude, (list, np.ndarray)) or isinstance(depth, (list, np.ndarray))): if (len(longitude) != len(latitude)) or (len(longitude) != len(depth)): raise GMTError("Unequal number of focal mechanism " "locations supplied.") # values are ok, so build the 2D array spec_array = [] for index in range(list_length): # Construct the array one row at a time (note that order # matters here, hence the list comprehension!) row = [longitude[index], latitude[index], depth[index] ] + [spec[key][index] for key in foc_params] # Add in plotting options, if given, otherwise add 0s as # required by GMT for arg in plot_longitude, plot_latitude: if arg is None: row.append(0) else: if "C" not in kwargs: kwargs["C"] = True row.append(arg[index]) spec_array.append(row) spec = spec_array # or assemble the array for the case of pd.DataFrames elif isinstance(dict_type_pointer, np.ndarray): # update pointers set_pointer(data_pointers, spec) # look for optional parameters in the right place ( longitude, latitude, depth, plot_longitude, plot_latitude, ) = update_pointers(data_pointers) # lets also check the inputs for longitude, latitude, and depth # just in case the user entered different length lists if (isinstance(longitude, (list, np.ndarray)) or isinstance(latitude, (list, np.ndarray)) or isinstance(depth, (list, np.ndarray))): if (len(longitude) != len(latitude)) or (len(longitude) != len(depth)): raise GMTError( "Unequal number of focal mechanism locations supplied." ) # values are ok, so build the 2D array in the correct order spec_array = [] for index in range(len(spec)): # Construct the array one row at a time (note that order # matters here, hence the list comprehension!) row = [longitude[index], latitude[index], depth[index] ] + [spec[key][index] for key in foc_params] # Add in plotting options, if given, otherwise add 0s as # required by GMT for arg in plot_longitude, plot_latitude: if arg is None: row.append(0) else: if "C" not in kwargs: kwargs["C"] = True row.append(arg[index]) spec_array.append(row) spec = spec_array else: raise GMTError( "Parameter 'spec' contains values of an unsupported type.") # Add condition and scale to kwargs if convention == "aki": data_format = "a" elif convention == "gcmt": data_format = "c" elif convention == "mt": # Check which component of mechanism the user wants plotted if component == "deviatoric": data_format = "z" elif component == "dc": data_format = "d" else: # component == 'full' data_format = "m" elif convention == "partial": data_format = "p" elif convention == "principal_axis": # Check which component of mechanism the user wants plotted if component == "deviatoric": data_format = "t" elif component == "dc": data_format = "y" else: # component == 'full' data_format = "x" # Support old-school GMT format options elif convention in ["a", "c", "m", "d", "z", "p", "x", "y", "t"]: data_format = convention else: raise GMTError("Convention not recognized.") # Assemble -S flag kwargs["S"] = data_format + scale kind = data_kind(spec) with Session() as lib: if kind == "matrix": file_context = lib.virtualfile_from_matrix(np.atleast_2d(spec)) elif kind == "file": file_context = dummy_context(spec) else: raise GMTInvalidInput("Unrecognized data type: {}".format( type(spec))) with file_context as fname: arg_str = " ".join([fname, build_arg_string(kwargs)]) lib.call_module("meca", arg_str)