Cal Paterson
Cal Paterson

Reputation: 172

Matplotlib and cartopy contours coming out completely wrong

I'm trying to plot latency maps of the world (for the moment, from London).

I have a database with a series of latencies between GPS points. I'd like to plot these on a map of the world with contour lines at various levels of latency, eg 50ms, 100ms, 200ms+ etc.

Right now I'm working with some sample code from the cartopy project for drawing labelled contours.

#!/usr/bin/env python3

from collections import defaultdict

import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import numpy as np

from cartopy.examples.waves import sample_data


def main():
    # lat, long and then latency from london
    zs = [
        (55.30927, 25.07725, 123.822),
        (19.81889, 41.3275, 61.154),
        (-58.37723, -34.61315, 250.024),
        (16.37208, 48.20849, 26.987),
        (15.45, 47.06667, 49.47),
        (115.8614, -31.95224, 273.459),
        (138.59863, -34.92866, 257.056),
        (151.20732, -33.86785, 258.382),
        (144.96332, -37.814, 259.542),
        (149.12807, -35.28346, 291.766),
        (153.02809, -27.46794, 283.675),
        (49.89201, 40.37767, 89.569),
        (90.40744, 23.7104, 232.381),
        (5.56749, 50.63373, 11.093),
        (4.34878, 50.85045, 9.644),
        (3.22424, 51.20892, 10.713),
        (4.40026, 51.22047, 10.905),
        (27.91667, 43.21667, 47.367),
        (23.32415, 42.69751, 52.414),
        (-34.86306, -7.115, 208.491),
        (-46.63611, -23.5475, 180.227),
        (-47.92972, -15.77972, 227.893),
        (-113.46871, 53.55014, 138.725),
        (-73.58781, 45.50884, 84.456),
        (-75.69812, 45.41117, 83.592),
        (-106.66892, 52.13238, 108.197),
        (-79.4163, 43.70011, 90.885),
        (-123.11934, 49.24966, 130.308),
        (-97.14704, 49.8844, 159.187),
        (-63.57291, 44.6464, 74.226),
        (-71.21454, 46.81228, 85.994),
        (8.55, 47.36667, 22.503),
        (8.96004, 46.01008, 33.557),
        (6.63282, 46.516, 27.375),
        (7.44744, 46.94809, 18.838),
        (7.57327, 47.55839, 27.376),
        (-70.64827, -33.45694, 195.647),
        (114.0683, 22.54554, 233.257),
        (121.45806, 31.22222, 191.371),
        (120.16142, 30.29365, 237.881),
        (114.87944, 40.81, 206.936),
        (-75.56359, 6.25184, 150.812),
        (-74.08175, 4.60971, 153.555),
        (-84.11651, 10.00236, 140.832),
        (33.03794, 34.68406, 64.037),
        (14.42076, 50.08804, 27.247),
        (16.60796, 49.19522, 29.384),
        (11.07752, 49.45421, 17.739),
        (11.57549, 48.13743, 20.171),
        (9.99302, 53.55073, 43.907),
        (8.68417, 50.11552, 13.733),
        (6.77616, 51.22172, 12.371),
        (12.10466, 47.7044, 19.85),
        (12.56553, 55.67594, 16.867),
        (3.08746, 36.73225, 40.629),
        (-78.52495, -0.22985, 161.671),
        (24.75353, 59.43696, 34.33),
        (31.24967, 30.06263, 63.373),
        (-0.37739, 39.46975, 32.652),
        (-3.70256, 40.4165, 23.838),
        (2.15899, 41.38879, 29.685),
        (24.93545, 60.16952, 33.84),
        (7.74553, 48.58392, 13.785),
        (3.17456, 50.69421, 4.4),
        (2.3488, 48.85341, 8.154),
        (4.84671, 45.74846, 21.794),
        (-1.61396, 54.97328, 5.601),
        (-2.23743, 53.48095, 7.15),
        (0.51667, 51.26667, 1.404),
        (-1.12902, 50.79509, 3.552),
        (-3.19648, 55.95206, 10.398),
        (-1.51217, 52.40656, 6.462),
        (-2.07972, 51.90006, 4.167),
        (-3.18, 51.48, 6.116),
        (-2.59665, 51.45523, 4.497),
        (-5.92541, 54.59682, 10.33),
        (44.83368, 41.69411, 88.784),
        (-0.1969, 5.55602, 97.088),
        (23.72784, 37.98376, 56.074),
        (22.93086, 40.64361, 61.766),
        (-90.51327, 14.64072, 342.363),
        (114.17469, 22.27832, 219.061),
        (15.97798, 45.81444, 31.988),
        (19.04045, 47.49835, 28.312),
        (106.84513, -6.21462, 191.802),
        (-6.24889, 53.33306, 11.926),
        (-6.92611, 52.84083, 12.585),
        (35.21633, 31.76904, 63.795),
        (34.78057, 32.08088, 111.049),
        (-4.48333, 54.15, 14.732),
        (78.15538, 11.65376, 70.362),
        (73.85535, 18.51957, 274.087),
        (77.22445, 28.63576, 150.969),
        (80.27847, 13.08784, 144.037),
        (75.8333, 22.71792, 137.159),
        (78.45636, 17.38405, 187.213),
        (72.88261, 19.07283, 187.64),
        (77.59369, 12.97194, 131.413),
        (-21.89541, 64.13548, 38.428),
        (13.33561, 38.13205, 52.313),
        (12.33265, 45.43713, 38.471),
        (12.51133, 41.89193, 31.075),
        (9.18951, 45.46427, 30.8),
        (13.34109, 41.63976, 41.74),
        (11.88068, 43.46276, 34.63),
        (139.69171, 35.6895, 215.214),
        (135.50218, 34.69374, 233.671),
        (141.35, 43.06667, 242.554),
        (36.81667, -1.28333, 174.557),
        (104.91601, 11.56245, 208.175),
        (126.9784, 37.566, 266.233),
        (73.10211, 49.80187, 123.06),
        (35.50157, 33.89332, 64.207),
        (25.2798, 54.68916, 38.825),
        (23.31667, 55.93333, 42.406),
        (6.13, 49.61167, 15.731),
        (24.10589, 56.946, 38.292),
        (-5.00028, 34.03313, 77.605),
        (28.8575, 47.00556, 51.354),
        (14.5148, 35.89968, 48.426),
        (-103.39182, 20.66682, 132.319),
        (3.39467, 6.45407, 96.877),
        (4.29861, 52.07667, 8.78),
        (4.47917, 51.9225, 6.952),
        (6.56667, 53.21917, 8.917),
        (5.47778, 51.44083, 8.77),
        (5.71806, 52.525, 7.052),
        (4.88969, 52.37403, 6.88),
        (4.66111, 51.86583, 9.274),
        (10.74609, 59.91273, 28.073),
        (5.32415, 60.39299, 28.998),
        (174.77557, -41.28664, 282.141),
        (172.63333, -43.53333, 273.846),
        (174.76349, -36.84853, 279.023),
        (-79.51973, 8.9936, 150.216),
        (-77.02824, -12.04318, 163.241),
        (120.9822, 14.6042, 220.693),
        (120.33325, 16.04313, 245.787),
        (74.35071, 31.558, 150.221),
        (21.01178, 52.22977, 31.504),
        (18.64912, 54.35227, 38.029),
        (-66.10572, 18.46633, 106.983),
        (-9.13333, 38.71667, 50.867),
        (26.10626, 44.43225, 47.648),
        (21.90333, 43.32472, 48.541),
        (20.46513, 44.80401, 38.377),
        (30.31413, 59.93863, 36.871),
        (37.61556, 55.75222, 49.041),
        (49.12214, 55.78874, 58.591),
        (82.9346, 55.0415, 127.4),
        (131.87353, 43.10562, 147.576),
        (46.72185, 24.68773, 88.155),
        (18.06871, 59.32938, 26.838),
        (11.96679, 57.70716, 56.335),
        (103.85007, 1.28967, 251.641),
        (14.50513, 46.05108, 36.656),
        (17.10674, 48.14816, 27.031),
        (-55.16682, 5.86638, 166.626),
        (100.50144, 13.75398, 265.619),
        (10.16579, 36.81897, 52.035),
        (27.13838, 38.41273, 67.678),
        (32.85427, 39.91987, 60.337),
        (28.94966, 41.01384, 51.519),
        (29.06013, 40.19559, 72.622),
        (121.53185, 25.04776, 261.82),
        (39.26951, -6.82349, 150.264),
        (30.5238, 50.45466, 41.29),
        (36.25272, 49.98081, 58.363),
        (32.58219, 0.31628, 159.655),
        (-77.03637, 38.89511, 78.045),
        (-81.65565, 30.33218, 94.374),
        (-80.19366, 25.77427, 99.16),
        (-81.37924, 28.53834, 97.119),
        (-82.45843, 27.94752, 101.628),
        (-84.38798, 33.749, 87.471),
        (-81.09983, 32.08354, 119.433),
        (-86.15804, 39.76838, 91.394),
        (-90.07507, 29.95465, 116.938),
        (-76.61219, 39.29038, 77.512),
        (-94.57857, 39.09973, 98.802),
        (-90.19789, 38.62727, 90.391),
        (-90.18481, 32.29876, 105.299),
        (-82.55402, 35.60095, 87.855),
        (-80.84313, 35.22709, 92.297),
        (-78.63861, 35.7721, 83.355),
        (-84.51439, 39.12711, 96.657),
        (-82.99879, 39.96118, 85.065),
        (-97.51643, 35.46756, 108.011),
        (-75.16379, 39.95233, 70.659),
        (-83.92074, 35.96064, 111.042),
        (-90.04898, 35.14953, 106.578),
        (-97.74306, 30.26715, 117.634),
        (-96.80667, 32.78306, 113.133),
        (-95.36327, 29.76328, 105.161),
        (-98.49363, 29.42412, 117.229),
        (-93.60911, 41.60054, 101.56),
        (-87.65005, 41.85003, 89.144),
        (-88.30535, 41.88753, 26.006),
        (-86.25001, 41.68338, 89.071),
        (-71.05977, 42.35843, 75.733),
        (-83.04575, 42.33143, 92.257),
        (-84.55553, 42.73253, 97.811),
        (-93.26384, 44.97997, 97.597),
        (-96.66696, 40.8, 97.95),
        (-74.39904, 40.49927, 69.437),
        (-74.05653, 40.78955, 71.265),
        (-73.75623, 42.65258, 74.285),
        (-78.87837, 42.88645, 79.13),
        (-73.96625, 40.78343, 68.356),
        (-74.00597, 40.71427, 71.41),
        (-76.14742, 43.04812, 76.038),
        (-81.8418, 41.23811, 83.061),
        (-81.69541, 41.4995, 93.716),
        (-83.55521, 41.66394, 97.349),
        (-79.99589, 40.44062, 87.723),
        (-75.6649, 41.40916, 73.833),
        (-88.01983, 44.51916, 102.133),
        (-112.07404, 33.44838, 130.966),
        (-121.98857, 37.54827, 134.523),
        (-118.24368, 34.05223, 136.396),
        (-121.4944, 38.58157, 136.928),
        (-117.16472, 32.71571, 146.006),
        (-122.41942, 37.77493, 141.373),
        (-121.89496, 37.33939, 133.461),
        (-104.82136, 38.83388, 108.739),
        (-104.9847, 39.73915, 121.039),
        (-106.65114, 35.08449, 164.648),
        (-115.13722, 36.17497, 146.236),
        (-122.39168, 40.58654, 156.6),
        (-122.67621, 45.52345, 130.65),
        (-123.34174, 43.2165, 147.008),
        (-111.89105, 40.76078, 151.18),
        (-122.33207, 47.60621, 129.576),
        (-157.85833, 21.30694, 186.991),
        (-56.18816, -34.90328, 228.291),
        (-66.87919, 10.48801, 148.292),
        (106.62965, 10.82302, 305.353),
        (105.84117, 21.0245, 240.46),
        (21.16688, 42.67272, 48.995),
        (28.04363, -26.20227, 165.392),
        (18.42322, -33.92584, 143.62),
    ]

    z = np.array(zs, dtype="float")
    breakpoint()

    fig = plt.figure()

    # Setup a global EckertIII map with faint coastlines.
    ax = fig.add_subplot(1, 1, 1, projection=ccrs.EckertIII())
    ax.set_global()
    ax.coastlines("110m", alpha=0.1)

    # Add colourful filled contours.
    filled_c = ax.contourf(z, transform=ccrs.PlateCarree())

    # And black line contours.
    line_c = ax.contour(
        z, levels=filled_c.levels, colors=["black"], transform=ccrs.PlateCarree()
    )

    # Uncomment to make the line contours invisible.
    # plt.setp(line_c.collections, visible=False)

    # Add a colorbar for the filled contour.
    fig.colorbar(filled_c, orientation="horizontal")

    # Use the line contours to place contour labels.
    ax.clabel(
        line_c,  # Typically best results when labelling line contours.
        colors=["black"],
        manual=False,  # Automatic placement vs manual placement.
        inline=True,  # Cut the line where the label will be placed.
        fmt=" {:.0f} ".format,  # Labes as integers, with some extra space.
    )

    plt.show()


