Reputation: 172
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:
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
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()
Upvotes: 1