Coverage for pyguymer3/geo/_add_roads.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_roads(
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 roads to a Cartopy axis.
17 Parameters
18 ----------
19 axis : cartopy.mpl.geoaxes.GeoAxesSubplot
20 the axis to add the roads 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 roads
29 linewidth : float, optional
30 the width of the roads
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 roads
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["red"])
88 if debug:
89 print(f"INFO: \"roads\" is ({edgecolor[0]:.6f},{edgecolor[1]:.6f},{edgecolor[2]:.6f},{edgecolor[3]:.6f}).")
91 # Define names ...
92 names = [
93 "roads",
94 "roads_north_america",
95 ]
97 # Loop over names ...
98 for name in names:
99 # Find file containing the shapes ...
100 try:
101 sfile = cartopy.io.shapereader.natural_earth(
102 resolution = resolution,
103 category = "cultural",
104 name = name,
105 )
106 except urllib.error.HTTPError:
107 continue
108 if debug:
109 print(f"INFO: \"{name}\" is \"{sfile}\".")
111 # Loop over records ...
112 for record in cartopy.io.shapereader.Reader(sfile).records():
113 # Skip bad records ...
114 if not hasattr(record, "geometry"):
115 continue
117 # Create a list of LineStrings to plot (taking in to account if the
118 # user provided a field-of-view to clip them by) ...
119 lines = []
120 for line in extract_lines(
121 record.geometry,
122 onlyValid = onlyValid,
123 ):
124 if fov is None:
125 lines.append(line)
126 continue
127 if line.disjoint(fov):
128 continue
129 lines.append(line.intersection(fov))
131 # Plot geometry ...
132 ax.add_geometries(
133 lines,
134 cartopy.crs.PlateCarree(),
135 edgecolor = edgecolor,
136 facecolor = "none",
137 linestyle = linestyle,
138 linewidth = linewidth,
139 )