python4oceanographers

Turning ripples into waves

Reading GPX files directly with fiona

In a previous post I said I would try to build a GPX loader for GeoPandas. If you try to load a GPX file right now this is what you get.

In [3]:
import geopandas as gpd

fname = './data/2014_08_05_farol.gpx'

gdf = gpd.read_file(fname)
gdf
Out[3]:

Ouch! Not even an error message... Instead of monkey patching GeoPandas we can just use fiona. Fiona can be defined as GDAL/OGR for Python humans.

In [4]:
import fiona

fiona.listlayers(fname)
Out[4]:
[u'waypoints', u'routes', u'tracks', u'route_points', u'track_points']

Let's get that track layer into fiona.

In [5]:
layer = fiona.open(fname, layer='tracks')

layer
Out[5]:
<open Collection './data/2014_08_05_farol.gpx:tracks', mode 'r' at 0x7f17e450e850>

The layer object has a lot of properties/methods. Some of the properties carries the underlying metadata. Here are some important ones:

In [6]:
layer.crs, layer.bounds
Out[6]:
({'init': u'epsg:4326'},
 (-38.53207166666667, -13.01158, -38.49701, -13.001495))

How many items we have in this object?

In [7]:
len(list(layer.items()))
Out[7]:
1

What are these items?

In [8]:
geom = layer[0]

type(geom)
Out[8]:
dict
In [9]:
geom.keys()
Out[9]:
['geometry', 'type', 'id', 'properties']
In [10]:
geom['type'], geom['id'], geom['properties']
Out[10]:
('Feature',
 '0',
 OrderedDict([(u'name', None), (u'cmt', None), (u'desc', None), (u'src', None), (u'link1_href', None), (u'link1_text', None), (u'link1_type', None), (u'link2_href', None), (u'link2_text', None), (u'link2_type', None), (u'number', None), (u'type', None)]))

OK. It is a dictionary with more data and other dictionaries in it. We are interested in the data stored into geometry['coordinates']. Instead of dumping a bunch of numbers in the screen lets create a Shapely object to inspect the geometry coordinates.

In [11]:
from shapely.geometry import shape

data = {'type': 'MultiLineString',
        'coordinates': geom['geometry']['coordinates']}

shp = shape(data)
shp
Out[11]:

Nice! A simple and quick way to extract tracks from GPX and export to Shapely. But this image makes no sense without a map ;-)

(Note that I created a new dictionary with a structure I know relates to a GeoJson before feeding it to Shapely.)

In [12]:
import matplotlib.pyplot as plt

import cartopy.crs as ccrs
from cartopy.io import shapereader
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER


def make_map(projection=ccrs.PlateCarree()):
    fig, ax = plt.subplots(figsize=(9, 13),
                           subplot_kw=dict(projection=projection))
    gl = ax.gridlines(draw_labels=True)
    gl.xlabels_top = gl.ylabels_right = False
    gl.xformatter = LONGITUDE_FORMATTER
    gl.yformatter = LATITUDE_FORMATTER
    return fig, ax
In [13]:
import cartopy.io.img_tiles as cimgt

request = cimgt.OSM()

extent = [-38.54, -38.48,
          -13.02, -12.98]

fig, ax = make_map(projection=request.crs)
ax.set_extent(extent)

img = ax.add_image(request, 14)
s = ax.add_geometries(shp, ccrs.PlateCarree(),
                      facecolor='none',
                      edgecolor='crimson',
                      linewidth=2)

Have fun exploring your GPX files!

In [14]:
HTML(html)
Out[14]:

This post was written as an IPython notebook. It is available for download or as a static html.

Creative Commons License
python4oceanographers by Filipe Fernandes is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
Based on a work at https://ocefpaf.github.io/.

Comments