How To Avoid Places Completely

metadata

This is just a quick blog post to follow on from one a couple of years ago where I showed (namely the UK and the US). I have now updated the script to include all of the overseas territories of both the UK and the US, to create a more complete calculation.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215

#!/usr/bin/env python3

# Use the proper idiom in the main module ...
# NOTE: See https://docs.python.org/3.12/library/multiprocessing.html#the-spawn-and-forkserver-start-methods
if __name__ == "__main__":
    # Import standard modules ...
    import os

    # Import special modules ...
    try:
        import cartopy
        cartopy.config.update(
            {
                "cache_dir" : os.path.expanduser("~/.local/share/cartopy_cache"),
            }
        )
    except:
        raise Exception("\"cartopy\" is not installed; run \"pip install --user Cartopy\"") from None
    try:
        import matplotlib
        matplotlib.rcParams.update(
            {
                       "backend" : "Agg",                                       # NOTE: See https://matplotlib.org/stable/gallery/user_interfaces/canvasagg.html
                    "figure.dpi" : 300,
                "figure.figsize" : (9.6, 7.2),                                  # NOTE: See https://github.com/Guymer/misc/blob/main/README.md#matplotlib-figure-sizes
                     "font.size" : 8,
            }
        )
        import matplotlib.pyplot
    except:
        raise Exception("\"matplotlib\" is not installed; run \"pip install --user matplotlib\"") from None
    try:
        import shapely
        import shapely.geometry
        import shapely.ops
    except:
        raise Exception("\"shapely\" is not installed; run \"pip install --user Shapely\"") from None

    # Import my modules ...
    try:
        import pyguymer3
        import pyguymer3.geo
        import pyguymer3.image
    except:
        raise Exception("\"pyguymer3\" is not installed; you need to have the Python module from https://github.com/Guymer/PyGuymer3 located somewhere in your $PYTHONPATH") from None

    # **************************************************************************

    # List countries to find the antipodes of ...
    # NOTE: Ignore Antarctica.
    avoids = [
        "United Kingdom",
            "Akrotiri",
            "Anguilla",
            "Bermuda",
            "Br. Indian Ocean Ter.",
            "British Virgin Is.",
            "Cayman Is.",
            "Dhekelia",
            "Falkland Is.",
            "Gibraltar",
            "Montserrat",
            "Pitcairn Is.",
            "S. Geo. and the Is.",
            "Saint Helena",
            "Turks and Caicos Is.",
        "United States of America",
            "American Samoa",
            "Guam",
            "Marshall Is.",
            "Micronesia",
            "N. Mariana Is.",
            "Palau",
            "Puerto Rico",
            "U.S. Minor Outlying Is.",
            "U.S. Virgin Is.",
            "USNB Guantanamo Bay",

    ]

    # Create colours and define number of angles and resolution ...
    colours = ["red", "green", "blue", "cyan", "magenta", "yellow", "red"]
    fill = 0.1                                                                  # [°]
    nang = 361                                                                  # [#]
    res = "10m"
    simp = 0.01                                                                 # [°]
    tol = 1.0e-10                                                               # [°]

    # Find file containing all the country shapes ...
    sfile = cartopy.io.shapereader.natural_earth(
          category = "cultural",
              name = "admin_0_countries",
        resolution = res,
    )

    # **************************************************************************
    # *               CREATE MULTIPOLYGON TO FIND THE BUFFER OF                *
    # **************************************************************************

    # Create empty list ...
    geoms = []

    # Loop over records ...
    for record in cartopy.io.shapereader.Reader(sfile).records():
        # Create short-hand ...
        neName = pyguymer3.geo.getRecordAttribute(record, "NAME")

        # Check if this record is to be avoided ...
        skip = True
        if neName in avoids:
            skip = False

        # Skip this record if it is not a country to be avoided ...
        if skip:
            continue

        # Add Polygons to the list ...
        geoms += pyguymer3.geo.extract_polys(record.geometry)

    # Convert list of Polygons to (unified) [Multi]Polygon ...
    geoms = shapely.ops.unary_union(geoms).simplify(tol)
    pyguymer3.geo.check(geoms)

    # **************************************************************************

    # Create figure ...
    fg = matplotlib.pyplot.figure(figsize = (12.8, 7.2))

    # Create axis ...
    ax = pyguymer3.geo.add_axis(fg)

    # Configure axis ...
    pyguymer3.geo.add_map_background(ax, resolution = "large8192px")

    # Add country outlines ...
    for record in cartopy.io.shapereader.Reader(sfile).records():
        ax.add_geometries(
            pyguymer3.geo.extract_polys(record.geometry),
            cartopy.crs.PlateCarree(),
            edgecolor = "black",
            facecolor = "none",
            linewidth = 0.5,
        )

    # Initialize distance, labels and lines ...
    dist2 = 0.0                                                                 # [km]
    labels = []
    lines = []

    # Loop over distances ...
    for i in range(7):
        # Set distance ...
        if i >= 6:
            dist1 = 0.5e6                                                       # [m]
        else:
            dist1 = 1.0e6                                                       # [m]
        dist2 += 0.001 * dist1                                                  # [km]

        # Find out how complicated the [Multi]Polygon is ...
        npoints = 0                                                             # [#]
        npolys = 0                                                              # [#]
        for poly in pyguymer3.geo.extract_polys(geoms):
            npoints += len(poly.exterior.coords)                                # [#]
            npolys += 1                                                         # [#]
            for interior in poly.interiors:
                npoints += len(interior.coords)                                 # [#]

        print(f"Calculating for {dist2:6,.0f} km (using {npoints:,d} points in {npolys:,d} Polygons) ...")

        # Buffer area ...
        # NOTE: geoms is the [Multi]Polygon to be buffered.
        geoms = pyguymer3.geo.buffer(
            geoms,
            dist1,
            debug = False,
             fill = fill,
             nang = nang,
             simp = simp,
              tol = tol,
        )
        # NOTE: geoms is now the simplified [Multi]Polygon buffer of geoms.

        # Add to plot ...
        ax.add_geometries(
            pyguymer3.geo.extract_polys(geoms),
            cartopy.crs.PlateCarree(),
            edgecolor = colours[i],
            facecolor = "none",
            linewidth = 1.0,
        )
        labels.append(f"{dist2:6,.0f} km")
        lines.append(matplotlib.lines.Line2D([], [], color = colours[i]))

    print("Plotting ...")

    # Configure axis ...
    ax.legend(
        lines,
        labels,
         loc = "upper center",
        ncol = 4,
    )

    # Configure figure ...
    fg.tight_layout()

    # Save figure ...
    fg.savefig("find_antipode_v3.png")
    matplotlib.pyplot.close(fg)

    # Optimize PNG ...
    pyguymer3.image.optimize_image(
        "find_antipode_v3.png",
        strip = True,
    )

              
You may also download “find_antipode_v3.py” directly or view “find_antipode_v3.py” on GitHub Gist (you may need to manually checkout the “main” branch).

The image produced by this script is shown below.

Download:
  1. 512 px × 288 px (0.1 Mpx; 234.9 KiB)
  2. 1,024 px × 576 px (0.6 Mpx; 879.5 KiB)
  3. 2,048 px × 1,152 px (2.4 Mpx; 3.0 MiB)
  4. 3,840 px × 2,160 px (8.3 Mpx; 7.2 MiB)

You can’t quite get 7,000 km away from both the UK and the US. There are only two regions in the world where you can get more than 5,000 km away: north west China and the seas south of Australia.