From acb33a4c104a90092c879d92a44e61083351a0f2 Mon Sep 17 00:00:00 2001 From: Jake Faulkner Date: Tue, 29 Apr 2025 15:43:21 +1200 Subject: [PATCH 01/13] feat(plot-ts): plot SRF files as an animation --- visualisation/plot_ts.py | 271 +++++++++++++++++++++++++++++++++++---- 1 file changed, 248 insertions(+), 23 deletions(-) diff --git a/visualisation/plot_ts.py b/visualisation/plot_ts.py index daea48e..67e6d68 100644 --- a/visualisation/plot_ts.py +++ b/visualisation/plot_ts.py @@ -1,6 +1,7 @@ """Create simulation video of surface ground motion levels.""" import functools +import multiprocessing as mp import os import shutil import subprocess @@ -10,23 +11,24 @@ import cartopy.crs as ccrs import cartopy.feature as cfeature +import cartopy.io.img_tiles as cimgt import matplotlib -import shapely matplotlib.use("Agg") -import multiprocessing as mp - -import cartopy.io.img_tiles as cimgt import matplotlib.colors as mcolors import matplotlib.pyplot as plt import numpy as np +import scipy as sp +import shapely import tqdm import typer +from matplotlib.animation import FFMpegWriter, FuncAnimation from qcore import cli, coordinates from qcore.xyts import XYTSFile -from workflow.realisations import SourceConfig +from source_modelling import srf +from workflow.realisations import DomainParameters, SourceConfig app = typer.Typer() @@ -280,7 +282,7 @@ def zoom_extents( return new_x_min, new_x_max, new_y_min, new_y_max -def xyts_waveform_coordinates(xyts_file: XYTSFile) -> np.ndarray: +def waveform_coordinates(nztm_corners: np.ndarray, nx: int, ny: int) -> np.ndarray: """Compute gridpoint coordinates for XYTS waveform. Parameters @@ -295,12 +297,7 @@ def xyts_waveform_coordinates(xyts_file: XYTSFile) -> np.ndarray: A numpy array of shape (2 x ny x nx) containing the x and y coordinates of gridpoints in the NZTM coordinate system. """ - corners_geo = np.array(xyts_file.corners()) - nztm_corners = coordinates.wgs_depth_to_nztm(corners_geo[:, ::-1]) - - norm_xi, norm_eta = np.meshgrid( - np.linspace(0, 1, xyts_file.nx), np.linspace(0, 1, xyts_file.ny) - ) + norm_xi, norm_eta = np.meshgrid(np.linspace(0, 1, nx), np.linspace(0, 1, ny)) origin = nztm_corners[0] # Bottom-left corner (x0, y0) in NZTM vec_x = nztm_corners[1] - origin # Vector along xi axis (bottom edge) in NZTM vec_y = nztm_corners[3] - origin # Vector along eta axis (left edge) in NZTM @@ -388,9 +385,6 @@ def render_single_frame( plot_towns(ax, map_extent_nztm) else: request = cimgt.OSM(cache=True) - request._MAX_THREADS = ( - 1 # Limit to one thread because it is in a multiprocess pool. - ) ax.add_image( request, 10, @@ -460,15 +454,10 @@ def render_single_frame( ) cbar.set_label("Ground Motion (cm/s)") - # Save the frame to a file - frame_filename = f"frame_{frame_index:04d}.png" - plt.savefig(frame_filename, dpi=dpi) - plt.close(fig) - - return frame_filename + return [ax] -@cli.from_docstring(app) +@cli.from_docstring(app, name="xyts") def animate_low_frequency_mpl_nztm( realisation_ffp: Annotated[Path, typer.Argument(exists=True, dir_okay=False)], xyts_ffp: Annotated[Path, typer.Argument(exists=True, dir_okay=False)], @@ -562,7 +551,7 @@ def animate_low_frequency_mpl_nztm( ) frame_count = frame_count or xyts_file.nt - xr, yr = xyts_waveform_coordinates(xyts_file) + xr, yr = waveform_coordinates(nztm_corners, xyts_file.nx, xyts_file.ny) with tempfile.TemporaryDirectory() as temp_dir: render_frame = functools.partial( @@ -623,3 +612,239 @@ def animate_low_frequency_mpl_nztm( ] subprocess.run(ffmpeg_cmd, check=True) + + +def non_zero_data_points( + x: np.ndarray, y: np.ndarray, z: np.ndarray +) -> tuple[np.ndarray, np.ndarray, np.ndarray]: + """Get the non-zero data points in the 3D array. + + Parameters + ---------- + x : np.ndarray + The x coordinates of the data points. + y : np.ndarray + The y coordinates of the data points. + z : np.ndarray + The z coordinates of the data points. + + Returns + ------- + tuple[np.ndarray, np.ndarray, np.ndarray] + The non-zero data points in the 3D array. + """ + mask = z > 0 + return x[mask], y[mask], z[mask] + + +@cli.from_docstring(app, name="srf") +def animate_srf_slip_times( + realisation_ffp: Annotated[Path, typer.Argument(exists=True, dir_okay=False)], + srf_ffp: Annotated[Path, typer.Argument(exists=True, dir_okay=False)], + output_mp4: Annotated[ + Path, typer.Argument(writable=True, dir_okay=False, resolve_path=True) + ], + max_motion: Annotated[float, typer.Option()] = 10.0, + padding: Annotated[float, typer.Option()] = 5.0, + cmap: Annotated[str, typer.Option()] = "hot", + scale: Annotated[str, typer.Option()] = "10m", + shading: Annotated[str, typer.Option()] = "gouraud", + frame_count: Annotated[int | None, typer.Option()] = None, + width: Annotated[float, typer.Option()] = 30.0, + height: Annotated[float, typer.Option()] = 30.0, + dpi: Annotated[float, typer.Option()] = 150.0, + fps: Annotated[float, typer.Option()] = 15.0, + title: Annotated[str | None, typer.Option()] = None, + zoom: Annotated[float, typer.Option()] = 1, + simple_map: Annotated[bool, typer.Option()] = False, + map_quality: Annotated[int, typer.Option()] = 4, +) -> None: + """Render SRF slip times as a 2D video. + + Parameters + ---------- + realisation_ffp : Path + The input realisation file. + srf_ffp : Path + The input srf file containing the simulation data. + output_mp4 : Path + The output file path for the generated animation. + max_motion : float, optional + The maximum ground motion value for color scaling, by default 10.0. + padding : float, optional + The padding in km for the map extent, by default 5.0. + cmap : str, optional + The colormap to use for the animation, by default "hot". + scale : str, optional + The scale for cartopy features, by default "10m". + shading : str, optional + The shading method for `plt.pcolormesh`, by default "gouraud". + frame_count : int | None, optional + The number of frames to display in the animation, by default None (uses all frames). + width : float, optional + The width of the figure in cm, by default 30. + height : float, optional + The height of the figure in cm, by default 30. + dpi : float, optional + The DPI for the figure, by default 150.0. + fps : float, optional + The frames per second for the animation, by default 15.0. + title : str | None, optional + The title for the animation, by default None (no title). + zoom : float, optional + Zoom factor for the map, by default 1.0, on a log-scale. Zoom + centres on centre of source geometry. + simple_map : bool, optional + If True, disable OpenStreetMap background and use a simple map. + map_quality : int, optional + The quality of the map, by default 4. Has no effect if using a + simple map. Lower values have lower quality but render faster. + """ + ffmpeg = shutil.which("ffmpeg") + if not ffmpeg: + print( + "You must have ffmpeg installed. See https://ffmpeg.org/download.html.", + ) + raise typer.Exit(code=1) + + if dpi % 2: + dpi += 1 + + source_config = SourceConfig.read_from_realisation(realisation_ffp) + domain_config = DomainParameters.read_from_realisation(realisation_ffp) + srf_file = srf.read_srf(srf_ffp) + + nztm_corners = coordinates.wgs_depth_to_nztm(domain_config.domain.corners)[:, ::-1] + slip = srf_file.slipt1_array.tocsc() + map_extent_nztm = map_extents(nztm_corners, padding) + + if zoom != 1: + centre = shapely.centroid( + shapely.union_all( + [fault.geometry for fault in source_config.source_geometries.values()] + ) + ) + map_extent_nztm = zoom_extents( + map_extent_nztm, + (centre.y, centre.x), + zoom, + ) + + frame_count = frame_count or srf_file.nt + + # Create figure and initial setup + cm = 1 / 2.54 + fig = plt.figure(figsize=(width * cm, height * cm)) + ax = fig.add_subplot(1, 1, 1, projection=NZTM_CRS) + ax.set_extent(map_extent_nztm, crs=NZTM_CRS) + + # Add time text + + time_text = ax.text( + 0.98, + 0.02, + "Time: 0s", + transform=ax.transAxes, + fontsize=12, + color="black", + fontweight="bold", + ha="right", + va="bottom", + bbox={"boxstyle": "round", "facecolor": "white", "alpha": 0.8}, + ) + + if simple_map: + plot_cartographic_features(ax, scale) + plot_towns(ax, map_extent_nztm) + else: + request = cimgt.OSM(cache=True) + request._MAX_THREADS = ( + 1 # Limit to one thread because it is in a multiprocess pool. + ) + ax.add_image( + request, + 10, + interpolation="spline36", + regrid_shape=map_quality * 1000, + zorder=0, + ) + + ax.add_geometries( + [shapely.Polygon(nztm_corners)], + facecolor="none", + edgecolor="black", + linestyle="--", + zorder=1, + crs=NZTM_CRS, + ) + + ax.add_geometries( + [ + shapely.transform(fault.geometry, lambda coords: coords[:, ::-1]) + for fault in sorted( + source_config.source_geometries.values(), + key=lambda fault: -fault.centroid[-1], + ) + ], + facecolor="red", + edgecolor="black", + zorder=2, + crs=NZTM_CRS, + ) + + if title: + fig.suptitle(title, fontsize=16) + coords = coordinates.wgs_depth_to_nztm(srf_file.points[["lat", "lon"]].values)[ + :, ::-1 + ] + x, y = coords[:, 0], coords[:, 1] + init_x, init_y, init_z = non_zero_data_points(x, y, slip[:, 0].todense()) + scat = ax.scatter( + init_x, + init_y, + c=init_z, + cmap=cmap, + transform=NZTM_CRS, + zorder=100, + ) + + def initial_frame() -> None: + time_text.set_text("Time: 0s") + return [scat, time_text] + + # Setup the animation function + def render_single_frame( + frame_index: int, + ) -> list: + # Create a new figure for this frame + slip_index = frame_index * 20 + # Add all static elements + interval_slip_mean = slip[:, slip_index].todense() + slip_end = min(slip_index + 20, srf_file.nt) + for j in range(slip_index, slip_end): + interval_slip_mean += slip[:, j].todense() + interval_slip_mean /= slip_end - slip_index + # Add the actual data for this frame + cur_x, cur_y, z = non_zero_data_points( + x, + y, + interval_slip_mean, + ) + scat.set_offsets(np.c_[cur_x, cur_y]) + scat.set_array(z) + time_text.set_text(f"Time: {slip_index * srf_file.dt:.2f} s") + return [scat, time_text] + + # Create the animation + anim = FuncAnimation( + fig, + render_single_frame, + init_func=initial_frame, + frames=tqdm.trange(frame_count // 20, desc="Rendering frames", unit="frame"), + blit=True, + ) + + # Save the animation + writer = FFMpegWriter(fps=fps) + anim.save(output_mp4, writer=writer) + plt.close(fig) From 4e77a6973b1597a439cc539c92a06bb379397d05 Mon Sep 17 00:00:00 2001 From: Jake Faulkner Date: Tue, 29 Apr 2025 15:44:54 +1200 Subject: [PATCH 02/13] doc(plot-ts): suppress errors --- visualisation/plot_ts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/visualisation/plot_ts.py b/visualisation/plot_ts.py index 67e6d68..e0525a9 100644 --- a/visualisation/plot_ts.py +++ b/visualisation/plot_ts.py @@ -808,14 +808,14 @@ def animate_srf_slip_times( zorder=100, ) - def initial_frame() -> None: + def initial_frame() -> None: # numpydoc ignore=GL08 time_text.set_text("Time: 0s") return [scat, time_text] # Setup the animation function def render_single_frame( frame_index: int, - ) -> list: + ) -> list: # numpydoc ignore=GL08 # Create a new figure for this frame slip_index = frame_index * 20 # Add all static elements From 700ab0e24c2a580d0cc89bea58615b17d7347a4a Mon Sep 17 00:00:00 2001 From: Jake Faulkner Date: Tue, 29 Apr 2025 15:45:03 +1200 Subject: [PATCH 03/13] fix(plot-ts): remove unused imports --- visualisation/plot_ts.py | 1 - 1 file changed, 1 deletion(-) diff --git a/visualisation/plot_ts.py b/visualisation/plot_ts.py index e0525a9..1aa82b4 100644 --- a/visualisation/plot_ts.py +++ b/visualisation/plot_ts.py @@ -19,7 +19,6 @@ import matplotlib.colors as mcolors import matplotlib.pyplot as plt import numpy as np -import scipy as sp import shapely import tqdm import typer From aff6f751eb457517818eaaa52e664070f116e1da Mon Sep 17 00:00:00 2001 From: Jake Faulkner Date: Tue, 29 Apr 2025 15:46:21 +1200 Subject: [PATCH 04/13] docs(plot-ts): fix `waveform_coordinates` grid --- visualisation/plot_ts.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/visualisation/plot_ts.py b/visualisation/plot_ts.py index 1aa82b4..caea917 100644 --- a/visualisation/plot_ts.py +++ b/visualisation/plot_ts.py @@ -286,9 +286,12 @@ def waveform_coordinates(nztm_corners: np.ndarray, nx: int, ny: int) -> np.ndarr Parameters ---------- - xyts_file : XYTSFile - The xyts file containing gridded data. - + nztm_corners : np.ndarray + The corners of the waveform grid. + nx : int + The number of x-points in the output grid. + ny : int + The number of x-points in the output grid. Returns ------- From 8646a90177c3fdd4b983896b80f52345f1e5eb1c Mon Sep 17 00:00:00 2001 From: Jake Faulkner Date: Tue, 29 Apr 2025 15:54:37 +1200 Subject: [PATCH 05/13] refactor(plot-ts): extract the frame_dt timestep as option --- visualisation/plot_ts.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/visualisation/plot_ts.py b/visualisation/plot_ts.py index caea917..0f85a15 100644 --- a/visualisation/plot_ts.py +++ b/visualisation/plot_ts.py @@ -660,6 +660,7 @@ def animate_srf_slip_times( zoom: Annotated[float, typer.Option()] = 1, simple_map: Annotated[bool, typer.Option()] = False, map_quality: Annotated[int, typer.Option()] = 4, + frame_dt: Annotated[int, typer.Option(min=0)] = 20, ) -> None: """Render SRF slip times as a 2D video. @@ -701,6 +702,8 @@ def animate_srf_slip_times( map_quality : int, optional The quality of the map, by default 4. Has no effect if using a simple map. Lower values have lower quality but render faster. + frame_dt : int, optional + The number of timeslices per dt-step, default is 20. """ ffmpeg = shutil.which("ffmpeg") if not ffmpeg: @@ -819,10 +822,10 @@ def render_single_frame( frame_index: int, ) -> list: # numpydoc ignore=GL08 # Create a new figure for this frame - slip_index = frame_index * 20 + slip_index = frame_index * frame_dt # Add all static elements interval_slip_mean = slip[:, slip_index].todense() - slip_end = min(slip_index + 20, srf_file.nt) + slip_end = min(slip_index + frame_dt, srf_file.nt) for j in range(slip_index, slip_end): interval_slip_mean += slip[:, j].todense() interval_slip_mean /= slip_end - slip_index @@ -842,7 +845,9 @@ def render_single_frame( fig, render_single_frame, init_func=initial_frame, - frames=tqdm.trange(frame_count // 20, desc="Rendering frames", unit="frame"), + frames=tqdm.trange( + frame_count // frame_dt, desc="Rendering frames", unit="frame" + ), blit=True, ) From b372955dd9e9a9fe19af6e9983e87c89e661db25 Mon Sep 17 00:00:00 2001 From: Jake Faulkner Date: Tue, 29 Apr 2025 15:55:25 +1200 Subject: [PATCH 06/13] docs(plot-ts): correct docstring for `waveform_coordinates` --- visualisation/plot_ts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/visualisation/plot_ts.py b/visualisation/plot_ts.py index 0f85a15..795fb2f 100644 --- a/visualisation/plot_ts.py +++ b/visualisation/plot_ts.py @@ -291,7 +291,7 @@ def waveform_coordinates(nztm_corners: np.ndarray, nx: int, ny: int) -> np.ndarr nx : int The number of x-points in the output grid. ny : int - The number of x-points in the output grid. + The number of y-points in the output grid. Returns ------- From d8c635c12139ace76b3db9661cbaff30e82e58ed Mon Sep 17 00:00:00 2001 From: Jake Faulkner Date: Wed, 30 Apr 2025 10:51:39 +1200 Subject: [PATCH 07/13] deps: require scipy at least 1.15.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index fdfb8cd..a70d53b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ qcore @ git+https://github.com/ucgmsim/qcore.git geopandas pandas shapely -scipy +scipy >= 1.15.0 pooch pytest pytest-cov From 29a9860644495cc8d994b7463d468f8ba1b90d32 Mon Sep 17 00:00:00 2001 From: Jake Faulkner Date: Wed, 30 Apr 2025 10:55:46 +1200 Subject: [PATCH 08/13] fix(plot-ts): restore original functionality for xyts --- visualisation/plot_ts.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/visualisation/plot_ts.py b/visualisation/plot_ts.py index 795fb2f..d99d7ba 100644 --- a/visualisation/plot_ts.py +++ b/visualisation/plot_ts.py @@ -387,6 +387,9 @@ def render_single_frame( plot_towns(ax, map_extent_nztm) else: request = cimgt.OSM(cache=True) + request._MAX_THREADS = ( + 1 # Limit to one thread because it is in a multiprocess pool. + ) ax.add_image( request, 10, @@ -456,7 +459,12 @@ def render_single_frame( ) cbar.set_label("Ground Motion (cm/s)") - return [ax] + # Save the frame to a file + frame_filename = f"frame_{frame_index:04d}.png" + plt.savefig(frame_filename, dpi=dpi) + plt.close(fig) + + return frame_filename @cli.from_docstring(app, name="xyts") From d277773c193389bad9827c9a15be71081cee40d5 Mon Sep 17 00:00:00 2001 From: Jake Faulkner Date: Wed, 30 Apr 2025 11:05:09 +1200 Subject: [PATCH 09/13] refactor(plot-ts): cleanup slip average calculations --- visualisation/plot_ts.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/visualisation/plot_ts.py b/visualisation/plot_ts.py index d99d7ba..e52e3ae 100644 --- a/visualisation/plot_ts.py +++ b/visualisation/plot_ts.py @@ -831,12 +831,8 @@ def render_single_frame( ) -> list: # numpydoc ignore=GL08 # Create a new figure for this frame slip_index = frame_index * frame_dt - # Add all static elements - interval_slip_mean = slip[:, slip_index].todense() slip_end = min(slip_index + frame_dt, srf_file.nt) - for j in range(slip_index, slip_end): - interval_slip_mean += slip[:, j].todense() - interval_slip_mean /= slip_end - slip_index + interval_slip_mean = slip[:, list(range(slip_index, slip_end))].mean(axis=1) # Add the actual data for this frame cur_x, cur_y, z = non_zero_data_points( x, From 80e8e9734b0a91b5f8e43bf74fccaa32d9d3be4b Mon Sep 17 00:00:00 2001 From: Jake Faulkner Date: Wed, 30 Apr 2025 11:19:56 +1200 Subject: [PATCH 10/13] feat(plot-ts): add colour bar for slip video --- visualisation/plot_ts.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/visualisation/plot_ts.py b/visualisation/plot_ts.py index e52e3ae..e20e388 100644 --- a/visualisation/plot_ts.py +++ b/visualisation/plot_ts.py @@ -654,11 +654,10 @@ def animate_srf_slip_times( output_mp4: Annotated[ Path, typer.Argument(writable=True, dir_okay=False, resolve_path=True) ], - max_motion: Annotated[float, typer.Option()] = 10.0, + max_slip: Annotated[float, typer.Option()] = 10.0, padding: Annotated[float, typer.Option()] = 5.0, cmap: Annotated[str, typer.Option()] = "hot", scale: Annotated[str, typer.Option()] = "10m", - shading: Annotated[str, typer.Option()] = "gouraud", frame_count: Annotated[int | None, typer.Option()] = None, width: Annotated[float, typer.Option()] = 30.0, height: Annotated[float, typer.Option()] = 30.0, @@ -680,16 +679,14 @@ def animate_srf_slip_times( The input srf file containing the simulation data. output_mp4 : Path The output file path for the generated animation. - max_motion : float, optional - The maximum ground motion value for color scaling, by default 10.0. + max_slip : float, optional + The slip (not ground motion) for color scaling, by default 10.0 cm. padding : float, optional The padding in km for the map extent, by default 5.0. cmap : str, optional The colormap to use for the animation, by default "hot". scale : str, optional The scale for cartopy features, by default "10m". - shading : str, optional - The shading method for `plt.pcolormesh`, by default "gouraud". frame_count : int | None, optional The number of frames to display in the animation, by default None (uses all frames). width : float, optional @@ -817,9 +814,20 @@ def animate_srf_slip_times( init_y, c=init_z, cmap=cmap, + vmin=0, + vmax=max_slip, transform=NZTM_CRS, zorder=100, ) + fig.colorbar( + scat, + ax=ax, + orientation="vertical", + pad=0.02, + aspect=30, + shrink=0.8, + label="Slip (cm)", + ) def initial_frame() -> None: # numpydoc ignore=GL08 time_text.set_text("Time: 0s") From 08bc22d539afe07aed69ea71a48d9ce9d7d312d1 Mon Sep 17 00:00:00 2001 From: Jake Faulkner Date: Wed, 30 Apr 2025 13:46:09 +1200 Subject: [PATCH 11/13] fix(plot-ts): types for fps and dpi --- visualisation/plot_ts.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/visualisation/plot_ts.py b/visualisation/plot_ts.py index e20e388..f1b6693 100644 --- a/visualisation/plot_ts.py +++ b/visualisation/plot_ts.py @@ -329,7 +329,7 @@ def render_single_frame( title: str | None, width: float, height: float, - dpi: float, + dpi: int, ) -> str: """Render a single frame of the animation. @@ -367,7 +367,7 @@ def render_single_frame( The width of the figure in cm. height : float The height of the figure in cm. - dpi : float + dpi : int The DPI for the figure. Returns @@ -482,8 +482,8 @@ def animate_low_frequency_mpl_nztm( frame_count: Annotated[int | None, typer.Option()] = None, width: Annotated[float, typer.Option()] = 30.0, height: Annotated[float, typer.Option()] = 30.0, - dpi: Annotated[float, typer.Option()] = 150.0, - fps: Annotated[float, typer.Option()] = 15.0, + dpi: Annotated[int, typer.Option()] = 150, + fps: Annotated[float, typer.Option()] = 15, title: Annotated[str | None, typer.Option()] = None, zoom: Annotated[float, typer.Option()] = 1, simple_map: Annotated[bool, typer.Option()] = False, @@ -515,10 +515,10 @@ def animate_low_frequency_mpl_nztm( The width of the figure in cm, by default 30. height : float, optional The height of the figure in cm, by default 30. - dpi : float, optional + dpi : int, optional The DPI for the figure, by default 150.0. - fps : float, optional - The frames per second for the animation, by default 15.0. + fps : int, optional + The frames per second for the animation, by default 15. title : str | None, optional The title for the animation, by default None (no title). zoom : float, optional @@ -537,9 +537,6 @@ def animate_low_frequency_mpl_nztm( ) raise typer.Exit(code=1) - if dpi % 2: - dpi += 1 - source_config = SourceConfig.read_from_realisation(realisation_ffp) xyts_file = XYTSFile(xyts_ffp) @@ -661,8 +658,8 @@ def animate_srf_slip_times( frame_count: Annotated[int | None, typer.Option()] = None, width: Annotated[float, typer.Option()] = 30.0, height: Annotated[float, typer.Option()] = 30.0, - dpi: Annotated[float, typer.Option()] = 150.0, - fps: Annotated[float, typer.Option()] = 15.0, + dpi: Annotated[int, typer.Option()] = 150.0, + fps: Annotated[int, typer.Option()] = 15, title: Annotated[str | None, typer.Option()] = None, zoom: Annotated[float, typer.Option()] = 1, simple_map: Annotated[bool, typer.Option()] = False, @@ -693,9 +690,9 @@ def animate_srf_slip_times( The width of the figure in cm, by default 30. height : float, optional The height of the figure in cm, by default 30. - dpi : float, optional + dpi : int, optional The DPI for the figure, by default 150.0. - fps : float, optional + fps : int, optional The frames per second for the animation, by default 15.0. title : str | None, optional The title for the animation, by default None (no title). From 0f77aa4c1812052b00fd61f1c030704ee77b13a9 Mon Sep 17 00:00:00 2001 From: Jake Faulkner Date: Thu, 1 May 2025 16:03:47 +1200 Subject: [PATCH 12/13] Update visualisation/plot_ts.py Co-authored-by: AndrewRidden-Harper <52001209+AndrewRidden-Harper@users.noreply.github.com> --- visualisation/plot_ts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/visualisation/plot_ts.py b/visualisation/plot_ts.py index f1b6693..447592a 100644 --- a/visualisation/plot_ts.py +++ b/visualisation/plot_ts.py @@ -483,7 +483,7 @@ def animate_low_frequency_mpl_nztm( width: Annotated[float, typer.Option()] = 30.0, height: Annotated[float, typer.Option()] = 30.0, dpi: Annotated[int, typer.Option()] = 150, - fps: Annotated[float, typer.Option()] = 15, + fps: Annotated[int, typer.Option()] = 15, title: Annotated[str | None, typer.Option()] = None, zoom: Annotated[float, typer.Option()] = 1, simple_map: Annotated[bool, typer.Option()] = False, From e8d0f1e8c7133d26cb66a895d650740cae7a0d11 Mon Sep 17 00:00:00 2001 From: Jake Faulkner Date: Mon, 5 May 2025 16:46:45 +1200 Subject: [PATCH 13/13] ci: bump