Coverage for pyguymer3/geo/_add_rivers.py: 2%
42 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_rivers(
5 ax,
6 /,
7 *,
8 debug = __debug__,
9 fov = None,
10 linestyle = "solid",
11 linewidth = 0.5,
12 onlyValid = False,
13 resolution = "10m",
14):
15 """Add rivers to a Cartopy axis.
17 Parameters
18 ----------
19 axis : cartopy.mpl.geoaxes.GeoAxesSubplot
20 the axis to add the rivers to
21 debug : bool, optional
22 print debug messages
23 fov : None or shapely.geometry.polygon.Polygon, optional
24 clip the plotted shapes to the provided field-of-view to work around
25 occaisional MatPlotLib or Cartopy plotting errors when shapes much
26 larger than the field-of-view are plotted
27 linestyle : str, optional
28 the style of the rivers
29 linewidth : float, optional
30 the width of the rivers
31 onlyValid : bool, optional
32 only add valid LinearRings and LineStrings (checks for validity can take
33 a while, if being being called often)
34 resolution : str, optional
35 the resolution of the rivers
37 Notes
38 -----
39 This function uses `CSS4 named colours
40 <https://matplotlib.org/stable/gallery/color/named_colors.html>`_ .
42 Copyright 2017 Thomas Guymer [1]_
44 References
45 ----------
46 .. [1] PyGuymer3, https://github.com/Guymer/PyGuymer3
47 """
49 # Import standard modules ...
50 import os
51 import urllib
53 # Import special modules ...
54 try:
55 import cartopy
56 cartopy.config.update(
57 {
58 "cache_dir" : os.path.expanduser("~/.local/share/cartopy_cache"),
59 }
60 )
61 except:
62 raise Exception("\"cartopy\" is not installed; run \"pip install --user Cartopy\"") from None
63 try:
64 import matplotlib
65 matplotlib.rcParams.update(
66 {
67 "backend" : "Agg", # NOTE: See https://matplotlib.org/stable/gallery/user_interfaces/canvasagg.html
68 "figure.dpi" : 300,
69 "figure.figsize" : (9.6, 7.2), # NOTE: See https://github.com/Guymer/misc/blob/main/README.md#matplotlib-figure-sizes
70 "font.size" : 8,
71 }
72 )
73 except:
74 raise Exception("\"matplotlib\" is not installed; run \"pip install --user matplotlib\"") from None
75 try:
76 import shapely
77 import shapely.geometry
78 except:
79 raise Exception("\"shapely\" is not installed; run \"pip install --user Shapely\"") from None
81 # Import sub-functions ...
82 from .extract_lines import extract_lines
84 # **************************************************************************
86 # Create suitable colour ...
87 edgecolor = matplotlib.colors.to_rgba(matplotlib.colors.CSS4_COLORS["lightblue"])
88 if debug:
89 print(f"INFO: \"rivers\" is ({edgecolor[0]:.6f},{edgecolor[1]:.6f},{edgecolor[2]:.6f},{edgecolor[3]:.6f}).")
91 # Define names ...
92 names = [
93 "rivers_australia",
94 "rivers_europe",
95 "rivers_lake_centerlines",
96 "rivers_north_america",
97 ]
99 # Loop over names ...
100 for name in names:
101 # Find file containing the shapes ...
102 try:
103 sfile = cartopy.io.shapereader.natural_earth(
104 resolution = resolution,
105 category = "physical",
106 name = name,
107 )
108 except urllib.error.HTTPError:
109 continue
110 if debug:
111 print(f"INFO: \"{name}\" is \"{sfile}\".")
113 # Loop over records ...
114 for record in cartopy.io.shapereader.Reader(sfile).records():
115 # Skip bad records ...
116 if not hasattr(record, "geometry"):
117 continue
119 # Create a list of LineStrings to plot (taking in to account if the
120 # user provided a field-of-view to clip them by) ...
121 lines = []
122 for line in extract_lines(
123 record.geometry,
124 onlyValid = onlyValid,
125 ):
126 if fov is None:
127 lines.append(line)
128 continue
129 if line.disjoint(fov):
130 continue
131 lines.append(line.intersection(fov))
133 # Plot geometry ...
134 ax.add_geometries(
135 lines,
136 cartopy.crs.PlateCarree(),
137 edgecolor = edgecolor,
138 facecolor = "none",
139 linestyle = linestyle,
140 linewidth = linewidth,
141 )