Coverage for pyguymer3/geo/_add_bathymetry.py: 2%
43 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-08 18:47 +0000
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-08 18:47 +0000
1#!/usr/bin/env python3
3# Define function ...
4def _add_bathymetry(
5 ax,
6 /,
7 *,
8 debug = __debug__,
9 fov = None,
10 onlyValid = False,
11 repair = False,
12 resolution = "10m",
13):
14 """Add bathymetry to a Cartopy axis.
16 Parameters
17 ----------
18 axis : cartopy.mpl.geoaxes.GeoAxesSubplot
19 the axis to add the bathymetry to
20 debug : bool, optional
21 print debug messages
22 fov : None or shapely.geometry.polygon.Polygon, optional
23 clip the plotted shapes to the provided field-of-view to work around
24 occaisional MatPlotLib or Cartopy plotting errors when shapes much
25 larger than the field-of-view are plotted
26 onlyValid : bool, optional
27 only add valid Polygons (checks for validity can take a while, if being
28 being called often)
29 repair : bool, optional
30 attempt to repair invalid Polygons
31 resolution : str, optional
32 the resolution of the bathymetry
34 Notes
35 -----
36 This function uses `CSS4 named colours
37 <https://matplotlib.org/stable/gallery/color/named_colors.html>`_ .
39 Copyright 2017 Thomas Guymer [1]_
41 References
42 ----------
43 .. [1] PyGuymer3, https://github.com/Guymer/PyGuymer3
44 """
46 # Import standard modules ...
47 import os
48 import urllib
50 # Import special modules ...
51 try:
52 import cartopy
53 cartopy.config.update(
54 {
55 "cache_dir" : os.path.expanduser("~/.local/share/cartopy_cache"),
56 }
57 )
58 except:
59 raise Exception("\"cartopy\" is not installed; run \"pip install --user Cartopy\"") from None
60 try:
61 import matplotlib
62 matplotlib.rcParams.update(
63 {
64 "backend" : "Agg", # NOTE: See https://matplotlib.org/stable/gallery/user_interfaces/canvasagg.html
65 "figure.dpi" : 300,
66 "figure.figsize" : (9.6, 7.2), # NOTE: See https://github.com/Guymer/misc/blob/main/README.md#matplotlib-figure-sizes
67 "font.size" : 8,
68 }
69 )
70 except:
71 raise Exception("\"matplotlib\" is not installed; run \"pip install --user matplotlib\"") from None
72 try:
73 import shapely
74 import shapely.geometry
75 except:
76 raise Exception("\"shapely\" is not installed; run \"pip install --user Shapely\"") from None
78 # Import sub-functions ...
79 from .extract_polys import extract_polys
81 # **************************************************************************
83 # Create suitable colour map ...
84 cmap = matplotlib.colors.LinearSegmentedColormap.from_list(
85 "bathymetry",
86 [
87 matplotlib.colors.to_rgba(matplotlib.colors.CSS4_COLORS["lightblue"]),
88 matplotlib.colors.to_rgba(matplotlib.colors.CSS4_COLORS["darkblue"]),
89 ]
90 )
92 # Define depths ...
93 depths = [
94 ( 0, "bathymetry_L_0" ),
95 ( 200, "bathymetry_K_200" ),
96 ( 1000, "bathymetry_J_1000" ),
97 ( 2000, "bathymetry_I_2000" ),
98 ( 3000, "bathymetry_H_3000" ),
99 ( 4000, "bathymetry_G_4000" ),
100 ( 5000, "bathymetry_F_5000" ),
101 ( 6000, "bathymetry_E_6000" ),
102 ( 7000, "bathymetry_D_7000" ),
103 ( 8000, "bathymetry_C_8000" ),
104 ( 9000, "bathymetry_B_9000" ),
105 (10000, "bathymetry_A_10000"),
106 ]
108 # Loop over depths ...
109 for depth, name in depths:
110 # Create suitable colour ...
111 facecolor = cmap(float(depth) / 10000.0)
112 if debug:
113 print(f"INFO: \"{name}\" is ({facecolor[0]:.6f},{facecolor[1]:.6f},{facecolor[2]:.6f},{facecolor[3]:.6f}).")
115 # Find file containing the shapes ...
116 try:
117 sfile = cartopy.io.shapereader.natural_earth(
118 resolution = resolution,
119 category = "physical",
120 name = name,
121 )
122 except urllib.error.HTTPError:
123 continue
124 if debug:
125 print(f"INFO: \"{name}\" is \"{sfile}\".")
127 # Loop over records ...
128 for record in cartopy.io.shapereader.Reader(sfile).records():
129 # Skip bad records ...
130 if not hasattr(record, "geometry"):
131 continue
133 # Create a list of Polygons to plot (taking in to account if the
134 # user provided a field-of-view to clip them by) ...
135 polys = []
136 for poly in extract_polys(
137 record.geometry,
138 onlyValid = onlyValid,
139 repair = repair,
140 ):
141 if fov is None:
142 polys.append(poly)
143 continue
144 if poly.disjoint(fov):
145 continue
146 polys.append(poly.intersection(fov))
148 # Plot geometry ...
149 ax.add_geometries(
150 polys,
151 cartopy.crs.PlateCarree(),
152 edgecolor = "none",
153 facecolor = facecolor,
154 )