Skip to content

Commit

Permalink
Moved get_cum_fmd to utils and added get_fmd + plot_fmd_classic
Browse files Browse the repository at this point in the history
  • Loading branch information
adzubay committed Jul 14, 2023
1 parent f2f4cb5 commit efafc5b
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 82 deletions.
109 changes: 61 additions & 48 deletions catalog_tools/plots/basics.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import Optional, Union

# Own functions
from catalog_tools.utils.binning import bin_to_precision
from catalog_tools.utils.binning import bin_to_precision, get_cum_fmd, get_fmd


def gutenberg_richter(magnitudes: np.ndarray, b_value: float,
Expand Down Expand Up @@ -87,43 +87,6 @@ def plot_cum_fmd(
return ax


def get_cum_fmd(
mags: np.ndarray,
delta_m: float,
left: bool = False
) -> [np.ndarray, np.ndarray, np.ndarray]:
""" Calculates cumulative event counts across all magnitude units
(summed from the right). Note that the returned bins array contains
the center point of each bin unless left is True.
Args:
mags : array of magnitudes
delta_m : discretization of the magnitudes
left : When True, left edges of bins are returned. When false,
center points are returned.
Returns:
bins : array of bin centers (right to left)
c_counts: cumulative counts for each bin ("")
mags : array of magnitudes binned to delta_m
"""
mags = bin_to_precision(mags, delta_m)
mags_i = bin_to_precision(mags / delta_m - np.min(mags / delta_m), 1)
mags_i = mags_i.astype(int)
counts = np.bincount(mags_i)
bins = bin_to_precision(np.arange((np.min(mags)) * 10000,
(np.max(mags) + delta_m / 2) * 10000,
delta_m * 10000) / 10000, delta_m)

bins = bins[::-1]
c_counts = np.cumsum(counts[::-1])

if left:
bins = bins - delta_m / 2

return bins, c_counts, mags


def plot_cum_fmd_classic(
mags: np.ndarray,
ax: Optional[plt.Axes] = None,
Expand Down Expand Up @@ -238,11 +201,61 @@ def plot_fmd(
return ax


def plot_fmd_classic(
mags: np.ndarray,
ax: Optional[plt.Axes] = None,
delta_m: float = 0.1,
color: str = 'blue',
size: int = 3,
grid: bool = False,
left: bool = False
) -> plt.Axes:
""" Plots frequency magnitude distribution. Unlike plot_fmd,
plots values for all bins and requires binning.
Args:
mags : array of magnitudes
ax : axis where figure should be plotted
delta_m : discretization of the magnitudes, important for the correct
visualization of the data
color : color of the data.
size : size of scattered data
grid : bool, include grid lines or not
left : When True, left edges of bins are returned. When false,
center points are returned.
Returns:
ax that was plotted on
"""

mags = mags[~np.isnan(mags)]

if delta_m == 0:
delta_m = 0.1

bins, counts, mags = get_fmd(mags, delta_m, left=left)

if ax is None:
ax = plt.subplots()[1]

ax.scatter(bins, counts, s=size,
color=color, marker='^')
ax.set_yscale('log')
ax.set_xlabel('Magnitude')
ax.set_ylabel('N')

if grid is True:
ax.grid(True)
ax.grid(which='minor', alpha=0.3)

return ax


def plot_cum_count(
cat: pd.DataFrame,
ax: Optional[plt.Axes] = None,
mcs: Optional[np.ndarray] = np.array([0]),
delta_m: Optional[float] = 0.1,
cat: pd.DataFrame,
ax: Optional[plt.Axes] = None,
mcs: Optional[np.ndarray] = np.array([0]),
delta_m: Optional[float] = 0.1,
) -> plt.Axes:
"""
Plots cumulative count of earthquakes in given catalog above given Mc
Expand Down Expand Up @@ -270,7 +283,7 @@ def plot_cum_count(
ax = plt.subplots()[1]

for mc in mcs:
cat_above_mc = cat.query(f"magnitude>={mc-delta_m/2}")
cat_above_mc = cat.query(f"magnitude>={mc - delta_m / 2}")
times = sorted(cat_above_mc["time"])
times_adjusted = [first_time, *times, last_time]

Expand All @@ -285,10 +298,10 @@ def plot_cum_count(


def plot_mags_in_time(
cat: pd.DataFrame,
ax: Optional[plt.Axes] = None,
years: Optional[list] = None,
mcs: Optional[list] = None
cat: pd.DataFrame,
ax: Optional[plt.Axes] = None,
years: Optional[list] = None,
mcs: Optional[list] = None
) -> plt.Axes:
"""
Creates a scatter plot, each dot is an event. Time shown on x-axis,
Expand Down Expand Up @@ -318,7 +331,7 @@ def plot_mags_in_time(

if ax is None:
ax = plt.subplots()[1]
ax.scatter(cat_years, cat["magnitude"], cat["magnitude"]**2)
ax.scatter(cat_years, cat["magnitude"], cat["magnitude"] ** 2)

if years is not None and mcs is not None:
years.append(np.max(cat_years) + 1)
Expand Down
34 changes: 1 addition & 33 deletions catalog_tools/plots/tests/test_basics.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import pytest
import numpy as np
from numpy.testing import assert_allclose

from catalog_tools.plots.basics import dot_size, get_cum_fmd
from catalog_tools.plots.basics import dot_size


def test_dot_size():
Expand Down Expand Up @@ -38,34 +37,3 @@ def test_dot_size():

# Check that the computed sizes are close to the expected ones
assert_allclose(sizes, expected_sizes, rtol=tolerance, atol=tolerance)


@pytest.mark.parametrize(
"magnitudes, delta_m, bins, c_counts, left",
[(np.array([0.20990507, 0.04077336, 0.27906596, 0.57406287, 0.64256544,
0.07293118, 0.58589873, 0.02678655, 0.27631233, 0.17682814]),
0.1, np.array([0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0]),
np.array([3, 3, 3, 5, 7, 8, 10]), False),
(np.array([0.02637757, 0.06353823, 0.10257919, 0.54494906, 0.03928375,
0.08825028, 0.77713586, 0.54553981, 0.69315583, 0.06656642,
0.29035447, 0.2051877, 0.30858087, 0.68896342, 0.03328782,
0.45016109, 0.40779409, 0.06788892, 0.02684032, 0.56140282,
0.29443359, 0.36328762, 0.17124489, 0.02154936, 0.36461541,
0.03613088, 0.15798366, 0.09111875, 0.16169287, 0.11986668,
0.10232035, 0.72695761, 0.19484174, 0.0459675, 0.40514163,
0.08979514, 0.0442659, 0.18672424, 0.21239088, 0.02287468,
0.1244267, 0.04939361, 0.11232758, 0.02706083, 0.04275401,
0.02732529, 0.83884229, 0.4147758, 0.07416183, 0.05636252]),
0.2, np.array([0.7, 0.5, 0.3, 0.1, -0.1]), np.array([3, 8,
15, 29, 50]), True)]
)
def test_get_cum_fmd(magnitudes: np.ndarray, delta_m: float,
bins: np.ndarray, c_counts: np.ndarray, left: bool):
errors = []
nbins, nc_counts, nmags = get_cum_fmd(magnitudes, delta_m, left=left)
if not np.allclose(bins, nbins, atol=1e-10):
errors.append("Incorrect bin values.")
if not np.allclose(c_counts, nc_counts, atol=1e-10):
errors.append("Incorrect cumulative counts.")

assert not errors, "errors occurred:\n{}".format("\n".join(errors))
62 changes: 62 additions & 0 deletions catalog_tools/utils/binning.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,65 @@ def bin_to_precision(x: Union[np.ndarray, list], delta_x: float = 0.1
d = decimal.Decimal(str(delta_x))
decimal_places = abs(d.as_tuple().exponent)
return np.round(normal_round_to_int(x / delta_x) * delta_x, decimal_places)


def get_fmd(
mags: np.ndarray,
delta_m: float,
left: bool = False
) -> [np.ndarray, np.ndarray, np.ndarray]:
""" Calculates event counts across all magnitude units
(summed from the right). Note that the returned bins array contains
the center point of each bin unless left is True.
Args:
mags : array of magnitudes
delta_m : discretization of the magnitudes
left : When True, left edges of bins are returned. When false,
center points are returned.
Returns:
bins : array of bin centers (left to right)
counts : counts for each bin ("")
mags : array of magnitudes binned to delta_m
"""
mags = bin_to_precision(mags, delta_m)
mags_i = bin_to_precision(mags / delta_m - np.min(mags / delta_m), 1)
mags_i = mags_i.astype(int)
counts = np.bincount(mags_i)
bins = bin_to_precision(np.arange((np.min(mags)) * 10000,
(np.max(mags) + delta_m / 2) * 10000,
delta_m * 10000) / 10000, delta_m)

if left:
bins = bins - delta_m / 2

return bins, counts, mags


def get_cum_fmd(
mags: np.ndarray,
delta_m: float,
left: bool = False
) -> [np.ndarray, np.ndarray, np.ndarray]:
""" Calculates cumulative event counts across all magnitude units
(summed from the right). Note that the returned bins array contains
the center point of each bin unless left is True.
Args:
mags : array of magnitudes
delta_m : discretization of the magnitudes
left : When True, left edges of bins are returned. When false,
center points are returned.
Returns:
bins : array of bin centers (left to right)
c_counts: cumulative counts for each bin ("")
mags : array of magnitudes binned to delta_m
"""
bins, counts, mags = get_fmd(mags, delta_m, left)

c_counts = np.cumsum(counts[::-1])
c_counts = c_counts[::-1]

return bins, c_counts, mags
67 changes: 66 additions & 1 deletion catalog_tools/utils/tests/test_binning.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from catalog_tools.utils.binning import normal_round_to_int, normal_round
from catalog_tools.utils.binning import normal_round_to_int, normal_round, get_fmd, get_cum_fmd
from catalog_tools.utils.binning import bin_to_precision

import pytest
Expand Down Expand Up @@ -42,3 +42,68 @@ def test_bin_to_precision(x: np.ndarray, delta_x: float,
rounded_value: np.ndarray):
y = bin_to_precision(x, delta_x)
assert (y == rounded_value).all()


@pytest.mark.parametrize(
"magnitudes, delta_m, bins, c_counts, left",
[(np.array([0.20990507, 0.04077336, 0.27906596, 0.57406287, 0.64256544,
0.07293118, 0.58589873, 0.02678655, 0.27631233, 0.17682814]),
0.1, np.array([0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6]),
np.array([10, 8, 7, 5, 3, 3, 3]), False),
(np.array([0.02637757, 0.06353823, 0.10257919, 0.54494906, 0.03928375,
0.08825028, 0.77713586, 0.54553981, 0.69315583, 0.06656642,
0.29035447, 0.2051877, 0.30858087, 0.68896342, 0.03328782,
0.45016109, 0.40779409, 0.06788892, 0.02684032, 0.56140282,
0.29443359, 0.36328762, 0.17124489, 0.02154936, 0.36461541,
0.03613088, 0.15798366, 0.09111875, 0.16169287, 0.11986668,
0.10232035, 0.72695761, 0.19484174, 0.0459675, 0.40514163,
0.08979514, 0.0442659, 0.18672424, 0.21239088, 0.02287468,
0.1244267, 0.04939361, 0.11232758, 0.02706083, 0.04275401,
0.02732529, 0.83884229, 0.4147758, 0.07416183, 0.05636252]),
0.2, np.array([-0.1, 0.1, 0.3, 0.5, 0.7]), np.array([50, 29,
15, 8, 3]), True)]
)
def test_get_cum_fmd(magnitudes: np.ndarray, delta_m: float,
bins: np.ndarray, c_counts: np.ndarray, left: bool):
errors = []
nbins, nc_counts, nmags = get_cum_fmd(magnitudes, delta_m, left=left)
print(bins)
print(nbins)
if not np.allclose(bins, nbins, atol=1e-10):
errors.append("Incorrect bin values.")
if not np.allclose(c_counts, nc_counts, atol=1e-10):
errors.append("Incorrect cumulative counts.")

assert not errors, "errors occurred:\n{}".format("\n".join(errors))


@pytest.mark.parametrize(
"magnitudes, delta_m, bins, counts, left",
[(np.array([0.20990507, 0.04077336, 0.27906596, 0.57406287, 0.64256544,
0.07293118, 0.58589873, 0.02678655, 0.27631233, 0.17682814]),
0.1, np.array([0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6]),
np.array([2, 1, 2, 2, 0, 0, 3]), False),
(np.array([0.02637757, 0.06353823, 0.10257919, 0.54494906, 0.03928375,
0.08825028, 0.77713586, 0.54553981, 0.69315583, 0.06656642,
0.29035447, 0.2051877, 0.30858087, 0.68896342, 0.03328782,
0.45016109, 0.40779409, 0.06788892, 0.02684032, 0.56140282,
0.29443359, 0.36328762, 0.17124489, 0.02154936, 0.36461541,
0.03613088, 0.15798366, 0.09111875, 0.16169287, 0.11986668,
0.10232035, 0.72695761, 0.19484174, 0.0459675, 0.40514163,
0.08979514, 0.0442659, 0.18672424, 0.21239088, 0.02287468,
0.1244267, 0.04939361, 0.11232758, 0.02706083, 0.04275401,
0.02732529, 0.83884229, 0.4147758, 0.07416183, 0.05636252]),
0.2, np.array([-0.1, 0.1, 0.3, 0.5, 0.7]), np.array([21, 14,
7, 5, 3]), True)]
)
def test_get_fmd(magnitudes: np.ndarray, delta_m: float,
bins: np.ndarray, counts: np.ndarray, left: bool):
errors = []
nbins, ncounts, nmags = get_fmd(magnitudes, delta_m, left=left)

if not np.allclose(bins, nbins, atol=1e-10):
errors.append("Incorrect bin values.")
if not np.allclose(counts, ncounts, atol=1e-10):
errors.append("Incorrect counts.")

assert not errors, "errors occurred:\n{}".format("\n".join(errors))

0 comments on commit efafc5b

Please sign in to comment.