Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates the ship_traffic notebook to match AE5 deployment #359

Merged
merged 3 commits into from
Jun 26, 2024
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 60 additions & 11 deletions ship_traffic/ship_traffic.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"# Ship Traffic"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Exploring AIS vessel-traffic data\n",
"# Exploring AIS vessel-traffic data\n",
"\n",
"This [Jupyter](https://jupyter.org) notebook demonstrates how to use the [Datashader](https://datashader.org)-based rendering in [HoloViews](https://holoviews.org) to explore and analyze US Coast Guard [Automatic Identification System (AIS)](https://en.wikipedia.org/wiki/Automatic_identification_system) vessel-location data. AIS data includes vessels identified by their [Maritime Mobile Service Identity](https://en.wikipedia.org/wiki/Maritime_Mobile_Service_Identity) numbers along with other data such as vessel type. Data is provided here for January 2020 (200 million datapoints), but additional months and years of data can be downloaded for US coastal areas from [marinecadastre.gov](https://marinecadastre.gov/ais), and with slight modifications the same code here should work for AIS data available for other regions. This notebook also illustrates a workflow for visualizing large categorical datasets in general, letting users interact with individual datapoints even though the data itself is never sent to the browser for plotting."
]
Expand All @@ -30,7 +23,7 @@
"from holoviews.util.transform import lon_lat_to_easting_northing as ll2en\n",
"from dask.diagnostics import ProgressBar\n",
"\n",
"hv.extension('bokeh', 'matplotlib')"
"hv.extension('bokeh', 'matplotlib', width=100)"
]
},
{
Expand Down Expand Up @@ -350,7 +343,7 @@
"tiles = hv.element.tiles.ESRI().opts(alpha=0.4, bgcolor=\"black\").opts(responsive=True, min_height=600)\n",
"labels = hv.element.tiles.StamenLabels().opts(alpha=0.7, level='glyph')\n",
"\n",
"tiles * points * labels * legend.opts(xaxis='bare',yaxis='bare', title='')"
"tiles * labels * points.opts(show_legend=False) * legend.opts(xaxis='bare',yaxis='bare', title='')"
]
},
{
Expand All @@ -366,6 +359,61 @@
"To find out more about particular datapoints that we see, we can use HoloViews and Bokeh tools to watch for the x,y location of a tap, then query the underlying dataset for a ping in that region, and then then highlight it on top of the main plot."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from bokeh.models import CustomJSHover\n",
"from holoviews.operation.datashader import rasterize\n",
"\n",
"def convert(x):\n",
" try:\n",
" return int(x)\n",
" except:\n",
" return 0"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"vtypes_copy = vessel_types.copy()\n",
"vtypes_copy['VesselType'] = vtypes_copy['num'] \n",
"mmsi_vessels_df = vessels[['MMSI', 'VesselName', 'VesselType']].copy()\n",
"mmsi_mapping_df = mmsi_vessels_df.merge(vtypes_copy, on='VesselType')\n",
"mmsi_mapping_df['ShipType'] = mmsi_mapping_df['VesselType'].apply(lambda x: category_desc(categories[x]))\n",
"MAPPING = {int(el['MMSI']):str(el['VesselName'])+' : '+el['ShipType'] for el in mmsi_mapping_df[['MMSI', 'VesselName', 'ShipType']].to_dict(orient='records')}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def lookup_hook(plot, element):\n",
" test = CustomJSHover(\n",
" code=f\"\"\"\n",
" const mapping = {MAPPING};\n",
" if ( value in mapping ) {{\n",
" return mapping[value].toString()\n",
" }}\n",
" return \"No ship info\"\n",
" \"\"\"\n",
" )\n",
"\n",
" plot.handles[\"hover\"].tooltips.pop() # The index\n",
" plot.handles[\"hover\"].tooltips.append((\"Ship\", \"@image{custom}\"))\n",
" plot.handles[\"hover\"].formatters[\"@image\"] = test\n",
"\n",
"vessel_name_raster = rasterize(hv.Points(df, vdims=['MMSI']).redim.range(**loc['Vancouver Area']) , \n",
" aggregator=ds.max('MMSI')).opts(tools=[\"hover\"], hooks=[lookup_hook], alpha=0)"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand All @@ -391,6 +439,7 @@
"pts2 = hv.Points(df, vdims=['category']).redim.range(**loc['Vancouver Area'])\n",
"pointsp = hd.dynspread(hd.datashade(pts2, color_key=color_key, aggregator=ds.count_cat('category'), min_alpha=90))\n",
"\n",
"\n",
"max_hits = pn.widgets.IntSlider(value=2, start=1, end=10, name=\"Max hits\", sizing_mode='stretch_width')\n",
"highlighter = hd.inspect_points.instance(streams=[hv.streams.Tap], transform=brief_vessel_record,\n",
" x=-13922122, y=6184391) # optional initial values for static web page\n",
Expand Down Expand Up @@ -468,7 +517,7 @@
"data_opacity = pn.widgets.FloatSlider(value=1.0, name=\"Data opacity\", **sopts)\n",
"label_opacity = pn.widgets.FloatSlider(value=0.9, name=\"Label opacity\", **sopts)\n",
"overlay = (tiles.apply.opts(alpha=map_opacity) *\n",
" pointsp.apply.opts(alpha=data_opacity) *\n",
" pointsp.apply.opts(alpha=data_opacity, show_legend=False) * vessel_name_raster *\n",
" labels.apply.opts(alpha=label_opacity) * highlight * legend)\n",
"\n",
"description = \"\"\"\n",
Expand Down
Loading