Source code for pygeostat.plotting.variogram_plot

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Basic variogram plotting function using matplotlib reminiscent of varplt from gslib"""

#-----------------------------------------------------------------------------
# Boilerplate
#-----------------------------------------------------------------------------

#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
import matplotlib as mpl
import matplotlib.pyplot as plt


import matplotlib as mpl
import matplotlib.pyplot as plt
from . set_style import set_plot_style
from .. pygeostat_parameters import Parameters
import numpy as np



[docs] @set_plot_style def variogram_plot(data, index=None, sill=1, experimental=True, label=None, ax=None, figsize=None, xlim=None, ylim=None, title=None, xlabel=None, unit=None, ylabel=None, color=None, marker=None, ms=None, ls=None, lw=None, minpairs=40, pairnumbers=False, grid=None, axis_xy=None, plot_style=None, custom_style=None, output_file=None, out_kws=None, **kwargs): """ This function uses matplotlib to create a variogram plot. Input dataframe structure is important as the required data is found within columns that have recognizable headers. The only parameter needed is ``data`` and must be a pandas dataframe. All other arguments are optional or automatically determined. The settings for experimental and modeled variogram plotting is controlled by the ``experimental`` parameter. Please review the documentation of the :func:`gs.set_style() <pygeostat.plotting.set_style.set_style>` and :func:`gs.export_image() <pygeostat.plotting.export_image.export_image>` functions for details on their parameters so that their use in this function can be understood. Parameters: data (pd.DataFrame/gs.DataFile): Dataframe/DataFile containing the variogram value, variogram distance, and variogram index (if required) data as columns. The dataframe must contain the correct column IDs. The column header containing the variogram distance can be: 'h', 'Lag Distance', or 'Distance.' The column header containing the variogram values can be: 'vario', 'Variogram Value', or 'Variogram' index (int): Point to which variogram you would like to plot if there are multiple variogram within your dataframe. The dataframe must contain the correct column ID. The column header containing the variogram index values can be: 'Variogram Index' or 'Index' sill (float): Value to plot a horizontal line representing the variograms sill experimental (bool): Indicator if the variogram is experimental ``True`` or modeled ``False`` label (str or bool): String to pass to Matplotlib's auto legend function. A default value will be generated; however, to prevent this, set label to ``False`` ax (mpl.axis): Matplotlib axis to plot the figure figsize (tuple): Figure size (width, height) xlim (float tuple): Minimum and maximum limits of data along the x axis ylim (float tuple): Minimum and maximum limits of data along the y axis title (str): Title for the plot xlabel (str): X-axis label unit (str): Distance units used for lag distance. Only used if the keyword parameter ``xlabel`` is left to its default value of ``None``. yalabl (str): Y-axis label color (str): Any Matplotlib color marker (str): A valid Matplotlib marker style ms (float): Marker size in points ls (float): A valid Matplotlib line style lw (float): Line width in points minpairs (int or bool): Any experimental variogram values that were calculated using fewer pairs then what is specified by the argument ``minpairs``, is highlighted red. To turn this functionality off, set ``minpairs`` to ``False``. grid (bool): Plots the major grid lines if True. Based on Parameters['plotting.grid'] if None. axis_xy (bool): converts the axis to GSLIB-style axis visibility (only left and bottom visible) if axis_xy is True. Based on Parameters['plotting.axis_xy'] if None. plot_style (str): Use a predefined set of matplotlib plotting parameters as specified by :class:`gs.GridDef <pygeostat.data.grid_definition.GridDef>`. Use ``False`` or ``None`` to turn it off custom_style (dict): Alter some of the predefined parameters in the ``plot_style`` selected. output_file (str): Output figure file name and location out_kws (dict): Optional dictionary of permissible keyword arguments to pass to :func:`gs.export_image() <pygeostat.plotting.export_image.export_image>` **kwargs: Optional permissible keyword arguments to pass to matplotlib's plot function Returns: ax (ax): matplotlib Axes object with the variogram **Examples:** A simple call for experimental variograms, plotting only one direction: .. plot:: import pygeostat as gs #Load the data from output from varcal/varmodel file varcalcdat = gs.ExampleData('experimental_variogram') gs.variogram_plot(varcalcdat, index=1) | A simple call for modeled variograms, plotting only one direction: .. plot:: import pygeostat as gs varmodeldat = gs.ExampleData('variogram_model') gs.variogram_plot(varmodeldat, index=1, experimental=False) | Plot both experimental and modeled variograms for one direction: .. note:: Some odd behavior may occur if the sill is repeatedly plotted. In the case when variograms are being plotted iteratively on the same figure, set the parameter ``sill`` to ``False`` on all but the last figure. .. plot:: import pygeostat as gs varcalcdat = gs.ExampleData('experimental_variogram') varmodeldat = gs.ExampleData('variogram_model') ax = gs.variogram_plot(varcalcdat.data, index=1, sill=False) gs.variogram_plot(varmodeldat.data, index=1, experimental=False, ax=ax) | Plot both directions experimental and modeled variograms with a legend, grab 2 colors from :func:`gs.get_palette() <pygeostat.plotting.utils.get_palette>` to use for the plots, and prevent points calculated using a low amount of pairs from being highlighted for one of the plots: .. plot:: import pygeostat as gs varcalcdat = gs.ExampleData('experimental_variogram') varmodeldat = gs.ExampleData('variogram_model') colors = gs.get_palette('cat_dark', 2, cmap=False) ax = gs.variogram_plot(varcalcdat.data, index=1, color=colors[0], minpairs=False, label=False) gs.variogram_plot(varmodeldat.data, index=1, experimental=False, ax=ax, color=colors[0], label='Minor') gs.variogram_plot(varcalcdat.data, index=2, ax=ax, color=colors[1], label=False) gs.variogram_plot(varmodeldat.data, index=2, experimental=False, ax=ax, color=colors[1], label='Major') plt.legend(loc=4) """ from .export_image import export_image from ..data.data import DataFile from ..utility.logging import printerr from . utils import format_plot, setup_plot, _spatial_aspect if isinstance (data, DataFile): data = data.data # Handle dictionary defaults if out_kws is None: out_kws = dict() # Infer the data columns assuming pygeostat or gslib's varcalc function or pygeostat's model # function was used if 'h' in data.columns: h_name = 'h' elif 'Lag Distance' in data.columns: h_name = 'Lag Distance' elif 'Distance' in data.columns: h_name = 'Distance' else: print("Error: A distance column could not be found. Ensure its header is one of the", "following: 'h',\n 'Lag Distance', or 'Distance.'") return if 'vario' in data.columns: vario_name = 'vario' elif 'Variogram Value' in data.columns: vario_name = 'Variogram Value' elif 'Variogram' in data.columns: vario_name = 'Variogram' else: print("Error: A variogram column could not be found. Ensure its header is one of the", "\n following: 'vario', 'Variogram Value', or 'Variogram.'") return if index: if 'Variogram Index' in data.columns: index_name = 'Variogram Index' elif 'Index' in data.columns: index_name = 'Index' else: print("Error: A variogram index column could not be found. Ensure its header is one of" " the\n following: 'Variogram Index' or 'Index.'") return if minpairs and experimental: if experimental or pairnumbers: pairs_name = False if 'numpairs' in data.columns: pairs_name = 'numpairs' if 'Number of Pairs' in data.columns: pairs_name = 'Number of Pairs' if not pairs_name: printerr("The argument `minpairs` is being used; however, the column 'numpairs'" " or 'Number of Pairs' was not found in `data`. `minpairs` has been" " set to a value of `False`.", errtype='warning') minpairs = False else: pairs_name = False minpairs = False pairnumbers = False else: pairs_name = False minpairs = False pairnumbers = False # Set-up some default plotting parameters if color is None: color = Parameters['plotting.variogram_plot.color'] if experimental: if ms is None: ms = Parameters['plotting.variogram_plot.ms'] if marker is None: marker = 'o' if lw is None: lw = 0 if ls is None and lw > 0: ls = '-' else: ls = 'None' else: if lw is None: lw = 1 if ls is None: ls = '-' if ms is None: ms = 0 if label is None: if index: label = 'Var %s' % index else: label = 'Var' elif not label: label = "_nolegend_" # Get the right data data = data[data[vario_name] != np.nan] # This shouldn't be necessary once everything is converted to an nan standard, but for now.. data = data[data[vario_name] != Parameters['data.null']] if experimental: data = data[data[h_name] > 0] pairs_label = None varpairs = None if index is None: vardata = data[vario_name] vardist = data[h_name] if minpairs or pairnumbers and experimental: varpairs = data[data[pairs_name] <= minpairs] pairs_label = data[pairs_name] else: vardata = data[vario_name][data[index_name] == index] vardist = data[h_name][data[index_name] == index] if minpairs or pairnumbers and experimental: varpairs = data[(data[pairs_name] <= minpairs) & (data[index_name] == index)] pairs_label = data[pairs_name] if len(vardata) == 0 or len(vardist) == 0: print("Error: The index value provided wasn't found") return # Set-up plot if no axis is supplied fig, ax, cax = setup_plot(ax, figsize=figsize, aspect =False) # Highlight the pairs with fewer pairs then minpairs if required if minpairs: for i in range(len(varpairs)): try: ax.plot(varpairs.iloc[i][h_name], varpairs.iloc[i][vario_name], marker=marker, color='#fb8072', ms=round((ms * 1.4 + 0.5), 0)) except: ax.plot(varpairs.iloc[i][h_name], varpairs.iloc[i][vario_name], marker=marker, ms=round((ms * 1.4 + 0.5), 0)) # Plot the variogram and identifier ax.plot(vardist, vardata, color=color, lw=lw, marker=marker, ls=ls, ms=ms, label=label, **kwargs) if experimental and pairnumbers and pairs_label is not None: if ylim is None: ymin, ymax = ax.get_ybound() else: ymin, ymax = ylim for x, y, lbl in zip(vardist, vardata, pairs_label): if ymin <= y <= ymax: ax.text(x, y - 0.025, int(lbl), rotation=-55) # Plot figure and axis labels if unit is None: unit = Parameters['plotting.unit'] if unit is None or unit == '': unit = '' else: unit = ' ({})'.format(unit) if xlabel is None: xlabel = Parameters['plotting.lagname'] + unit if ylabel is None: ax.set_ylabel(r'$\gamma$ ', fontsize=mpl.rcParams['font.size'] * Parameters['plotting.gammasize'], rotation=0) elif ylabel: ax.set_ylabel(ylabel) # Draw Sill if sill: ax.axhline(sill, color='black') # Set plot limits if ylim is None: if sill == 1: ylim = (0, 1.2) elif abs(sill) < 1: # If the sill is bellow 1, it's likely a cross variogram if sill < 0: # Positive default which also draws a line at 0 ylim = (-1, 0.2) ax.axhline(0, color='black', linestyle='--', lw=0.5, dashes=(2, 2)) if sill >= 0: # Positive defaults ylim = (0, 1.2) if xlim is None: xmin, xmax = ax.get_xbound() xlim = [0, xmax] ax = format_plot(ax, xlabel=xlabel, title=title, grid=grid, axis_xy=axis_xy, xlim=xlim, ylim=ylim) # Export figure if output_file or ('pdfpages' in out_kws): export_image(output_file, **out_kws) # Return axis return ax