A hands-on quick start guide for using AISdb.
python -m venv AISdb # create a python virtual environment
source ./AISdb/bin/activate # activate the virtual environment
pip install aisdb # from https://pypi.org/project/aisdb/python -m venv AISdb
./AISdb/Scripts/activate
pip install aisdbpython
>>> import aisdb
>>> aisdb.__version__ # should return '1.7.3' or newersource ./AISdb/bin/activate
pip install jupyter
jupyter notebooksource AISdb/bin/activate # On Windows use `AISdb\Scripts\activate`
# Cloning the Repository and installing the package
git clone https://github.com/AISViz/AISdb.git && cd aisdb
# Windows users can instead download the installer:
# - https://forge.rust-lang.org/infra/other-installation-methods.html#rustup
# - https://static.rust-lang.org/rustup/dist/i686-pc-windows-gnu/rustup-init.exe
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > install-rust.sh
# Installing Rust and Maturin
/bin/bash install-rust.sh -q -y
pip install --upgrade maturin[patchelf]
# Building AISdb package with Maturin
maturin develop --release --extras=test,docsimport os
# Clone the AISdb repository from GitHub
!git clone https://github.com/AISViz/AISdb.git
# Install Rust using the official Rustup script
!curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
# Install Maturin to build the packages
!pip install --upgrade maturin[patchelf]
# Set up environment variables
os.environ["PATH"] += os.pathsep + "/root/.cargo/bin"
# Install wasm-pack for building WebAssembly packages
!curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
# Install wasm-pack as a Cargo dependency
!cargo install wasm-pack
# Setting environment variable for the virtual environment
os.environ["VIRTUAL_ENV"] = "/usr/local"
# Change directory to AISdb for building the package
%cd AISdb
# Build and install the AISdb package using Maturin
!maturin develop --release --extras=test,docs$ sudo apt install -y timescaledb-postgresql-XX # XX is the PG-SQL version> CREATE EXTENSION IF NOT EXISTS timescaledb;> SELECT * FROM timescaledb_information.version;$ sudo systemctl restart postgresqlfrom aisdb.database.dbconn import PostgresDBConn
# [OPTION 1]
dbconn = PostgresDBConn(
hostaddr='127.0.0.1', # Replace this with the Postgres address (supports IPv6)
port=5432, # Replace this with the Postgres running port (if not the default)
user='USERNAME', # Replace this with the Postgres username
password='PASSWORD', # Replace this with your password
dbname='DATABASE', # Replace this with your database name
)
# [OPTION 2]
dbconn = PostgresDBConn('postgresql://USERNAME:PASSWORD@HOST:PORT/DATABASE')from aisdb.database.dbconn import SQLiteDBConn
dbpath='example_data.db'
dbconn = SQLiteDBConn(dbpath=dbpath)import aisdb
import pandas as pd
from datetime import datetime
from collections import defaultdict
dbpath = 'example_data.db'
start_time = datetime.strptime("2022-01-01 00:00:00", '%Y-%m-%d %H:%M:%S')
end_time = datetime.strptime("2022-01-01 0:59:59", '%Y-%m-%d %H:%M:%S')
def data2frame(tracks):
# Dictionary where for key/value
ais_data = defaultdict(lambda: pd.DataFrame(
columns = ['time', 'lat', 'lon', 'cog', 'rocog', 'sog', 'delta_sog']))
for track in tracks:
mmsi = track['mmsi']
df = pd.DataFrame({
'time': pd.to_datetime(track['time'], unit='s'),
'lat': track['lat'], 'lon': track['lon'],
'cog': track['cog'], 'sog': track['sog']
})
# Sort by time in descending order
df = df.sort_values(by='time', ascending=False).reset_index(drop=True)
# Compute the time difference in seconds
df['time_diff'] = df['time'].diff().dt.total_seconds()
# Compute RoCOG (Rate of Change of Course Over Ground)
delta_cog = (df['cog'].diff() + 180) % 360 - 180
df['rocog'] = delta_cog / df['time_diff']
# Compute Delta SOG (Rate of Change of Speed Over Ground)
df['delta_sog'] = df['sog'].diff() / df['time_diff']
# Fill NaN values (first row) and infinite values (division by zero cases)
df[['rocog', 'delta_sog']] = df[['rocog', 'delta_sog']].replace([float('inf'), float('-inf')], 0).fillna(0)
# Drop unnecessary column
df.drop(columns = ['time_diff'], inplace=True)
# Store in the dictionary
ais_data[mmsi] = df
return ais_data
with aisdb.SQLiteDBConn(dbpath=dbpath) as dbconn:
qry = aisdb.DBQuery(
dbconn=dbconn, start=start_time, end=end_time,
callback=aisdb.database.sqlfcn_callbacks.in_timerange_validmmsi,
)
rowgen = qry.gen_qry()
tracks = aisdb.track_gen.TrackGen(rowgen, decimate=False)
ais_data = data2frame(tracks) # re-use previous function
# Display DataFrames
for key in ais_data.keys():
print(ais_data[key])# a circle with a 100km radius around the location point
domain = aisdb.DomainFromPoints(points=[(-69.34, 41.55)], radial_distances=[100000])
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_validmmsi_bbox,
)
rowgen = qry.gen_qry()
tracks = aisdb.track_gen.TrackGen(rowgen, decimate=False)
ais_data = data2frame(tracks) # re-use previous function
# Display DataFrames
for key in ais_data.keys():
print(ais_data[key])from datetime import timedelta
# Define a maximum time interval
maxdelta = timedelta(hours=24)
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_validmmsi_bbox,
)
rowgen = qry.gen_qry()
tracks = aisdb.track_gen.TrackGen(rowgen, decimate=False)
# Split the generated tracks into segments
track_segments = aisdb.split_timedelta(tracks, maxdelta)
ais_data = data2frame(track_segments) # re-use previous function
# Display DataFrames
for key in ais_data.keys():
print(ais_data[key])distance_threshold = 20000 # the maximum allowed distance (meters) between consecutive AIS messages
speed_threshold = 50 # the maximum allowed vessel speed in consecutive AIS messages
minscore = 1e-6 # the minimum score threshold for track segment validation
with aisdb.SQLiteDBConn(dbpath=dbpath) as dbconn:
qry = aisdb.DBQuery(
dbconn=dbconn, start=start_time, end=end_time,
callback=aisdb.database.sqlfcn_callbacks.in_timerange,
)
rowgen = qry.gen_qry()
tracks = aisdb.track_gen.TrackGen(rowgen, decimate=False)
# Encode the track segments to clean and validate the track data
tracks_encoded = aisdb.encode_greatcircledistance(tracks,
distance_threshold=distance_threshold,
speed_threshold=speed_threshold,
minscore=minscore)
ais_data = data2frame(tracks_encoded) # re-use previous function
# Display DataFrames
for key in ais_data.keys():
print(ais_data[key])# Define a domain with a central point and corresponding radial distances
domain = aisdb.DomainFromPoints(points=[(-69.34, 41.55),], radial_distances=[100000,])
# Filter the encoded tracks to include only those within the specified domain
tracks_filtered = aisdb.track_gen.zone_mask(tracks_encoded, domain)
# Interpolate the filtered tracks with a specified time interval
tracks_interp = aisdb.interp_time(tracks_filtered, step=timedelta(minutes=15))aisdb.write_csv(tracks_interp, 'ais_processed.csv')import aisdb
# Set the data storage directory
data_dir = './testdata/'
# Download bathymetry grid from the internet
bathy = aisdb.webdata.bathymetry.Gebco(data_dir=data_dir)
bathy.fetch_bathymetry_grid()tracks = aisdb.TrackGen(qry.gen_qry(), decimate=False)
tracks_bathymetry = bathy.merge_tracks(tracks) # merge tracks with bathymetry datatracks = aisdb.TrackGen(qry.gen_qry())
raster_path './GMT_intermediate_coast_distance_01d.tif'
# Load the raster file
raster = aisdb.webdata.load_raster.RasterFile(raster_path)
# Merge the generated tracks with the raster data
tracks = raster.merge_tracks(tracks, new_track_key="coast_distance")from datetime import datetime, timedelta
import aisdb
from aisdb import DomainFromPoints
dbpath='example_data.db'
def color_tracks(tracks):
''' set the color of each vessel track using a color name or RGB value '''
for track in tracks:
track['color'] = 'blue' or 'rgb(0,0,255)'
yield track
# Set the start and end times for the query
start_time = datetime.strptime("2022-01-01 00:00:00", '%Y-%m-%d %H:%M:%S')
end_time = datetime.strptime("2022-01-31 00:00:00", '%Y-%m-%d %H:%M:%S')
with aisdb.SQLiteDBConn(dbpath=dbpath) as dbconn:
qry = aisdb.DBQuery(
dbconn=dbconn,
start=start_time,
end=end_time,
callback=aisdb.database.sqlfcn_callbacks.in_timerange_validmmsi,
)
rowgen = qry.gen_qry()
# Convert queried rows to vessel trajectories
tracks = aisdb.track_gen.TrackGen(rowgen, decimate=False)
# Visualization
aisdb.web_interface.visualize(
tracks,
visualearth=False,
open_browser=True,
)