Source code for verde.synthetic

# Copyright (c) 2017 The Verde Developers.
# Distributed under the terms of the BSD 3-Clause License.
# SPDX-License-Identifier: BSD-3-Clause
#
# This code is part of the Fatiando a Terra project (https://www.fatiando.org)
#
import numpy as np
import pandas as pd

from .base import BaseGridder
from .base.base_classes import get_instance_region, project_coordinates
from .base.utils import check_data
from .coordinates import check_region, scatter_points


[docs]class CheckerBoard(BaseGridder): r""" Generate synthetic data in a checkerboard pattern. The mathematical model is: .. math:: f(e, n) = a \sin\left(\frac{2\pi}{w_e} e\right) \cos\left(\frac{2\pi}{w_n} n\right) in which :math:`e` is the easting coordinate, :math:`n` is the northing coordinate, :math:`a` is the amplitude, and :math:`w_e` and :math:`w_n` are the wavelengths in the east and north directions, respectively. Parameters ---------- amplitude : float The amplitude of the checkerboard undulations. region : tuple The boundaries (``[W, E, S, N]``) of the region used to generate the synthetic data. w_east : float The wavelength in the east direction. Defaults to half of the West-East size of the evaluating region. w_north : float The wavelength in the north direction. Defaults to half of the South-North size of the evaluating region. Examples -------- >>> synth = CheckerBoard() >>> # Default values for the wavelengths are selected automatically >>> print(synth.w_east_, synth.w_north_) 2500.0 2500.0 >>> # CheckerBoard.grid produces an xarray.Dataset with data on a grid >>> grid = synth.grid(shape=(11, 6)) >>> # scatter and profile generate pandas.DataFrame objects >>> table = synth.scatter() >>> print(sorted(table.columns)) ['easting', 'northing', 'scalars'] >>> profile = synth.profile(point1=(0, 0), point2=(2500, -2500), size=100) >>> print(sorted(profile.columns)) ['distance', 'easting', 'northing', 'scalars'] """ def __init__( self, amplitude=1000, region=(0, 5000, -5000, 0), w_east=None, w_north=None ): super().__init__() self.amplitude = amplitude self.w_east = w_east self.w_north = w_north self.region = region @property def w_east_(self): "Use half of the E-W extent" if self.w_east is None: return (self.region[1] - self.region[0]) / 2 return self.w_east @property def w_north_(self): "Use half of the N-S extent" if self.w_north is None: return (self.region[3] - self.region[2]) / 2 return self.w_north @property def region_(self): "Used to fool the BaseGridder methods" check_region(self.region) return self.region
[docs] def predict(self, coordinates): """ Evaluate the checkerboard function on a given set of points. Parameters ---------- coordinates : tuple of arrays Arrays with the coordinates of each data point. Should be in the following order: (easting, northing, vertical, ...). Only easting and northing will be used, all subsequent coordinates will be ignored. Returns ------- data : array The evaluated checkerboard function. """ easting, northing = coordinates[:2] data = ( self.amplitude * np.sin((2 * np.pi / self.w_east_) * easting) * np.cos((2 * np.pi / self.w_north_) * northing) ) return data
[docs] def scatter( self, region=None, size=300, random_state=0, dims=None, data_names=None, projection=None, **kwargs, ): """ Generate values on a random scatter of points. Point coordinates are generated by :func:`verde.scatter_points`. Other arguments for this function can be passed as extra keyword arguments (``kwargs``) to this method. By default, the region specified when creating the class instance will be used if ``region=None``. Use the *dims* and *data_names* arguments to set custom names for the dimensions and the data field(s) in the output :class:`pandas.DataFrame`. Default names are provided. Parameters ---------- region : list = [W, E, S, N] The west, east, south, and north boundaries of a given region. size : int The number of points to generate. random_state : numpy.random.RandomState or an int seed A random number generator used to define the state of the random permutations. Use a fixed seed to make sure computations are reproducible. Use ``None`` to choose a seed automatically (resulting in different numbers with each run). dims : list or None The names of the northing and easting data dimensions, respectively, in the output dataframe. Default is determined from the ``dims`` attribute of the class. Must be defined in the following order: northing dimension, easting dimension. **NOTE: This is an exception to the "easting" then "northing" pattern but is required for compatibility with xarray.** data_names : str, list or None The name(s) of the data variables in the output dataframe. Defaults to ``'scalars'`` for scalar data, ``['east_component', 'north_component']`` for 2D vector data, and ``['east_component', 'north_component', 'vertical_component']`` for 3D vector data. projection : callable or None If not None, then should be a callable object ``projection(easting, northing) -> (proj_easting, proj_northing)`` that takes in easting and northing coordinate arrays and returns projected northing and easting coordinate arrays. This function will be used to project the generated scatter coordinates before passing them into ``predict``. For example, you can use this to generate a geographic scatter from a Cartesian gridder. Returns ------- table : pandas.DataFrame The interpolated values on a random set of points. """ dims = self._get_dims(dims) region = get_instance_region(self, region) coordinates = scatter_points(region, size, random_state=random_state, **kwargs) if projection is None: data = check_data(self.predict(coordinates)) else: data = check_data( self.predict(project_coordinates(coordinates, projection)) ) data_names = self._get_data_names(data, data_names) columns = [(dims[0], coordinates[1]), (dims[1], coordinates[0])] extra_coords_names = self._get_extra_coords_names(coordinates) columns.extend(zip(extra_coords_names, coordinates[2:])) columns.extend(zip(data_names, data)) return pd.DataFrame(dict(columns), columns=[c[0] for c in columns])