Repository: fatiando/verde (python)

Issue:
Function to generate a 2D point scatter
Need a `scatter(region, size, random_state=None)` function to generate random coordinate pairs inside a given area. Use a uniform distribution. `region` is `[west, east, south, north]` in geographic or cartesian coordinates.  Should return two arrays with easting and northing coordinates.

Pull request:
Add function to generate a scatter of points
Copied over from fatiando.gridder. Uses numpy.random.RandomState.uniform
to generate coordinates for points on a 2D plane. Implements a utility
function `check_region` to make sure the common region argument is
correctly specified.

Fixes #1 


Patch:
diff --git a/verde/__init__.py b/verde/__init__.py
index 15c7b7a..cf1980d 100644
--- a/verde/__init__.py
+++ b/verde/__init__.py
@@ -4,6 +4,9 @@ The Verde public API.
 from ._version import get_versions as _get_versions
 
 # Import functions/classes to make the API
+from .utils import scatter_points
+
+
 # Get the version number through versioneer
 __version__ = _get_versions()['version']
 __commit__ = _get_versions()['full-revisionid']
diff --git a/verde/utils.py b/verde/utils.py
new file mode 100644
index 0000000..b7cb8bc
--- /dev/null
+++ b/verde/utils.py
@@ -0,0 +1,76 @@
+"""
+General utilities for dealing with grids and point generation.
+"""
+from numpy.random import RandomState
+
+
+def check_region(region):
+    """
+    Check that the given region dimensions are valid.
+
+    For example, the west limit should not be greater than the east and there
+    must be exactly 4 values given.
+
+    Parameters
+    ----------
+    region : list
+        The boundaries (``[W, E, S, N]``) of a given region in Cartesian or
+        geographic coordinates.
+
+    Raises
+    ------
+    ValueError
+        If the region doesn't have exactly 4 entries, W > E, or S > N.
+
+    """
+    if len(region) != 4:
+        raise ValueError("Invalid region '{}'. Only 4 values allowed."
+                         .format(region))
+    w, e, s, n = region
+    if w > e:
+        raise ValueError("Invalid region '{}' (W, E, S, N). Must have W =< E."
+                         .format(region))
+    if s > n:
+        raise ValueError("Invalid region '{}' (W, E, S, N). Must have S =< N."
+                         .format(region))
+
+
+def scatter_points(region, size, random_seed=None):
+    """
+    Generate the coordinates for a random scatter of points.
+
+    The points are drawn from a uniform distribution.
+
+    Parameters
+    ----------
+    region : list
+        The boundaries (``[W, E, S, N]``) of a given region in Cartesian or
+        geographic coordinates.
+    size : int
+        The number of points to generate.
+    random_seed : None or int
+        Value used to seed the random number generator.
+
+    Returns
+    -------
+    easting, northing : 1d arrays
+        The West-East and South-North coordinates of each point.
+
+    Examples
+    --------
+
+    >>> # We'll use a seed value will ensure that the same will be generated
+    >>> # every time.
+    >>> easting, northing = scatter_points((0, 10, -2, -1), 4, random_seed=0)
+    >>> print(', '.join(['{:.4f}'.format(i) for i in easting]))
+    5.4881, 7.1519, 6.0276, 5.4488
+    >>> print(', '.join(['{:.4f}'.format(i) for i in northing]))
+    -1.5763, -1.3541, -1.5624, -1.1082
+
+    """
+    check_region(region)
+    random = RandomState(seed=random_seed)
+    w, e, s, n = region
+    easting = random.uniform(w, e, size)
+    northing = random.uniform(s, n, size)
+    return easting, northing


Test patch:
diff --git a/verde/tests/test_utils.py b/verde/tests/test_utils.py
new file mode 100644
index 0000000..9d9ac7d
--- /dev/null
+++ b/verde/tests/test_utils.py
@@ -0,0 +1,24 @@
+"""
+Test the misc utilities in verde
+"""
+import pytest
+
+from ..utils import check_region
+
+
+def test_check_region():
+    "Make sure an exception is raised for bad regions"
+    with pytest.raises(ValueError):
+        check_region([])
+    with pytest.raises(ValueError):
+        check_region([1, 2, 3, 4, 5])
+    with pytest.raises(ValueError):
+        check_region([1, 2, 3])
+    with pytest.raises(ValueError):
+        check_region([1, 2, 3, 1])
+    with pytest.raises(ValueError):
+        check_region([2, 1, 3, 4])
+    with pytest.raises(ValueError):
+        check_region([-1, -2, -4, -3])
+    with pytest.raises(ValueError):
+        check_region([-2, -1, -2, -3])