Skip to content

Instantly share code, notes, and snippets.

@Hugoch
Last active November 28, 2020 17:43
Show Gist options
  • Save Hugoch/0d6f1b24077eb6ed4d21 to your computer and use it in GitHub Desktop.
Save Hugoch/0d6f1b24077eb6ed4d21 to your computer and use it in GitHub Desktop.
Plot flight data with matplolib
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import numpy as np
import pandas as pd
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
from matplotlib.colors import Normalize, LinearSegmentedColormap, PowerNorm
def plot_map(in_filename, color_mode='screen',
out_filename='flights_map_mpl.png', absolute=False):
"""Plots the given CSV data files use matplotlib basemap and saves it to
a PNG file.
Args:
in_filename: Filename of the CSV containing the data points.
out_filename: Output image filename
color_mode: Use 'screen' if you intend to use the visualisation for
on screen display. Use 'print' to save the visualisation
with printer-friendly colors.
absolute: set to True if you want coloring to depend on your dataset
parameter value (ie for comparison).
When set to false, each coordinate pair gets a different
color.
"""
if color_mode == 'screen':
bg_color = (0.0, 0.0, 0, 1.0)
coast_color = (204/255.0, 0, 153/255.0, 0.7)
color_list = [(0.0, 0.0, 0.0, 0.0),
(204/255.0, 0, 153/255.0, 0.6),
(255/255.0, 204/255.0, 230/255.0, 1.0)]
else:
bg_color = (1.0, 1.0, 1.0, 1.0)
coast_color = (10.0/255.0, 10.0/255.0, 10/255.0, 0.8)
color_list = [(1.0, 1.0, 1.0, 0.0),
(255/255.0, 204/255.0, 230/255.0, 1.0),
(204/255.0, 0, 153/255.0, 0.6)
]
# define the expected CSV columns
CSV_COLS = ('dep_lat', 'dep_lon', 'arr_lat', 'arr_lon',
'nb_flights', 'CO2')
routes = pd.read_csv(in_filename, names=CSV_COLS, na_values=['\\N'],
sep=';', skiprows=1)
num_routes = len(routes.index)
# normalize the dataset for color scale
norm = PowerNorm(0.3, routes['nb_flights'].min(),
routes['nb_flights'].max())
# norm = Normalize(routes['nb_flights'].min(), routes['nb_flights'].max())
# create a linear color scale with enough colors
if absolute:
n = routes['nb_flights'].max()
else:
n = num_routes
cmap = LinearSegmentedColormap.from_list('cmap_flights', color_list,
N=n)
# create the map and draw country boundaries
plt.figure(figsize=(27, 20))
m = Basemap(projection='mill', lon_0=0)
m.drawcoastlines(color=coast_color, linewidth=1.0)
m.fillcontinents(color=bg_color, lake_color=bg_color)
m.drawmapboundary(fill_color=bg_color)
# plot each route with its color depending on the number of flights
for i, route in enumerate(routes.sort_values(by='nb_flights',
ascending=True).iterrows()):
route = route[1]
if absolute:
color = cmap(norm(int(route['nb_flights'])))
else:
color = cmap(i * 1.0 / num_routes)
line, = m.drawgreatcircle(route['dep_lon'], route['dep_lat'],
route['arr_lon'], route['arr_lat'],
linewidth=0.5, color=color)
# if the path wraps the image, basemap plots a nasty line connecting
# the points at the opposite border of the map.
# we thus detect path that are bigger than 30km and split them
# by adding a NaN
path = line.get_path()
cut_point, = np.where(np.abs(np.diff(path.vertices[:, 0])) > 30000e3)
if len(cut_point) > 0:
cut_point = cut_point[0]
vertices = np.concatenate([path.vertices[:cut_point, :],
[[np.nan, np.nan]],
path.vertices[cut_point+1:, :]])
path.codes = None # treat vertices as a serie of line segments
path.vertices = vertices
# save the map
plt.savefig(out_filename, format='png', bbox_inches='tight')
if __name__ == '__main__':
# use 'screen' color mode for on-screen display. Use 'print' if you intend
# to print the map
plot_map('data.csv', 'screen', absolute=False)
@amartferr
Copy link

Hi Hugo, first of all thank you for sharing! I am playing with it and I get an error in your line 75 saying "name 'absolute' is not defined", what could this be?

Thank you in advance!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment