Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
6d8daef
feat: add alpine plot utilities
lispandfound Dec 9, 2025
400afaa
feat(response-rrup): add script as executable in package
lispandfound Dec 9, 2025
c579ad1
deps: add missing rpy2 dependency
lispandfound Dec 9, 2025
4e28aab
deps: add fixed xarray dependency
lispandfound Dec 9, 2025
01c6642
fix(response-rrup): explicitly use h5netcdf
lispandfound Dec 9, 2025
6591194
fix(response-rrup): legend capitalisation
lispandfound Dec 9, 2025
2b61b26
fix(response-rrup): expose `--span`
lispandfound Dec 9, 2025
d0adcfb
fix(response-rrup): add basin subplots in all-in-one
lispandfound Dec 10, 2025
3df84f3
fix(response-rrup): make basin names human readable
lispandfound Dec 10, 2025
e76a6c5
deps: pin to python < 3.14 because of numba
lispandfound Dec 10, 2025
e5a98af
fix(response-rrup): incorrect basin name function
lispandfound Dec 10, 2025
a60058c
fix(response-rrup): do not plot per-basin NSHM plots
lispandfound Dec 10, 2025
bf449e0
fix(response-rrup): do not create several plots in the all-in-one output
lispandfound Dec 10, 2025
df27db4
refactor(response-rrup): remove the omni function
lispandfound Dec 10, 2025
6f6f0c6
fix: remove titles, plot per-basin fit
lispandfound Dec 10, 2025
89fdcd4
fix(response-rrup): rrup values for plot simulation fit
lispandfound Dec 10, 2025
b44957d
fix(response-rrup): split LOESS fit from data scatter
lispandfound Dec 10, 2025
ae4bd94
fix(response-rrup): clear first
lispandfound Dec 10, 2025
7ba9866
feat: add response spectra plot
lispandfound Dec 10, 2025
3f9a81b
feat(plot-response-spectra): plot several stations at once
lispandfound Dec 10, 2025
754bb15
fix(response-rrup): use span = 1 for basin subplots
lispandfound Dec 10, 2025
70b0235
feat(response-rrup): allow xmin/xmax settings
lispandfound Dec 10, 2025
0556e00
fix(response-rrup): correctly set x-lim
lispandfound Dec 10, 2025
9dc9a64
fix(response-rrup): correct xmin/xmax passing
lispandfound Dec 10, 2025
21ccb4d
fix(response-rrup): use viridis for more basin colours
lispandfound Dec 10, 2025
ee57aaf
fix(response-rrup): no Union
lispandfound Dec 10, 2025
c86884d
fix(response-rrup): missing colourmap import
lispandfound Dec 10, 2025
a8c54c1
fix(response-rrup): use Dark2 set for colours
lispandfound Dec 11, 2025
64ff999
fix(response-rrup): make basins stand out more
lispandfound Dec 11, 2025
4efc91f
fix(response-rrup): fix legend labelling
lispandfound Dec 11, 2025
2614613
fix(response-rrup): remove simulation fit
lispandfound Dec 11, 2025
65689f4
refactor(response-rrup): use NSHM subtrend line
lispandfound Dec 11, 2025
744a842
fix(response-rrup): correct rrup references
lispandfound Dec 11, 2025
a60adf3
feat: add gmm comparison plots
lispandfound Dec 14, 2025
f1b835f
feat(plot-response-spectra): add scenario station comparison plots
lispandfound Jan 26, 2026
0c6683d
fix(gmm_comparison): dashed outline for gmm comparison
lispandfound Jan 26, 2026
17126e4
fix(response_rrup): compute site properties
lispandfound Jan 26, 2026
6e2c777
fix(realisation): handle fault and plane plotting better
lispandfound Jan 26, 2026
faa404e
refactor(plot-srf): use pygmt helper for grid generation
lispandfound Jan 26, 2026
037b0dd
refactor(plot-ts): make plot-ts work for new xyts format
lispandfound Jan 26, 2026
cb6fb35
ci: add plot-waveform utility
lispandfound Jan 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 18 additions & 17 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ readme = "README.md"
requires-python = ">=3.12"
dynamic = ["version", "dependencies"]


