From 9645854900a41d58ffdd09a3e899ffdef6da247d Mon Sep 17 00:00:00 2001 From: Jake Faulkner Date: Wed, 9 Jul 2025 11:54:09 +1200 Subject: [PATCH 1/5] refactor: use a dynamically determined grid scale for a region based on size --- visualisation/sources/plot_rise.py | 6 +++--- visualisation/sources/plot_srf.py | 5 +++-- visualisation/utils.py | 24 ++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/visualisation/sources/plot_rise.py b/visualisation/sources/plot_rise.py index 0d98b27..4f2b9a0 100644 --- a/visualisation/sources/plot_rise.py +++ b/visualisation/sources/plot_rise.py @@ -53,12 +53,12 @@ def plot_rise( fig = plotting.gen_region_fig( title, projection=f"M{width}c", region=region, map_data=None ) - + grid_scale = plotting.grid_scale_for_region(region) for i, segment_points in enumerate(srf_data.segments): cur_grid = plotting.create_grid( segment_points, "trise", - grid_spacing="5e/5e", + grid_spacing=f"{grid_scale}e/{grid_scale}e", region=( segment_points["lon"].min(), segment_points["lon"].max(), @@ -82,7 +82,7 @@ def plot_rise( time_grid = plotting.create_grid( segment_points, "tinit", - grid_spacing="5e/5e", + grid_spacing=f"{grid_scale}e/{grid_scale}e", region=( segment_points["lon"].min(), segment_points["lon"].max(), diff --git a/visualisation/sources/plot_srf.py b/visualisation/sources/plot_srf.py index 3205c4a..9adfd1c 100644 --- a/visualisation/sources/plot_srf.py +++ b/visualisation/sources/plot_srf.py @@ -119,6 +119,7 @@ def show_slip( ) dx = srf_data.header.iloc[0]["len"] / srf_data.header.iloc[0]["nstk"] subtitle = f"Slip: {slip_stats}, dx = {dx:.2f} km, {len(srf_data.header)} planes" + grid_scale = grid_scale_for_region(region) for (_, segment), segment_points in zip( srf_data.header.iterrows(), srf_data.segments ): @@ -129,7 +130,7 @@ def show_slip( cur_grid = plotting.create_grid( segment_points, "slip", - grid_spacing="5e/5e", + grid_spacing=f"{grid_scale}e/{grid_scale}e", region=( segment_points["lon"].min(), segment_points["lon"].max(), @@ -156,7 +157,7 @@ def show_slip( time_grid = plotting.create_grid( segment_points, "tinit", - grid_spacing="5e/5e", + grid_spacing=f"{grid_scale}e/{grid_scale}e", region=( segment_points["lon"].min(), segment_points["lon"].max(), diff --git a/visualisation/utils.py b/visualisation/utils.py index 6eeb860..4df312e 100644 --- a/visualisation/utils.py +++ b/visualisation/utils.py @@ -292,3 +292,27 @@ def bounding_region_for( min_latitude - latitude_pad, max_latitude + latitude_pad, ) + + +def grid_scale_for_region(region: tuple[float, float, float, float]) -> float: + """Compute a suitable grid scale for a pygmt region. + + Parameters + ---------- + region : tuple[float, float, float, float] + The pygmt region you will plot a grid in. + + Returns + ------- + int + A value (in metres) represent for `plotting.create_grid` to + use when plotting the lat-lon grid. Scale is based on the + maximum extent in the lat or lon direction for the figure in + kilometres. Works out that 10km = 25m, 100km = 250m, with a + minimum resolution of 5m. + """ + min_lon, max_lon, min_lat, max_lat = region + lat_km = (max_lat - min_lat) * 111 + lon_km = 111 * np.cos(np.radians((min_lat + max_lat) / 2)) + maximum_extent = max(lat_km, lon_km) + return int(round(max(5, 2.5 * maximum_extent))) From f2374c1934f73e4cfe9a95268cb5cba0839e7cfd Mon Sep 17 00:00:00 2001 From: Jake Faulkner Date: Wed, 9 Jul 2025 12:14:57 +1200 Subject: [PATCH 2/5] fix: call grid scale correctly --- tests/test_plots.py | 12 ++++++------ visualisation/sources/plot_rise.py | 3 ++- visualisation/sources/plot_srf.py | 2 +- visualisation/sources/plot_srf_distribution.py | 3 ++- visualisation/sources/plot_stoch.py | 2 +- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/tests/test_plots.py b/tests/test_plots.py index 1b98960..d4fcf39 100644 --- a/tests/test_plots.py +++ b/tests/test_plots.py @@ -90,12 +90,12 @@ def assert_images_match( Compares two images using diffimg and asserts the difference is within tolerance. Provides informative assertion messages. """ - assert ( - generated_path.exists() - ), f"Generated image file does not exist: {generated_path}" - assert ( - expected_path.exists() - ), f"Expected image file does not exist: {expected_path}" + assert generated_path.exists(), ( + f"Generated image file does not exist: {generated_path}" + ) + assert expected_path.exists(), ( + f"Expected image file does not exist: {expected_path}" + ) diff_ratio = diffimg.diff(expected_path, generated_path) diff --git a/visualisation/sources/plot_rise.py b/visualisation/sources/plot_rise.py index 4f2b9a0..dea0e76 100644 --- a/visualisation/sources/plot_rise.py +++ b/visualisation/sources/plot_rise.py @@ -8,6 +8,7 @@ from pygmt_helper import plotting from qcore import cli from source_modelling import srf +from visualisation import utils app = typer.Typer() @@ -53,7 +54,7 @@ def plot_rise( fig = plotting.gen_region_fig( title, projection=f"M{width}c", region=region, map_data=None ) - grid_scale = plotting.grid_scale_for_region(region) + grid_scale = utils.grid_scale_for_region(region) for i, segment_points in enumerate(srf_data.segments): cur_grid = plotting.create_grid( segment_points, diff --git a/visualisation/sources/plot_srf.py b/visualisation/sources/plot_srf.py index 9adfd1c..ee20ec3 100644 --- a/visualisation/sources/plot_srf.py +++ b/visualisation/sources/plot_srf.py @@ -119,7 +119,7 @@ def show_slip( ) dx = srf_data.header.iloc[0]["len"] / srf_data.header.iloc[0]["nstk"] subtitle = f"Slip: {slip_stats}, dx = {dx:.2f} km, {len(srf_data.header)} planes" - grid_scale = grid_scale_for_region(region) + grid_scale = utils.grid_scale_for_region(region) for (_, segment), segment_points in zip( srf_data.header.iterrows(), srf_data.segments ): diff --git a/visualisation/sources/plot_srf_distribution.py b/visualisation/sources/plot_srf_distribution.py index a82dd3a..ddedcd9 100644 --- a/visualisation/sources/plot_srf_distribution.py +++ b/visualisation/sources/plot_srf_distribution.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 """Plot SRF distributions.""" + from pathlib import Path from typing import Annotated, Optional @@ -46,7 +47,7 @@ def plot_srf_distribution( ax.set_xlabel("Slip (cm)") ax.set_title( title - or f'Slip PDF for {srf_ffp.stem} ({utils.format_description(srf_data.points["slip"], compact=True)})' + or f"Slip PDF for {srf_ffp.stem} ({utils.format_description(srf_data.points['slip'], compact=True)})" ) plt.savefig(plot_png, dpi=dpi) diff --git a/visualisation/sources/plot_stoch.py b/visualisation/sources/plot_stoch.py index 15fe88e..d305965 100644 --- a/visualisation/sources/plot_stoch.py +++ b/visualisation/sources/plot_stoch.py @@ -82,7 +82,7 @@ def plot_stoch( ax.text( k * dx + dx / 2, (j * dy + dy / 2), - f"{int(slip[j, k])}", + f"{int(slip[j, k])}", ha="center", va="center", color=colour, From d86d370b7a8d8d3cadfab23c6f4e15cf55e05096 Mon Sep 17 00:00:00 2001 From: Jake Faulkner Date: Wed, 9 Jul 2025 12:22:27 +1200 Subject: [PATCH 3/5] fix: ensure resolution is at least the SRF segment resolution --- visualisation/sources/plot_rise.py | 3 ++- visualisation/sources/plot_srf.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/visualisation/sources/plot_rise.py b/visualisation/sources/plot_rise.py index dea0e76..b9153f4 100644 --- a/visualisation/sources/plot_rise.py +++ b/visualisation/sources/plot_rise.py @@ -54,7 +54,8 @@ def plot_rise( fig = plotting.gen_region_fig( title, projection=f"M{width}c", region=region, map_data=None ) - grid_scale = utils.grid_scale_for_region(region) + dx = srf_data.header.iloc[0]["len"] / srf_data.header.iloc[0]["nstk"] + grid_scale = min(utils.grid_scale_for_region(region), dx * 1000) for i, segment_points in enumerate(srf_data.segments): cur_grid = plotting.create_grid( segment_points, diff --git a/visualisation/sources/plot_srf.py b/visualisation/sources/plot_srf.py index ee20ec3..54d75a8 100644 --- a/visualisation/sources/plot_srf.py +++ b/visualisation/sources/plot_srf.py @@ -119,7 +119,7 @@ def show_slip( ) dx = srf_data.header.iloc[0]["len"] / srf_data.header.iloc[0]["nstk"] subtitle = f"Slip: {slip_stats}, dx = {dx:.2f} km, {len(srf_data.header)} planes" - grid_scale = utils.grid_scale_for_region(region) + grid_scale = min(utils.grid_scale_for_region(region), dx * 1000) for (_, segment), segment_points in zip( srf_data.header.iterrows(), srf_data.segments ): From e2656f607d3382c9b8114fbe40dd9e4a9803549a Mon Sep 17 00:00:00 2001 From: Jake Faulkner Date: Wed, 9 Jul 2025 13:22:40 +1200 Subject: [PATCH 4/5] Fix longitude scale Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- visualisation/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/visualisation/utils.py b/visualisation/utils.py index 4df312e..5fb4c0f 100644 --- a/visualisation/utils.py +++ b/visualisation/utils.py @@ -313,6 +313,6 @@ def grid_scale_for_region(region: tuple[float, float, float, float]) -> float: """ min_lon, max_lon, min_lat, max_lat = region lat_km = (max_lat - min_lat) * 111 - lon_km = 111 * np.cos(np.radians((min_lat + max_lat) / 2)) + lon_km = (max_lon - min_lon) * 111 * np.cos(np.radians((min_lat + max_lat) / 2)) maximum_extent = max(lat_km, lon_km) return int(round(max(5, 2.5 * maximum_extent))) From 72a02620eb46350a83b124fe3f7a3f2e417b105e Mon Sep 17 00:00:00 2001 From: Jake Faulkner Date: Wed, 9 Jul 2025 13:23:14 +1200 Subject: [PATCH 5/5] fix: return type of grid scale for region Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- visualisation/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/visualisation/utils.py b/visualisation/utils.py index 5fb4c0f..7a2694a 100644 --- a/visualisation/utils.py +++ b/visualisation/utils.py @@ -294,7 +294,7 @@ def bounding_region_for( ) -def grid_scale_for_region(region: tuple[float, float, float, float]) -> float: +def grid_scale_for_region(region: tuple[float, float, float, float]) -> int: """Compute a suitable grid scale for a pygmt region. Parameters