if __name__ == "__main__":
    main()

Instead of getting nice contours, I get this image:

bad map of contours

What's my problem?

Am I passing the wrong args to the matplotlib functions?

Is numpy somehow interpreting my floats wrong?

Upvotes: 0

Views: 864

Answers (1)

swatchai
swatchai

Reputation: 18772

You need to separate data into lat, long, and height. Then use tricontour type functions to generate the plot. Here is the relevant part of the modified code that handles the data and generate the plot.

# more code before this (see the question)
zs = np.array(zs)
# get `lat`, `long`, and `height` separately
lats, lons, zzz = zs[:,0], zs[:,1], zs[:,2]

fig = plt.figure()

# Setup a global EckertIII map with faint coastlines.
ax = fig.add_subplot(1, 1, 1, projection=ccrs.EckertIII())
ax.set_global()
ax.coastlines("110m", alpha=0.1)

# Add colourful filled contours.
filled_c = ax.tricontourf(lats, lons, zzz, transform=ccrs.PlateCarree())

# And black line contours.
line_c = ax.tricontour(
    lats, lons, zzz, levels=filled_c.levels, colors=["black"], transform=ccrs.PlateCarree()
)

# Uncomment to make the line contours invisible.
# plt.setp(line_c.collections, visible=False)

# Add a colorbar for the filled contour.
fig.colorbar(filled_c, orientation="horizontal")

# Use the line contours to place contour labels.
ax.clabel(
    line_c,  # Typically best results when labelling line contours.
    colors=["black"],
    manual=False,  # Automatic placement vs manual placement.
    inline=True,  # Cut the line where the label will be placed.
    fmt=" {:.0f} ".format,  # Labes as integers, with some extra space.
)

plt.show()

contourplot

Upvotes: 1

Related Questions