[project.scripts]
plot-srf-moment = "visualisation.sources.plot_srf_moment:app"
plot-domain = "visualisation.realisation:app"
Expand All @@ -25,6 +24,10 @@ plot-1d-velocity-model = "visualisation.plot_1d_velocity_model:app"
plot-rupture-path = "visualisation.plot_rupture_path:app"
plot-stoch = "visualisation.sources.plot_stoch:app"
plot-ts = "visualisation.plot_ts:app"
plot-response-rrup = "visualisation.ims.response_rrup:app"
plot-response-spectra = "visualisation.waveforms.plot_response_spectra:app"
plot-waveform = "visualisation.waveforms.plot_waveform:app"
plot-gmm-comparison = "visualisation.ims.gmm_comparison:app"

[tool.setuptools.package-dir]
visualisation = "visualisation"
Expand Down Expand Up @@ -53,7 +56,7 @@ extend-select = [
# Missing function argument type-annotation
"ANN001",
# Using except without specifying an exception type to catch
"BLE001"
"BLE001",
]
ignore = ["D104"]

Expand All @@ -62,15 +65,15 @@ convention = "numpy"

[tool.ruff.lint.isort]
known-first-party = [
"source_modelling",
"visualisation",
"workflow",
"pygmt_helper",
"qcore",
"empirical",
"nshmdb",
"IM_calculation",
"mera"
"source_modelling",
"visualisation",
"workflow",
"pygmt_helper",
"qcore",
"empirical",
"nshmdb",
"IM_calculation",
"mera",
]

