This tutorial introduces visualization options for vessel trajectories processed using AISdb, including AISdb's integrated web interface and alternative approaches with popular Python visualization packages. Practical examples were provided for each tool, illustrating how to process and visualize AISdb tracks effectively.
Internal visualization
AISdb provides an integrated data visualization feature through the aisdb.web_interface.visualize module, which allows users to generate interactive maps displaying vessel tracks. This built-in tool is designed for simplicity and ease of use, offering customizable visualizations directly from AIS data without requiring extensive setup.
Here is an example of using the web interface module to show queried data with colors. To display vessel tracks in a single color:
import aisdbfrom datetime import datetimefrom aisdb.database.dbconn import SQLiteDBConnfrom aisdb import DBConn, DBQuery, DomainFromPointsimport nest_asyncionest_asyncio.apply()dbpath='YOUR_DATABASE.db'# Define the path to your database# Set the start and end times for the querystart_time = datetime.strptime("2018-01-01 00:00:00", '%Y-%m-%d %H:%M:%S')end_time = datetime.strptime("2018-01-03 00:00:00", '%Y-%m-%d %H:%M:%S')# Define a circle with a 100km radius around the location pointdomain =DomainFromPoints(points=[(-63.6, 44.6)], radial_distances=[100000])defcolor_tracks(tracks):""" Set the color of each vessel track using a color name or RGB value. """for track in tracks: track['color']='yellow'yield trackwith aisdb.SQLiteDBConn(dbpath=dbpath)as dbconn: qry = aisdb.DBQuery( dbconn=dbconn, start=start_time, end=end_time, xmin=domain.boundary['xmin'], xmax=domain.boundary['xmax'], ymin=domain.boundary['ymin'], ymax=domain.boundary['ymax'], callback=aisdb.database.sqlfcn_callbacks.in_time_bbox_validmmsi, ) rowgen = qry.gen_qry() tracks = aisdb.track_gen.TrackGen(rowgen, decimate=False) colored_tracks =color_tracks(tracks)# Visualization aisdb.web_interface.visualize( colored_tracks, domain=domain, visualearth=True, open_browser=True, )
If you want to visualize vessel tracks in different colors based on MMSI, here's an example that demonstrates how to color-code tracks for easy identification:
import randomdefcolor_tracks2(tracks): colors ={}for track in tracks: mmsi = track.get('mmsi')if mmsi notin colors:# Assign a random color to this MMSI if not already assigned colors[mmsi]="#{:06x}".format(random.randint(0, 0xFFFFFF)) track['color']= colors[mmsi]# Set the color for the current trackyield trackwith aisdb.SQLiteDBConn(dbpath=dbpath)as dbconn: qry = aisdb.DBQuery( dbconn=dbconn, start=start_time, end=end_time, xmin=domain.boundary['xmin'], xmax=domain.boundary['xmax'], ymin=domain.boundary['ymin'], ymax=domain.boundary['ymax'], callback=aisdb.database.sqlfcn_callbacks.in_time_bbox_validmmsi, ) rowgen = qry.gen_qry() tracks = aisdb.track_gen.TrackGen(rowgen, decimate=False) colored_tracks =list(color_tracks2(tracks))# Visualization aisdb.web_interface.visualize( colored_tracks, domain=domain, visualearth=True, open_browser=True, )
Alternative visualization
Several alternative Python packages can be leveraged for users seeking more advanced or specialized visualization capabilities. For instance, Basemap and Cartopy are excellent for creating detailed 2D plots, while Plotly offering powerful interactive graphs. Additionally, Kepler.gl caters to users needing dynamic, large-scale visualizations or 3D mapping. These alternatives allow for a deeper exploration of AIS data, offering flexibility in how data is presented and analyzed beyond the default capabilities of AISdb.
Basemap + Matplotlib
from mpl_toolkits.basemap import Basemapimport matplotlib.pyplot as pltdefplot_tracks_with_basemap(tracks): plt.figure(figsize=(12, 8))# Define the geofence boundaries llcrnrlat =42.854329883666175# Latitude of the southwest corner urcrnrlat =47.13666808816243# Latitude of the northeast corner llcrnrlon =-68.73998377599209# Longitude of the southwest corner urcrnrlon =-56.92378296577808# Longitude of the northeast corner# Create the Basemap object with the geofence m =Basemap(projection='merc', llcrnrlat=llcrnrlat, urcrnrlat=urcrnrlat, llcrnrlon=llcrnrlon, urcrnrlon=urcrnrlon, resolution='i') m.drawcoastlines() m.drawcountries() m.drawmapboundary(fill_color='aqua') m.fillcontinents(color='lightgreen', lake_color='aqua')for track in tracks: lons, lats = track['lon'], track['lat'] x, y =m(lons, lats) m.plot(x, y, color=track['color'], linewidth=2) plt.show()with aisdb.SQLiteDBConn(dbpath=dbpath)as dbconn: qry = aisdb.DBQuery( dbconn=dbconn, start=start_time, end=end_time, xmin=domain.boundary['xmin'], xmax=domain.boundary['xmax'], ymin=domain.boundary['ymin'], ymax=domain.boundary['ymax'], callback=aisdb.database.sqlfcn_callbacks.in_time_bbox_validmmsi, ) rowgen = qry.gen_qry() tracks = aisdb.track_gen.TrackGen(rowgen, decimate=False) colored_tracks =list(color_tracks2(tracks))plot_tracks_with_basemap(colored_tracks)
import plotly.graph_objects as goimport plotly.express as pximport pandas as pddeftrack2dataframe(tracks): data = []# Iterate over each track in the vessels_generatorfor track in tracks:# Unpack static information mmsi = track['mmsi'] rot = track['rot'] maneuver = track['maneuver'] heading = track['heading']# Unpack dynamic information times = track['time'] lons = track['lon'] lats = track['lat'] cogs = track['cog'] sogs = track['sog'] utc_seconds = track['utc_second']# Iterate over the dynamic arrays and create a row for each time pointfor i inrange(len(times)): data.append({'mmsi': mmsi,'rot': rot,'maneuver': maneuver,'heading': heading,'time': times[i],'longitude': lons[i],'latitude': lats[i],'cog': cogs[i],'sog': sogs[i],'utc_second': utc_seconds[i], })# Convert the list of dictionaries to a pandas DataFrame df = pd.DataFrame(data)return dfdefplotly_visualize(data,visual_type='lines'):if (visual_type=='scatter'):# Create a scatter plot for the vessel data points using scatter_geo fig = px.scatter_geo( data, lat="latitude", lon="longitude", color="mmsi", # Color by vessel identifier hover_name="mmsi", hover_data={"time": True}, title="Vessel Data Points" )else:# Create a line plot for the vessel trajectory using scatter_geo fig = px.line_geo( data, lat="latitude", lon="longitude", color="mmsi", # Color by vessel identifier hover_name="mmsi", hover_data={"time": True}, )# Set the map style and projection fig.update_geos( projection_type="azimuthal equal area", # Change this to 'natural earth', 'azimuthal equal area', etc. showland=True, landcolor="rgb(243, 243, 243)", countrycolor="rgb(204, 204, 204)", lonaxis=dict(range=[-68.73998377599209, -56.92378296577808]), # Longitude range (geofence) lataxis=dict(range=[42.854329883666175, 47.13666808816243]) # Latitude range (geofence) )# Set the layout to focus on a specific area or zoom level fig.update_layout( geo=dict( projection_type="mercator", center={"lat": 44.5, "lon": -63.5}, ), width=900, # Increase the width of the plot height=700, # Increase the height of the plot ) fig.show()with aisdb.SQLiteDBConn(dbpath=dbpath)as dbconn: qry = aisdb.DBQuery( dbconn=dbconn, start=start_time, end=end_time, xmin=domain.boundary['xmin'], xmax=domain.boundary['xmax'], ymin=domain.boundary['ymin'], ymax=domain.boundary['ymax'], callback=aisdb.database.sqlfcn_callbacks.in_time_bbox_validmmsi, ) rowgen = qry.gen_qry() tracks = aisdb.track_gen.TrackGen(rowgen, decimate=False) df =track2dataframe(tracks)plotly_visualize(df, 'lines')