YAC 3.21.0
Yet Another Coupler
Loading...
Searching...
No Matches
yac_plot_grids.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2#
3# Copyright (c) 2026 The YAC Authors
4#
5# SPDX-License-Identifier: BSD-3-Clause
6#
7# /// script
8# requires-python = ">=3.9"
9# dependencies = ["numpy", "matplotlib", "netCDF4", "cartopy"]
10# ///
11
12"""Plot YAC debug grid files on an interactive map."""
13
14import logging
15import argparse
16from itertools import cycle
17
18import numpy as np
19import matplotlib.pyplot as plt
20import netCDF4
21
22from _utils.plotting import (
23 setup_figure,
24 add_label_in_extent,
25 plot_grid_edges_in_ax,
26 load_grid,
27 add_keybinding_legend,
28)
29
30# Cycle through these colours when more than one grid is plotted.
31_GRID_COLORS = ["green", "blue", "red", "orange", "purple", "brown", "pink", "gray"]
32
33
34def find_grids_in_file(filename):
35 ds = netCDF4.Dataset(filename, mode="r")
36 yac_grid_names = [d[3:] for d in ds.dimensions
37 if d.startswith("nv_")]
38 if len(yac_grid_names) == 0:
39 logging.warning(f"No yac grids found in {filename!r}")
40 return yac_grid_names
41
42if __name__ == "__main__":
43 parser = argparse.ArgumentParser(
44 description="Plot YAC debug grid files on an interactive map"
45 )
46 parser.add_argument(
47 "-v",
48 "--verbose",
49 action="count",
50 default=0,
51 help="Increase verbosity (-v for INFO, -vv for DEBUG)",
52 )
53 parser.add_argument(
54 "--center",
55 "-c",
56 type=float,
57 nargs=2,
58 metavar=("LON", "LAT"),
59 default=(0, 0),
60 help="Center of the map projection (longitude, latitude in degrees)",
61 )
62 parser.add_argument(
63 "--radius",
64 "-r",
65 type=float,
66 default=2000,
67 help="Radius in km of the region to display (default: 2000). Set to 0 to auto-scale the view to fit all plotted grid data.",
68 )
69 parser.add_argument(
70 "--coast-res",
71 type=str,
72 default="50m",
73 nargs="?",
74 choices=("10m", "50m", "110m"),
75 help=(
76 "Coastline resolution (default: 50m). "
77 "Use --coast-res without value to disable."
78 ),
79 )
80 parser.add_argument(
81 "--projection",
82 type=str,
83 default="orthographic",
84 choices=("orthographic", "stereographic", "platecarree"),
85 help="Map projection type (default: orthographic)",
86 )
87 parser.add_argument(
88 "gridfile",
89 type=str,
90 help="Path to YAC debug grid file (NetCDF format)",
91 )
92 parser.add_argument(
93 "--only",
94 type=str,
95 nargs="*",
96 default=None,
97 help="Only plot grids with these names",
98 )
99 parser.add_argument(
100 "--corner",
101 action="store_true",
102 help="Load indices on corners",
103 )
104 parser.add_argument(
105 "--ranks",
106 type=int,
107 nargs="*",
108 default=None,
109 help="Plot only the part of the grid that was stored on the given MPI ranks")
110
111 args = parser.parse_args()
112
113 log_level = [logging.WARNING, logging.INFO, logging.DEBUG][min(args.verbose, 2)]
114 logging.basicConfig(format="%(levelname)s: %(message)s")
115 logging.getLogger("_utils").setLevel(level=log_level)
116 logger = logging.getLogger("plotting")
117 logger.setLevel(level=log_level)
118
119
120 logger.info("Starting YAC grid visualisation")
121 logger.debug(f"CLI arguments: {args}")
122
123 logger.info("Setting up figure and map projection")
124 fig, ax = setup_figure(
125 projection=args.projection,
126 center=args.center,
127 focus_points=None,
128 radius=args.radius,
129 coast_res=args.coast_res,
130 )
131
132 legend = []
133 for gridname, color, key in zip(args.only or find_grids_in_file(args.gridfile),
134 _GRID_COLORS, "ABCDEFGHIJKLMNO"):
135 logger.info(f"Plotting {gridname}")
136 (clo, cla), (lo, la), ids, mask = load_grid([args.gridfile], gridname, "CORNER" if args.corner else "CELL", args.ranks)
137 plot_grid_edges_in_ax(ax, clo[mask], cla[mask], plot_kwargs={"color": color})
138 plot_grid_edges_in_ax(ax, clo[~mask], cla[~mask], plot_kwargs={"color": color, "alpha": 0.3, "linestyle": "dashed"})
139
140 if args.corner:
141 ids, select = np.unique(ids.ravel(), return_index=True)
142 lo = lo.ravel()[select]
143 la = la.ravel()[select]
144
145 add_label_in_extent(
146 ax,
147 lo,
148 la,
149 ids,
150 {"color": "black", "visible": False},
151 key,
152 )
153 legend.append((key, f"toggle {gridname} labels", color))
154
155 add_keybinding_legend(ax, legend)
156 if args.radius==0:
157 ax.autoscale(True)
158
159 logger.info("Opening interactive plot window")
160 plt.show()
find_grids_in_file(filename)