[tool.ruff.lint.per-file-ignores]
Expand All @@ -80,9 +83,7 @@ known-first-party = [
"tests/**.py" = ["D"]

[tool.coverage.run]
omit = [
"visualisation/plot_ts.py"
]
omit = ["visualisation/plot_ts.py"]

[tool.numpydoc_validation]
checks = [
Expand All @@ -103,7 +104,7 @@ checks = [
"YD01",
]
# remember to use single quotes for regex in TOML
exclude = [ # don't report on objects that match any of these regex
'\.undocumented_method$',
'\.__repr__$',
exclude = [ # don't report on objects that match any of these regex
'\.undocumented_method$',
'\.__repr__$',
]
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ pytest-cov
pytest-xdist
typer
tqdm
rpy2
xarray[io]
193 changes: 193 additions & 0 deletions visualisation/ims/gmm_comparison.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
from pathlib import Path
from typing import Annotated

import numpy as np
import numpy.typing as npt
import oq_wrapper as oqw
import pandas as pd
import pygmt
import shapely
import typer
import xarray as xr

from pygmt_helper import plotting
from qcore import cli
from visualisation import realisation, utils
from workflow.realisations import (
DomainParameters,
Magnitudes,
Rakes,
RupturePropagationConfig,
SourceConfig,
)

app = typer.Typer()


def plot_diff(
fig: pygmt.Figure,
dset: xr.Dataset,
gmm_psa_value: pd.Series,
period: float,
cmap: str,
cmap_max: float | None,
cmap_min: float | None,
ticks: int,
reverse: bool,
) -> None:
intensity = dset["pSA"].sel(period=period, component="rotd50")
pgv_value = intensity.to_series()
diff = np.log(pgv_value) - gmm_psa_value
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The variable pgv_value is assigned the value of intensity, which is pSA. This naming is misleading as pSA (Pseudo-Spectral Acceleration) and PGV (Peak Ground Velocity) are distinct intensity measures. Please rename pgv_value to psa_value for clarity and correctness.

Suggested change
diff = np.log(pgv_value) - gmm_psa_value
psa_value = intensity.to_series()
diff = np.log(psa_value) - gmm_psa_value

cmap_min = cmap_min or diff.min()
cmap_max = cmap_max or diff.max()

cmap_limits = utils.range_for(cmap_min, cmap_max, ticks)

latitude = intensity.latitude.to_series()
longitude = intensity.longitude.to_series()
df = pd.DataFrame({"lat": latitude, "lon": longitude, "value": diff})

grid: xr.DataArray = plotting.create_grid(
df,
"value",
grid_spacing="1000e/1000e",
region=tuple(fig.region),
set_water_to_nan=True,
)

plotting.plot_grid(
fig,
grid,
cmap,
cmap_limits,
("red", "blue"),
reverse_cmap=reverse,
transparency=40,
plot_contours=False,
)


def find_region(domain: DomainParameters) -> tuple[float, float, float, float]:
"""Find an appropriate domain,"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The docstring for find_region is incomplete. It ends with a comma, suggesting that the description is unfinished. Please complete the docstring to clearly explain what the function does.

Suggested change
"""Find an appropriate domain,"""
def find_region(domain: DomainParameters) -> tuple[float, float, float, float]:
"""Find an appropriate domain for plotting."""

nz_region = shapely.box(166.0, -48.0, 178.5, -34.0)
region = shapely.union(
utils.polygon_nztm_to_pygmt(domain.domain.polygon), nz_region
)
(min_x, min_y, max_x, max_y) = shapely.bounds(region)
return (min_x, max_x, min_y, max_y)


def generate_basemap(region: tuple[float, float, float, float]) -> pygmt.Figure:
fig: pygmt.Figure = plotting.gen_region_fig(
title=None,
region=region,
plot_kwargs=dict(
plot_kwargs=["af", "xaf+Longitude", "yaf+Latitude"],
water_color="white",
topo_cmap_min=-900,
topo_cmap_max=3100,
),
plot_highways=False,
config_options=dict(
MAP_FRAME_TYPE="plain",
FORMAT_GEO_MAP="ddd.xx",
MAP_FRAME_PEN="thinner,black",
),
)
assert isinstance(fig, pygmt.Figure)
return fig


@cli.from_docstring(app)
def main(
realisation_ffp: Annotated[Path, typer.Argument()],
dataset: Annotated[
Path,
typer.Argument(),
],
period: Annotated[
float,
typer.Argument(),
],
output: Annotated[
Path,
typer.Argument(),
],
cmap: Annotated[
str,
typer.Option(),
] = "polar",
reverse: Annotated[
bool,
typer.Option(is_flag=True),
] = False,
cmap_min: Annotated[
float | None,
typer.Option(),
] = None,
cmap_max: Annotated[
float | None,
typer.Option(),
] = None,
ticks: Annotated[
int,
typer.Option(),
] = 10,
) -> None:
"""Compare simulation results to predictions from the NSHM2022 logic tree.

Parameters
----------
realisation_ffp : Path
Path to realisation.
dataset : Path
Path to xarray intensity measure dataset.
period : float
pSA period to compare against.
output : Path
The path to write the figure out to.
cmap_min : float
Colourmap minimum
cmap_max : float
Colourmap maximum
ticks : int
Number of ticks in discrete colourmap.
output : Path
Output path.
cmap : str
Colourmap to plot log residuals. Should be divering.
reverse : bool
If true, reverse the colourmap. Defaults to false.
Comment on lines +149 to +160
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The docstring for the main function has several issues:

  • The output parameter is documented twice.
  • The cmap parameter is documented twice.
  • The cmap_min, cmap_max, ticks, and reverse parameters are missing from the docstring. Please ensure all parameters are documented once and accurately.
Suggested change
cmap_min : float
Colourmap minimum
cmap_max : float
Colourmap maximum
ticks : int
Number of ticks in discrete colourmap.
output : Path
Output path.
cmap : str
Colourmap to plot log residuals. Should be divering.
reverse : bool
If true, reverse the colourmap. Defaults to false.
output : Path
The path to write the figure out to.
cmap : str
Colourmap to plot log residuals. Should be diverging.
reverse : bool
If true, reverse the colourmap. Defaults to false.
cmap_min : float
Colourmap minimum
cmap_max : float
Colourmap maximum
ticks : int
Number of ticks in discrete colourmap.

"""

dset = xr.open_dataset(dataset, engine="h5netcdf")
domain = DomainParameters.read_from_realisation(realisation_ffp)
source_config = SourceConfig.read_from_realisation(realisation_ffp)
magnitudes = Magnitudes.read_from_realisation(realisation_ffp)
rakes = Rakes.read_from_realisation(realisation_ffp)
rupture_propagation_config = RupturePropagationConfig.read_from_realisation(
realisation_ffp
)

region = find_region(domain)

fig = generate_basemap(region)
gmm_psa_value = utils.get_gmm_prediction(
dset, period, source_config, magnitudes, rakes, rupture_propagation_config
)

plot_diff(
fig,
dset,
gmm_psa_value,
period,
cmap,
cmap_max,
cmap_min,
ticks,
reverse,
)
realisation.plot_domain(fig, domain, pen="1p,black,-")
realisation.plot_sources(fig, source_config)

fig.savefig(output)
Loading
Loading