data.py 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. from __future__ import annotations
  2. from typing import TYPE_CHECKING, Any
  3. import numpy as np
  4. if TYPE_CHECKING:
  5. from contourpy._contourpy import CoordinateArray
  6. def simple(
  7. shape: tuple[int, int], want_mask: bool = False,
  8. ) -> tuple[CoordinateArray, CoordinateArray, CoordinateArray | np.ma.MaskedArray[Any, Any]]:
  9. """Return simple test data consisting of the sum of two gaussians.
  10. Args:
  11. shape (tuple(int, int)): 2D shape of data to return.
  12. want_mask (bool, optional): Whether test data should be masked or not, default ``False``.
  13. Return:
  14. Tuple of 3 arrays: ``x``, ``y``, ``z`` test data, ``z`` will be masked if
  15. ``want_mask=True``.
  16. """
  17. ny, nx = shape
  18. x = np.arange(nx, dtype=np.float64)
  19. y = np.arange(ny, dtype=np.float64)
  20. x, y = np.meshgrid(x, y)
  21. xscale = nx - 1.0
  22. yscale = ny - 1.0
  23. # z is sum of 2D gaussians.
  24. amp = np.asarray([1.0, -1.0, 0.8, -0.9, 0.7])
  25. mid = np.asarray([[0.4, 0.2], [0.3, 0.8], [0.9, 0.75], [0.7, 0.3], [0.05, 0.7]])
  26. width = np.asarray([0.4, 0.2, 0.2, 0.2, 0.1])
  27. z = np.zeros_like(x)
  28. for i in range(len(amp)):
  29. z += amp[i]*np.exp(-((x/xscale - mid[i, 0])**2 + (y/yscale - mid[i, 1])**2) / width[i]**2)
  30. if want_mask:
  31. mask = np.logical_or(
  32. ((x/xscale - 1.0)**2 / 0.2 + (y/yscale - 0.0)**2 / 0.1) < 1.0,
  33. ((x/xscale - 0.2)**2 / 0.02 + (y/yscale - 0.45)**2 / 0.08) < 1.0,
  34. )
  35. z = np.ma.array(z, mask=mask) # type: ignore[no-untyped-call]
  36. return x, y, z
  37. def random(
  38. shape: tuple[int, int], seed: int = 2187, mask_fraction: float = 0.0,
  39. ) -> tuple[CoordinateArray, CoordinateArray, CoordinateArray | np.ma.MaskedArray[Any, Any]]:
  40. """Return random test data.
  41. Args:
  42. shape (tuple(int, int)): 2D shape of data to return.
  43. seed (int, optional): Seed for random number generator, default 2187.
  44. mask_fraction (float, optional): Fraction of elements to mask, default 0.
  45. Return:
  46. Tuple of 3 arrays: ``x``, ``y``, ``z`` test data, ``z`` will be masked if
  47. ``mask_fraction`` is greater than zero.
  48. """
  49. ny, nx = shape
  50. x = np.arange(nx, dtype=np.float64)
  51. y = np.arange(ny, dtype=np.float64)
  52. x, y = np.meshgrid(x, y)
  53. rng = np.random.default_rng(seed)
  54. z = rng.uniform(size=shape)
  55. if mask_fraction > 0.0:
  56. mask_fraction = min(mask_fraction, 0.99)
  57. mask = rng.uniform(size=shape) < mask_fraction
  58. z = np.ma.array(z, mask=mask) # type: ignore[no-untyped-call]
  59. return x, y, z