diff --git a/2-analysis-examples/bird-migration.ipynb b/2-analysis-examples/bird-migration.ipynb index 5aa9381..28f7339 100644 --- a/2-analysis-examples/bird-migration.ipynb +++ b/2-analysis-examples/bird-migration.ipynb @@ -38,7 +38,7 @@ "import geopandas as gpd\n", "import movingpandas as mpd\n", "import shapely as shp\n", - "import hvplot.pandas \n", + "import hvplot.pandas\n", "import matplotlib.pyplot as plt\n", "\n", "from geopandas import GeoDataFrame, read_file\n", @@ -49,11 +49,14 @@ "from urllib.request import urlretrieve\n", "\n", "import warnings\n", - "warnings.filterwarnings('ignore')\n", "\n", - "plot_defaults = {'linewidth':5, 'capstyle':'round', 'figsize':(9,3), 'legend':True}\n", - "opts.defaults(opts.Overlay(active_tools=['wheel_zoom'], frame_width=300, frame_height=500))\n", - "hvplot_defaults = {'tiles':None, 'cmap':'Viridis', 'colorbar':True}\n", + "warnings.filterwarnings(\"ignore\")\n", + "\n", + "plot_defaults = {\"linewidth\": 5, \"capstyle\": \"round\", \"figsize\": (9, 3), \"legend\": True}\n", + "opts.defaults(\n", + " opts.Overlay(active_tools=[\"wheel_zoom\"], frame_width=300, frame_height=500)\n", + ")\n", + "hvplot_defaults = {\"tiles\": None, \"cmap\": \"Viridis\", \"colorbar\": True}\n", "\n", "mpd.show_versions()" ] @@ -72,7 +75,7 @@ "outputs": [], "source": [ "%%time\n", - "df = read_file('../data/gulls.gpkg')\n", + "df = read_file(\"../data/gulls.gpkg\")\n", "print(f\"Finished reading {len(df)}\")" ] }, @@ -114,7 +117,7 @@ "metadata": {}, "outputs": [], "source": [ - "df['individual-local-identifier'].unique()" + "df[\"individual-local-identifier\"].unique()" ] }, { @@ -130,7 +133,7 @@ "metadata": {}, "outputs": [], "source": [ - "df['individual-local-identifier'].value_counts().plot(kind='bar', figsize=(17,3))" + "df[\"individual-local-identifier\"].value_counts().plot(kind=\"bar\", figsize=(17, 3))" ] }, { @@ -146,7 +149,9 @@ "metadata": {}, "outputs": [], "source": [ - "tc = mpd.TrajectoryCollection(df, 'individual-local-identifier', t='timestamp', min_length=100) \n", + "tc = mpd.TrajectoryCollection(\n", + " df, \"individual-local-identifier\", t=\"timestamp\", min_length=100\n", + ")\n", "tc" ] }, @@ -186,7 +191,7 @@ "metadata": {}, "outputs": [], "source": [ - "filtered = tc.filter('individual-local-identifier', '91916A')\n", + "filtered = tc.filter(\"individual-local-identifier\", \"91916A\")\n", "my_traj = filtered.trajectories[0].copy()\n", "my_traj.df.head()" ] @@ -197,7 +202,7 @@ "metadata": {}, "outputs": [], "source": [ - "my_traj.hvplot(title=f'Movement of {my_traj.id}', line_width=2) " + "my_traj.hvplot(title=f\"Movement of {my_traj.id}\", line_width=2)" ] }, { @@ -215,7 +220,7 @@ "metadata": {}, "outputs": [], "source": [ - "trips_by_year = mpd.TemporalSplitter(filtered).split(mode='year')\n", + "trips_by_year = mpd.TemporalSplitter(filtered).split(mode=\"year\")\n", "trips_by_year.to_traj_gdf()" ] }, @@ -232,7 +237,7 @@ "metadata": {}, "outputs": [], "source": [ - "one_year = trips_by_year.get_trajectory('91916A_2010-12-31 00:00:00')\n", + "one_year = trips_by_year.get_trajectory(\"91916A_2010-12-31 00:00:00\")\n", "one_year" ] }, @@ -251,8 +256,14 @@ "metadata": {}, "outputs": [], "source": [ - "one_year.hvplot(title=f'Movement speed of {one_year.id}', \n", - " line_width=5.0, c='speed', cmap='RdYlGn', colorbar=True, clim=(0,20)) " + "one_year.hvplot(\n", + " title=f\"Movement speed of {one_year.id}\",\n", + " line_width=5.0,\n", + " c=\"speed\",\n", + " cmap=\"RdYlGn\",\n", + " colorbar=True,\n", + " clim=(0, 20),\n", + ")" ] }, { @@ -270,8 +281,11 @@ "source": [ "def plot_location_at_timestamp(traj, t, fig_size=250):\n", " loc = GeoDataFrame([traj.get_row_at(t)])\n", - " return (loc.hvplot(title=str(t), geo=True, tiles='OSM', size=200, color='red') * \n", - " traj.hvplot(line_width=1.0, color='black', tiles=False, width=fig_size, height=fig_size))" + " return loc.hvplot(\n", + " title=str(t), geo=True, tiles=\"OSM\", size=200, color=\"red\"\n", + " ) * traj.hvplot(\n", + " line_width=1.0, color=\"black\", tiles=False, width=fig_size, height=fig_size\n", + " )" ] }, { @@ -280,9 +294,11 @@ "metadata": {}, "outputs": [], "source": [ - "( plot_location_at_timestamp(one_year, datetime(2010,9,1)) + \n", - " plot_location_at_timestamp(one_year, datetime(2010,10,1)) +\n", - " plot_location_at_timestamp(one_year, datetime(2010,11,1)) )" + "(\n", + " plot_location_at_timestamp(one_year, datetime(2010, 9, 1))\n", + " + plot_location_at_timestamp(one_year, datetime(2010, 10, 1))\n", + " + plot_location_at_timestamp(one_year, datetime(2010, 11, 1))\n", + ")" ] }, { @@ -302,11 +318,13 @@ " ts = [datetime(year, month, day) for year in traj.df.index.year.unique()]\n", " return plot_locations_at_timestamps(traj, ts, ax=ax)\n", "\n", - "def plot_locations_at_timestamps(traj, ts, ax=None): \n", + "\n", + "def plot_locations_at_timestamps(traj, ts, ax=None):\n", " loc = GeoDataFrame([traj.get_row_at(t) for t in ts])\n", - " loc['date_label'] = loc.index.strftime('%Y-%m-%d')\n", - " return (loc.hvplot(title=f'Movement of {traj.id}', c='date_label', size=200, geo=True, tiles='OSM') *\n", - " traj.hvplot(line_width=1.0, color='black', geo=True, tiles=False) )" + " loc[\"date_label\"] = loc.index.strftime(\"%Y-%m-%d\")\n", + " return loc.hvplot(\n", + " title=f\"Movement of {traj.id}\", c=\"date_label\", size=200, geo=True, tiles=\"OSM\"\n", + " ) * traj.hvplot(line_width=1.0, color=\"black\", geo=True, tiles=False)" ] }, { @@ -334,7 +352,9 @@ "outputs": [], "source": [ "area_of_interest = Polygon([(30, 25), (50, 25), (50, 15), (30, 15), (30, 25)])\n", - "plotted_area_of_interest = GeoDataFrame(pd.DataFrame([{'geometry': area_of_interest, 'id': 1}]), crs=4326).hvplot(geo=True, color='yellow', alpha=0.5)" + "plotted_area_of_interest = GeoDataFrame(\n", + " pd.DataFrame([{\"geometry\": area_of_interest, \"id\": 1}]), crs=4326\n", + ").hvplot(geo=True, color=\"yellow\", alpha=0.5)" ] }, { @@ -347,7 +367,9 @@ "print(f\"Found {len(arrivals)} arrivals\")\n", "\n", "for traj in arrivals:\n", - " print(f\"Individual '{traj.df['individual-local-identifier'].iloc[0]}' arrived at {traj.get_start_time()}\")" + " print(\n", + " f\"Individual '{traj.df['individual-local-identifier'].iloc[0]}' arrived at {traj.get_start_time()}\"\n", + " )" ] }, { @@ -356,7 +378,10 @@ "metadata": {}, "outputs": [], "source": [ - "( plot_locations_at_timestamps(my_traj, [traj.get_start_time() for traj in arrivals]) * plotted_area_of_interest )" + "(\n", + " plot_locations_at_timestamps(my_traj, [traj.get_start_time() for traj in arrivals])\n", + " * plotted_area_of_interest\n", + ")" ] }, { @@ -376,7 +401,12 @@ "source": [ "year_of_interest = 2010\n", "trajs_in_aoi = tc.clip(area_of_interest)\n", - "relevant = [ traj for traj in trajs_in_aoi if traj.get_start_time().year <= year_of_interest and traj.get_end_time().year >= year_of_interest]\n", + "relevant = [\n", + " traj\n", + " for traj in trajs_in_aoi\n", + " if traj.get_start_time().year <= year_of_interest\n", + " and traj.get_end_time().year >= year_of_interest\n", + "]\n", "print(\"Found {} arrivals\".format(len(relevant)))" ] }, @@ -387,9 +417,13 @@ "outputs": [], "source": [ "for traj in relevant:\n", - " print(\"Individual '{}' arrived at {} (duration: {})\".format(\n", - " traj.df['individual-local-identifier'].iloc[0], traj.get_start_time().date(), \n", - " traj.get_end_time()-traj.get_start_time()))" + " print(\n", + " \"Individual '{}' arrived at {} (duration: {})\".format(\n", + " traj.df[\"individual-local-identifier\"].iloc[0],\n", + " traj.get_start_time().date(),\n", + " traj.get_end_time() - traj.get_start_time(),\n", + " )\n", + " )" ] }, { @@ -407,10 +441,12 @@ "metadata": {}, "outputs": [], "source": [ - "my_traj = tc.get_trajectory('91761A')\n", - "segment = my_traj.get_segment_between(datetime(year_of_interest,1,1), datetime(year_of_interest,12,31))\n", + "my_traj = tc.get_trajectory(\"91761A\")\n", + "segment = my_traj.get_segment_between(\n", + " datetime(year_of_interest, 1, 1), datetime(year_of_interest, 12, 31)\n", + ")\n", "\n", - "segment.hvplot(color='black', line_width=1.0) * plotted_area_of_interest " + "segment.hvplot(color=\"black\", line_width=1.0) * plotted_area_of_interest" ] }, { @@ -435,7 +471,8 @@ "1. [Soccer game](soccer-game.ipynb)\n", "1. [Mars rover & heli](mars-rover.ipynb)\n", "1. [Ever Given](ever-given.ipynb)\n", - "1. [Iceberg](iceberg.ipynb) " + "1. [Iceberg](iceberg.ipynb)\n", + "1. [Pollution data](pollution-data.ipynb)" ] } ], diff --git a/2-analysis-examples/ever-given.ipynb b/2-analysis-examples/ever-given.ipynb index cd4d0df..ba2bdf3 100644 --- a/2-analysis-examples/ever-given.ipynb +++ b/2-analysis-examples/ever-given.ipynb @@ -41,6 +41,7 @@ "from holoviews.selection import link_selections\n", "\n", "import warnings\n", + "\n", "warnings.simplefilter(\"ignore\")" ] }, @@ -60,8 +61,8 @@ "metadata": {}, "outputs": [], "source": [ - "df = pd.read_csv('../data/boat-positions.csv')\n", - "df['t'] = pd.to_datetime(df['ais_pos_timestamp'], format='%d/%m/%Y %H:%M')\n", + "df = pd.read_csv(\"../data/boat-positions.csv\")\n", + "df[\"t\"] = pd.to_datetime(df[\"ais_pos_timestamp\"], format=\"%d/%m/%Y %H:%M\")\n", "df" ] }, @@ -71,8 +72,11 @@ "metadata": {}, "outputs": [], "source": [ - "gdf = gpd.GeoDataFrame(df.drop(['longitude', 'latitude', 'ais_pos_timestamp'], axis=1), \n", - " crs='epsg:4326', geometry=[Point(xy) for xy in zip(df.longitude, df.latitude)])\n", + "gdf = gpd.GeoDataFrame(\n", + " df.drop([\"longitude\", \"latitude\", \"ais_pos_timestamp\"], axis=1),\n", + " crs=\"epsg:4326\",\n", + " geometry=[Point(xy) for xy in zip(df.longitude, df.latitude)],\n", + ")\n", "gdf" ] }, @@ -82,7 +86,7 @@ "metadata": {}, "outputs": [], "source": [ - "gdf.hvplot(geo=True, tiles='OSM', frame_width=FSIZE, frame_height=FSIZE)" + "gdf.hvplot(geo=True, tiles=\"OSM\", frame_width=FSIZE, frame_height=FSIZE)" ] }, { @@ -91,7 +95,7 @@ "metadata": {}, "outputs": [], "source": [ - "tc = mpd.TrajectoryCollection(gdf, 'ID', t='t')" + "tc = mpd.TrajectoryCollection(gdf, \"ID\", t=\"t\")" ] }, { @@ -111,7 +115,9 @@ "outputs": [], "source": [ "stop_detector = mpd.TrajectoryStopDetector(tc)\n", - "stop_pts = stop_detector.get_stop_points(min_duration=timedelta(hours=3), max_diameter=1000)\n", + "stop_pts = stop_detector.get_stop_points(\n", + " min_duration=timedelta(hours=3), max_diameter=1000\n", + ")\n", "stop_pts" ] }, @@ -121,7 +127,7 @@ "metadata": {}, "outputs": [], "source": [ - "stop_pts['duration_h'] = stop_pts['duration_s'] / 3600\n", + "stop_pts[\"duration_h\"] = stop_pts[\"duration_s\"] / 3600\n", "stop_pts" ] }, @@ -138,7 +144,7 @@ "metadata": {}, "outputs": [], "source": [ - "stop_pts[stop_pts['traj_id']==EVERID]" + "stop_pts[stop_pts[\"traj_id\"] == EVERID]" ] }, { @@ -147,15 +153,33 @@ "metadata": {}, "outputs": [], "source": [ - "map_plot = ( \n", - " stop_pts.hvplot(geo=True, hover_cols=['start_time'], size=20, tiles='OSM') * \n", - " evergiven.hvplot(line_width=5, color='red', frame_width=FSIZE, frame_height=FSIZE, alpha=0.5, tiles=None).opts(active_tools=['pan','wheelzoom']) *\n", - " stop_pts[stop_pts['traj_id']==EVERID].hvplot(geo=True, hover_cols=['start_time'], size=dim('duration_h')/2, color='red', \n", - " title='Trajectory & stop location of Ever Given and stops of other vessels')\n", + "map_plot = (\n", + " stop_pts.hvplot(geo=True, hover_cols=[\"start_time\"], size=20, tiles=\"OSM\")\n", + " * evergiven.hvplot(\n", + " line_width=5,\n", + " color=\"red\",\n", + " frame_width=FSIZE,\n", + " frame_height=FSIZE,\n", + " alpha=0.5,\n", + " tiles=None,\n", + " ).opts(active_tools=[\"pan\", \"wheelzoom\"])\n", + " * stop_pts[stop_pts[\"traj_id\"] == EVERID].hvplot(\n", + " geo=True,\n", + " hover_cols=[\"start_time\"],\n", + " size=dim(\"duration_h\") / 2,\n", + " color=\"red\",\n", + " title=\"Trajectory & stop location of Ever Given and stops of other vessels\",\n", + " )\n", ")\n", - "scatter_plot = ( \n", - " stop_pts.hvplot.scatter(title='Stop start & duration (in hours)', x='start_time', y='duration_h', frame_width=FSIZE, frame_height=FSIZE, alpha=0.7) * \n", - " stop_pts[stop_pts['traj_id']==EVERID].hvplot.scatter(x='start_time', y='duration_h', color='red', size=200) \n", + "scatter_plot = stop_pts.hvplot.scatter(\n", + " title=\"Stop start & duration (in hours)\",\n", + " x=\"start_time\",\n", + " y=\"duration_h\",\n", + " frame_width=FSIZE,\n", + " frame_height=FSIZE,\n", + " alpha=0.7,\n", + ") * stop_pts[stop_pts[\"traj_id\"] == EVERID].hvplot.scatter(\n", + " x=\"start_time\", y=\"duration_h\", color=\"red\", size=200\n", ")\n", "map_plot + scatter_plot" ] @@ -173,10 +197,11 @@ "metadata": {}, "outputs": [], "source": [ - "stop_pts[stop_pts.start_time > datetime(2021,3,23,5,39,0)]\\\n", - " .sort_values('duration_s', ascending=False)\\\n", - " .head(12)\\\n", - " #.style.background_gradient(cmap='Reds')" + "stop_pts[stop_pts.start_time > datetime(2021, 3, 23, 5, 39, 0)].sort_values(\n", + " \"duration_s\", ascending=False\n", + ").head(\n", + " 12\n", + ") # .style.background_gradient(cmap='Reds')" ] }, { @@ -192,7 +217,8 @@ "1. [Soccer game](soccer-game.ipynb)\n", "1. [Mars rover & heli](mars-rover.ipynb)\n", "1. [Ever Given](ever-given.ipynb)\n", - "1. [Iceberg](iceberg.ipynb) " + "1. [Iceberg](iceberg.ipynb)\n", + "1. [Pollution data](pollution-data.ipynb)" ] } ], diff --git a/2-analysis-examples/horse-collar.ipynb b/2-analysis-examples/horse-collar.ipynb index 9c85e67..b11d7b2 100644 --- a/2-analysis-examples/horse-collar.ipynb +++ b/2-analysis-examples/horse-collar.ipynb @@ -35,7 +35,7 @@ "import geopandas as gpd\n", "import movingpandas as mpd\n", "import shapely as shp\n", - "import hvplot.pandas \n", + "import hvplot.pandas\n", "import matplotlib.pyplot as plt\n", "\n", "from pyproj import CRS\n", @@ -47,11 +47,14 @@ "from urllib.request import urlretrieve\n", "\n", "import warnings\n", - "warnings.filterwarnings('ignore')\n", "\n", - "plot_defaults = {'linewidth':5, 'capstyle':'round', 'figsize':(9,3), 'legend':True}\n", - "opts.defaults(opts.Overlay(active_tools=['wheel_zoom'], frame_width=300, frame_height=400))\n", - "hvplot_defaults = {'tiles':None, 'cmap':'Viridis', 'colorbar':True}\n", + "warnings.filterwarnings(\"ignore\")\n", + "\n", + "plot_defaults = {\"linewidth\": 5, \"capstyle\": \"round\", \"figsize\": (9, 3), \"legend\": True}\n", + "opts.defaults(\n", + " opts.Overlay(active_tools=[\"wheel_zoom\"], frame_width=300, frame_height=400)\n", + ")\n", + "hvplot_defaults = {\"tiles\": None, \"cmap\": \"Viridis\", \"colorbar\": True}\n", "\n", "mpd.show_versions()" ] @@ -78,9 +81,9 @@ "metadata": {}, "outputs": [], "source": [ - "df = read_file('../data/horse_collar.gpkg')\n", - "df['t'] = pd.to_datetime(df['timestamp'])\n", - "df = df.set_index('t').tz_localize(None)\n", + "df = read_file(\"../data/horse_collar.gpkg\")\n", + "df[\"t\"] = pd.to_datetime(df[\"timestamp\"])\n", + "df = df.set_index(\"t\").tz_localize(None)\n", "print(\"This dataset contains {} records.\\nThe first lines are:\".format(len(df)))\n", "df.head()" ] @@ -100,13 +103,48 @@ "metadata": {}, "outputs": [], "source": [ - "df = df.drop(columns=['LMT_Date', 'LMT_Time',\n", - " 'Origin', 'SCTS_Date', 'SCTS_Time', 'Latitude [?]', 'Longitude [?]',\n", - " 'FixType', 'Main [V]', 'Beacon [V]', 'Sats', 'Sat',\n", - " 'C/N', 'Sat_1', 'C/N_1', 'Sat_2', 'C/N_2', 'Sat_3', 'C/N_3', 'Sat_4',\n", - " 'C/N_4', 'Sat_5', 'C/N_5', 'Sat_6', 'C/N_6', 'Sat_7', 'C/N_7', 'Sat_8',\n", - " 'C/N_8', 'Sat_9', 'C/N_9', 'Sat_10', 'C/N_10', 'Sat_11', 'C/N_11',\n", - " 'Easting', 'Northing',], axis=1)" + "df = df.drop(\n", + " columns=[\n", + " \"LMT_Date\",\n", + " \"LMT_Time\",\n", + " \"Origin\",\n", + " \"SCTS_Date\",\n", + " \"SCTS_Time\",\n", + " \"Latitude [?]\",\n", + " \"Longitude [?]\",\n", + " \"FixType\",\n", + " \"Main [V]\",\n", + " \"Beacon [V]\",\n", + " \"Sats\",\n", + " \"Sat\",\n", + " \"C/N\",\n", + " \"Sat_1\",\n", + " \"C/N_1\",\n", + " \"Sat_2\",\n", + " \"C/N_2\",\n", + " \"Sat_3\",\n", + " \"C/N_3\",\n", + " \"Sat_4\",\n", + " \"C/N_4\",\n", + " \"Sat_5\",\n", + " \"C/N_5\",\n", + " \"Sat_6\",\n", + " \"C/N_6\",\n", + " \"Sat_7\",\n", + " \"C/N_7\",\n", + " \"Sat_8\",\n", + " \"C/N_8\",\n", + " \"Sat_9\",\n", + " \"C/N_9\",\n", + " \"Sat_10\",\n", + " \"C/N_10\",\n", + " \"Sat_11\",\n", + " \"C/N_11\",\n", + " \"Easting\",\n", + " \"Northing\",\n", + " ],\n", + " axis=1,\n", + ")" ] }, { @@ -124,7 +162,7 @@ "metadata": {}, "outputs": [], "source": [ - "collar_id = df['CollarID'].unique()[0]\n", + "collar_id = df[\"CollarID\"].unique()[0]\n", "print(\"There is only one collar with ID {}.\".format(collar_id))" ] }, @@ -134,7 +172,7 @@ "metadata": {}, "outputs": [], "source": [ - "df['Activity'].unique()" + "df[\"Activity\"].unique()" ] }, { @@ -166,7 +204,9 @@ "metadata": {}, "outputs": [], "source": [ - "df.to_crs({'init': 'epsg:4326'}).hvplot(title='Geographic extent of the dataset', geo=True, tiles='OSM')" + "df.to_crs({\"init\": \"epsg:4326\"}).hvplot(\n", + " title=\"Geographic extent of the dataset\", geo=True, tiles=\"OSM\"\n", + ")" ] }, { @@ -184,7 +224,7 @@ "metadata": {}, "outputs": [], "source": [ - "pd.DataFrame(df).sort_values('lat').tail(2)" + "pd.DataFrame(df).sort_values(\"lat\").tail(2)" ] }, { @@ -202,9 +242,17 @@ "metadata": {}, "outputs": [], "source": [ - "df = df[2:].to_crs({'init': 'epsg:4326'})\n", - "( df.hvplot(title='OSM showing paths and fences', size=2, geo=True, tiles='OSM') +\n", - " df.hvplot(title='Imagery showing land cover details', size=2, color='red', geo=True, tiles='EsriImagery') )" + "df = df[2:].to_crs({\"init\": \"epsg:4326\"})\n", + "(\n", + " df.hvplot(title=\"OSM showing paths and fences\", size=2, geo=True, tiles=\"OSM\")\n", + " + df.hvplot(\n", + " title=\"Imagery showing land cover details\",\n", + " size=2,\n", + " color=\"red\",\n", + " geo=True,\n", + " tiles=\"EsriImagery\",\n", + " )\n", + ")" ] }, { @@ -221,10 +269,10 @@ "outputs": [], "source": [ "temp = df.to_crs(CRS(25832))\n", - "temp['geometry'] = temp['geometry'].buffer(5)\n", - "total_area = temp.dissolve(by='CollarID').area \n", - "total_area = total_area[collar_id]/10000\n", - "print('The total area covered by the data is: {:,.2f} ha'.format(total_area))" + "temp[\"geometry\"] = temp[\"geometry\"].buffer(5)\n", + "total_area = temp.dissolve(by=\"CollarID\").area\n", + "total_area = total_area[collar_id] / 10000\n", + "print(\"The total area covered by the data is: {:,.2f} ha\".format(total_area))" ] }, { @@ -240,7 +288,11 @@ "metadata": {}, "outputs": [], "source": [ - "print(\"The dataset covers the time between {} and {}.\".format(df.index.min(), df.index.max()))" + "print(\n", + " \"The dataset covers the time between {} and {}.\".format(\n", + " df.index.min(), df.index.max()\n", + " )\n", + ")" ] }, { @@ -258,7 +310,7 @@ "metadata": {}, "outputs": [], "source": [ - "df['No'].resample('1d').count().hvplot(title='Number of records per day')" + "df[\"No\"].resample(\"1d\").count().hvplot(title=\"Number of records per day\")" ] }, { @@ -285,8 +337,13 @@ "metadata": {}, "outputs": [], "source": [ - "df['Y-M'] = df.index.to_period('M') \n", - "Layout([df[df['Y-M']==i].hvplot(title=str(i), size=2, geo=True, tiles='OSM') for i in df['Y-M'].unique()])" + "df[\"Y-M\"] = df.index.to_period(\"M\")\n", + "Layout(\n", + " [\n", + " df[df[\"Y-M\"] == i].hvplot(title=str(i), size=2, geo=True, tiles=\"OSM\")\n", + " for i in df[\"Y-M\"].unique()\n", + " ]\n", + ")" ] }, { @@ -325,8 +382,13 @@ "source": [ "t = df.reset_index().t\n", "df = df.assign(delta_t=t.diff().values)\n", - "df['delta_t'] = df['delta_t'].dt.total_seconds()/60\n", - "pd.DataFrame(df).hvplot.hist('delta_t', title='Histogram of intervals between consecutive records (in minutes)', bins=60, bin_range=(0, 60))" + "df[\"delta_t\"] = df[\"delta_t\"].dt.total_seconds() / 60\n", + "pd.DataFrame(df).hvplot.hist(\n", + " \"delta_t\",\n", + " title=\"Histogram of intervals between consecutive records (in minutes)\",\n", + " bins=60,\n", + " bin_range=(0, 60),\n", + ")" ] }, { @@ -353,11 +415,15 @@ "metadata": {}, "outputs": [], "source": [ - "tc = mpd.TrajectoryCollection(df, 'CollarID')\n", + "tc = mpd.TrajectoryCollection(df, \"CollarID\")\n", "traj = tc.trajectories[0]\n", "traj.add_speed()\n", "max_speed = traj.df.speed.max()\n", - "print(\"The highest computed speed is {:,.2f} m/s ({:,.2f} km/h)\".format(max_speed, max_speed*3600/1000))" + "print(\n", + " \"The highest computed speed is {:,.2f} m/s ({:,.2f} km/h)\".format(\n", + " max_speed, max_speed * 3600 / 1000\n", + " )\n", + ")" ] }, { @@ -373,7 +439,9 @@ "metadata": {}, "outputs": [], "source": [ - "pd.DataFrame(traj.df).hvplot.hist('speed', title='Histogram of speeds (in meters per second)', bins=90)" + "pd.DataFrame(traj.df).hvplot.hist(\n", + " \"speed\", title=\"Histogram of speeds (in meters per second)\", bins=90\n", + ")" ] }, { @@ -390,7 +458,7 @@ "outputs": [], "source": [ "traj.add_direction(overwrite=True)\n", - "pd.DataFrame(traj.df).hvplot.hist('direction', title='Histogram of directions', bins=90)" + "pd.DataFrame(traj.df).hvplot.hist(\"direction\", title=\"Histogram of directions\", bins=90)" ] }, { @@ -417,8 +485,13 @@ "metadata": {}, "outputs": [], "source": [ - "pd.DataFrame(traj.df).hvplot.heatmap(title='Mean speed by hour of day and month of year', \n", - " x='t.hour', y='t.month', C='speed', reduce_function=np.mean)" + "pd.DataFrame(traj.df).hvplot.heatmap(\n", + " title=\"Mean speed by hour of day and month of year\",\n", + " x=\"t.hour\",\n", + " y=\"t.month\",\n", + " C=\"speed\",\n", + " reduce_function=np.mean,\n", + ")" ] }, { @@ -438,9 +511,14 @@ "metadata": {}, "outputs": [], "source": [ - "traj.df['n'] = 1\n", - "pd.DataFrame(traj.df).hvplot.heatmap(title='Record count by temperature and month of year', \n", - " x='Temp [?C]', y='t.month', C='n', reduce_function=np.sum)" + "traj.df[\"n\"] = 1\n", + "pd.DataFrame(traj.df).hvplot.heatmap(\n", + " title=\"Record count by temperature and month of year\",\n", + " x=\"Temp [?C]\",\n", + " y=\"t.month\",\n", + " C=\"n\",\n", + " reduce_function=np.sum,\n", + ")" ] }, { @@ -449,8 +527,13 @@ "metadata": {}, "outputs": [], "source": [ - "pd.DataFrame(traj.df).hvplot.heatmap(title='Mean speed by temperature and month of year', \n", - " x='Temp [?C]', y='t.month', C='speed', reduce_function=np.mean)" + "pd.DataFrame(traj.df).hvplot.heatmap(\n", + " title=\"Mean speed by temperature and month of year\",\n", + " x=\"Temp [?C]\",\n", + " y=\"t.month\",\n", + " C=\"speed\",\n", + " reduce_function=np.mean,\n", + ")" ] }, { @@ -468,9 +551,21 @@ "metadata": {}, "outputs": [], "source": [ - "traj.df['dir_class'] = ((traj.df['direction']-22.5)/45).round(0)\n", + "traj.df[\"dir_class\"] = ((traj.df[\"direction\"] - 22.5) / 45).round(0)\n", "temp = traj.df\n", - "Layout([temp[temp['dir_class']==i].hvplot(geo=True, tiles='OSM', size=2, width=300, height=300, title=str(int(i*45))+\"°\") for i in sorted(temp['dir_class'].unique())])" + "Layout(\n", + " [\n", + " temp[temp[\"dir_class\"] == i].hvplot(\n", + " geo=True,\n", + " tiles=\"OSM\",\n", + " size=2,\n", + " width=300,\n", + " height=300,\n", + " title=str(int(i * 45)) + \"°\",\n", + " )\n", + " for i in sorted(temp[\"dir_class\"].unique())\n", + " ]\n", + ")" ] }, { @@ -486,14 +581,24 @@ "metadata": {}, "outputs": [], "source": [ - "traj.df['speed_class'] = (traj.df['speed']*2).round(1)\n", + "traj.df[\"speed_class\"] = (traj.df[\"speed\"] * 2).round(1)\n", "temp = traj.df\n", "plots = []\n", - "for i in sorted(temp['speed_class'].unique()):\n", - " filtered = temp[temp['speed_class']==i]\n", - " if len(filtered) < 10: \n", + "for i in sorted(temp[\"speed_class\"].unique()):\n", + " filtered = temp[temp[\"speed_class\"] == i]\n", + " if len(filtered) < 10:\n", " continue\n", - " plots.append(filtered.hvplot(geo=True, tiles='EsriImagery', color='red', size=2, width=300, height=300, title=str(i/2)))\n", + " plots.append(\n", + " filtered.hvplot(\n", + " geo=True,\n", + " tiles=\"EsriImagery\",\n", + " color=\"red\",\n", + " size=2,\n", + " width=300,\n", + " height=300,\n", + " title=str(i / 2),\n", + " )\n", + " )\n", "Layout(plots)" ] }, @@ -530,7 +635,7 @@ "metadata": {}, "outputs": [], "source": [ - "tc.hvplot() " + "tc.hvplot()" ] }, { @@ -555,7 +660,7 @@ "metadata": {}, "outputs": [], "source": [ - "daily = mpd.TemporalSplitter(tc).split(mode='day')" + "daily = mpd.TemporalSplitter(tc).split(mode=\"day\")" ] }, { @@ -564,7 +669,14 @@ "metadata": {}, "outputs": [], "source": [ - "Layout([daily.trajectories[i].hvplot(title=daily.trajectories[i].id, c='speed', line_width=2, cmap='RdYlBu') for i in range(0,7)])" + "Layout(\n", + " [\n", + " daily.trajectories[i].hvplot(\n", + " title=daily.trajectories[i].id, c=\"speed\", line_width=2, cmap=\"RdYlBu\"\n", + " )\n", + " for i in range(0, 7)\n", + " ]\n", + ")" ] }, { @@ -581,9 +693,9 @@ "outputs": [], "source": [ "daily_starts = daily.get_start_locations()\n", - "daily_starts.set_index(pd.to_datetime(daily_starts['timestamp']), inplace=True) \n", - "daily_starts['month'] = daily_starts.index.month\n", - "daily_starts.hvplot(c='month', geo=True, tiles='EsriImagery', cmap='autumn')" + "daily_starts.set_index(pd.to_datetime(daily_starts[\"timestamp\"]), inplace=True)\n", + "daily_starts[\"month\"] = daily_starts.index.month\n", + "daily_starts.hvplot(c=\"month\", geo=True, tiles=\"EsriImagery\", cmap=\"autumn\")" ] }, { @@ -606,7 +718,7 @@ "metadata": {}, "outputs": [], "source": [ - "moving = mpd.TrajectoryCollection(traj.df[traj.df['speed'] > 0.05], 'CollarID')\n", + "moving = mpd.TrajectoryCollection(traj.df[traj.df[\"speed\"] > 0.05], \"CollarID\")\n", "moving = mpd.ObservationGapSplitter(moving).split(gap=timedelta(minutes=70))" ] }, @@ -616,7 +728,9 @@ "metadata": {}, "outputs": [], "source": [ - "moving.get_start_locations().hvplot(c='month', geo=True, tiles='EsriImagery', color='red')" + "moving.get_start_locations().hvplot(\n", + " c=\"month\", geo=True, tiles=\"EsriImagery\", color=\"red\"\n", + ")" ] }, { @@ -642,8 +756,8 @@ "metadata": {}, "outputs": [], "source": [ - "daily_lengths = pd.DataFrame(daily_lengths, index=daily_t, columns=['length'])\n", - "daily_lengths.hvplot(title='Daily trajectory length')" + "daily_lengths = pd.DataFrame(daily_lengths, index=daily_t, columns=[\"length\"])\n", + "daily_lengths.hvplot(title=\"Daily trajectory length\")" ] }, { @@ -675,9 +789,12 @@ "metadata": {}, "outputs": [], "source": [ - "daily_areas = [(traj.id, traj.to_crs(CRS(25832)).to_linestring().convex_hull.area/10000) for traj in daily]\n", - "daily_areas = pd.DataFrame(daily_areas, index=daily_t, columns=['id', 'area'])\n", - "daily_areas.hvplot(title='Daily covered area [ha]', y='area')" + "daily_areas = [\n", + " (traj.id, traj.to_crs(CRS(25832)).to_linestring().convex_hull.area / 10000)\n", + " for traj in daily\n", + "]\n", + "daily_areas = pd.DataFrame(daily_areas, index=daily_t, columns=[\"id\", \"area\"])\n", + "daily_areas.hvplot(title=\"Daily covered area [ha]\", y=\"area\")" ] }, { @@ -693,9 +810,12 @@ "metadata": {}, "outputs": [], "source": [ - "daily_areas = [(traj.id, traj.to_crs(CRS(25832)).to_linestring().buffer(15).area/10000) for traj in daily]\n", - "daily_areas = pd.DataFrame(daily_areas, index=daily_t, columns=['id', 'area'])\n", - "daily_areas.hvplot(title='Daily covered area [ha]', y='area')" + "daily_areas = [\n", + " (traj.id, traj.to_crs(CRS(25832)).to_linestring().buffer(15).area / 10000)\n", + " for traj in daily\n", + "]\n", + "daily_areas = pd.DataFrame(daily_areas, index=daily_t, columns=[\"id\", \"area\"])\n", + "daily_areas.hvplot(title=\"Daily covered area [ha]\", y=\"area\")" ] }, { @@ -711,7 +831,7 @@ "metadata": {}, "outputs": [], "source": [ - "daily_areas.sort_values(by='area')[:10]" + "daily_areas.sort_values(by=\"area\")[:10]" ] }, { @@ -727,8 +847,8 @@ "metadata": {}, "outputs": [], "source": [ - "daily_areas = daily_areas.drop(datetime(2018,11,14,12,30,8))\n", - "daily_areas = daily_areas.drop(datetime(2019,11,7,0,0,9))" + "daily_areas = daily_areas.drop(datetime(2018, 11, 14, 12, 30, 8))\n", + "daily_areas = daily_areas.drop(datetime(2019, 11, 7, 0, 0, 9))" ] }, { @@ -744,7 +864,14 @@ "metadata": {}, "outputs": [], "source": [ - "Layout([daily.get_trajectory(i).hvplot(title=i, c='speed', line_width=2, cmap='RdYlBu', width=300, height=300) for i in daily_areas.sort_values(by='area')[:3].id])" + "Layout(\n", + " [\n", + " daily.get_trajectory(i).hvplot(\n", + " title=i, c=\"speed\", line_width=2, cmap=\"RdYlBu\", width=300, height=300\n", + " )\n", + " for i in daily_areas.sort_values(by=\"area\")[:3].id\n", + " ]\n", + ")" ] }, { @@ -767,13 +894,20 @@ "MAX_DIAMETER = 100\n", "MIN_DURATION = timedelta(hours=3)\n", "\n", - "one_day = daily.get_trajectory('30788_2018-11-17 00:00:00')\n", + "one_day = daily.get_trajectory(\"30788_2018-11-17 00:00:00\")\n", "one_day_stops = mpd.TrajectoryStopDetector(one_day).get_stop_segments(\n", - " min_duration=MIN_DURATION, max_diameter=MAX_DIAMETER)\n", + " min_duration=MIN_DURATION, max_diameter=MAX_DIAMETER\n", + ")\n", "\n", - "( one_day.hvplot(title='Stops in Trajectory {}'.format(one_day.id), line_width=3.0, color='slategray') * \n", - " one_day_stops.hvplot(line_width=5, tiles=None, color='deeppink') *\n", - " one_day_stops.get_start_locations().hvplot(geo=True, size=200, color='deeppink') )" + "(\n", + " one_day.hvplot(\n", + " title=\"Stops in Trajectory {}\".format(one_day.id),\n", + " line_width=3.0,\n", + " color=\"slategray\",\n", + " )\n", + " * one_day_stops.hvplot(line_width=5, tiles=None, color=\"deeppink\")\n", + " * one_day_stops.get_start_locations().hvplot(geo=True, size=200, color=\"deeppink\")\n", + ")" ] }, { @@ -790,7 +924,9 @@ "outputs": [], "source": [ "%%time\n", - "stops = mpd.TrajectoryStopDetector(tc).get_stop_points(min_duration=MIN_DURATION, max_diameter=MAX_DIAMETER)\n", + "stops = mpd.TrajectoryStopDetector(tc).get_stop_points(\n", + " min_duration=MIN_DURATION, max_diameter=MAX_DIAMETER\n", + ")\n", "len(stops)" ] }, @@ -809,7 +945,7 @@ }, "outputs": [], "source": [ - "stops.hvplot(geo=True, tiles='OSM', color='deeppink', size=MAX_DIAMETER, alpha=0.2)" + "stops.hvplot(geo=True, tiles=\"OSM\", color=\"deeppink\", size=MAX_DIAMETER, alpha=0.2)" ] }, { @@ -818,8 +954,12 @@ "metadata": {}, "outputs": [], "source": [ - "stops['duration_h'] = (stops['end_time']-stops['start_time']).dt.total_seconds() / 3600\n", - "pd.DataFrame(stops)['duration_h'].hvplot.hist(title='Stop duration histogram', xlabel='Duration [hours]', ylabel='n', bins=12)" + "stops[\"duration_h\"] = (\n", + " stops[\"end_time\"] - stops[\"start_time\"]\n", + ").dt.total_seconds() / 3600\n", + "pd.DataFrame(stops)[\"duration_h\"].hvplot.hist(\n", + " title=\"Stop duration histogram\", xlabel=\"Duration [hours]\", ylabel=\"n\", bins=12\n", + ")" ] }, { @@ -835,7 +975,8 @@ "1. [Soccer game](soccer-game.ipynb)\n", "1. [Mars rover & heli](mars-rover.ipynb)\n", "1. [Ever Given](ever-given.ipynb)\n", - "1. [Iceberg](iceberg.ipynb) " + "1. [Iceberg](iceberg.ipynb)\n", + "1. [Pollution data](pollution-data.ipynb)" ] } ], diff --git a/2-analysis-examples/iceberg.ipynb b/2-analysis-examples/iceberg.ipynb index 91d57af..eaed201 100644 --- a/2-analysis-examples/iceberg.ipynb +++ b/2-analysis-examples/iceberg.ipynb @@ -106,7 +106,8 @@ "import movingpandas as mpd\n", "import zipfile\n", "import warnings\n", - "warnings.filterwarnings('ignore')" + "\n", + "warnings.filterwarnings(\"ignore\")" ] }, { @@ -115,9 +116,9 @@ "metadata": {}, "outputs": [], "source": [ - "zf = zipfile.ZipFile('../data/icebergs_v5.zip') \n", - "df = pd.read_csv(zf.open('consol/uk319.csv'))\n", - "df['t'] = pd.to_datetime(df.date, format='%Y%j')\n", + "zf = zipfile.ZipFile(\"../data/icebergs_v5.zip\")\n", + "df = pd.read_csv(zf.open(\"consol/uk319.csv\"))\n", + "df[\"t\"] = pd.to_datetime(df.date, format=\"%Y%j\")\n", "df" ] }, @@ -127,9 +128,14 @@ "metadata": {}, "outputs": [], "source": [ - "traj = mpd.Trajectory(df, traj_id=1, t='t', x='ascat_2', y='ascat_1')\n", - "traj.hvplot(title='Iceberg trajectory', c='ascat_3', line_width=5, \n", - " cmap=['yellow','blue'], colorbar=True)" + "traj = mpd.Trajectory(df, traj_id=1, t=\"t\", x=\"ascat_2\", y=\"ascat_1\")\n", + "traj.hvplot(\n", + " title=\"Iceberg trajectory\",\n", + " c=\"ascat_3\",\n", + " line_width=5,\n", + " cmap=[\"yellow\", \"blue\"],\n", + " colorbar=True,\n", + ")" ] }, { @@ -162,9 +168,9 @@ }, "outputs": [], "source": [ - "( \n", - " gf.coastline * \n", - " traj.hvplot(title='Iceberg trajectory in SouthPolarStereo', tiles=None)\n", + "(\n", + " gf.coastline\n", + " * traj.hvplot(title=\"Iceberg trajectory in SouthPolarStereo\", tiles=None)\n", ").opts(projection=crs.SouthPolarStereo())" ] }, @@ -183,7 +189,8 @@ "1. [Soccer game](soccer-game.ipynb)\n", "1. [Mars rover & heli](mars-rover.ipynb)\n", "1. [Ever Given](ever-given.ipynb)\n", - "1. [Iceberg](iceberg.ipynb) " + "1. [Iceberg](iceberg.ipynb)\n", + "1. [Pollution data](pollution-data.ipynb)" ] } ], diff --git a/2-analysis-examples/mars-rover.ipynb b/2-analysis-examples/mars-rover.ipynb index 7eb25f3..7508f94 100644 --- a/2-analysis-examples/mars-rover.ipynb +++ b/2-analysis-examples/mars-rover.ipynb @@ -39,7 +39,7 @@ "import geopandas as gpd\n", "import movingpandas as mpd\n", "import shapely as shp\n", - "import hvplot.pandas \n", + "import hvplot.pandas\n", "import matplotlib.pyplot as plt\n", "\n", "from geopandas import GeoDataFrame, read_file\n", @@ -50,11 +50,14 @@ "from urllib.request import urlretrieve\n", "\n", "import warnings\n", - "warnings.filterwarnings('ignore')\n", "\n", - "plot_defaults = {'linewidth':5, 'capstyle':'round', 'figsize':(9,3), 'legend':True}\n", - "opts.defaults(opts.Overlay(active_tools=['wheel_zoom'], frame_width=500, frame_height=400))\n", - "hvplot_defaults = {'tiles':None, 'cmap':'Viridis', 'colorbar':True}\n", + "warnings.filterwarnings(\"ignore\")\n", + "\n", + "plot_defaults = {\"linewidth\": 5, \"capstyle\": \"round\", \"figsize\": (9, 3), \"legend\": True}\n", + "opts.defaults(\n", + " opts.Overlay(active_tools=[\"wheel_zoom\"], frame_width=500, frame_height=400)\n", + ")\n", + "hvplot_defaults = {\"tiles\": None, \"cmap\": \"Viridis\", \"colorbar\": True}\n", "\n", "mpd.show_versions()" ] @@ -77,29 +80,35 @@ "outputs": [], "source": [ "def to_timestamp(row):\n", - " start_time = datetime(2021,2,18,0,0,0) # sol 0 \n", - " try: \n", - " sol = row['sol'] # rover\n", + " start_time = datetime(2021, 2, 18, 0, 0, 0) # sol 0\n", + " try:\n", + " sol = row[\"sol\"] # rover\n", " except KeyError:\n", - " sol = row['Sol'] # heli \n", - " td = timedelta(hours=24*sol, minutes=40*sol)\n", + " sol = row[\"Sol\"] # heli\n", + " td = timedelta(hours=24 * sol, minutes=40 * sol)\n", " return start_time + td\n", "\n", + "\n", "def get_df_from_url(url):\n", - " file = url.split('/')[-1]\n", + " file = url.split(\"/\")[-1]\n", " if not exists(file):\n", " urlretrieve(url, file)\n", " gdf = read_file(file)\n", - " gdf['time'] = gdf.apply(to_timestamp, axis=1)\n", - " gdf.set_index('time', inplace=True)\n", + " gdf[\"time\"] = gdf.apply(to_timestamp, axis=1)\n", + " gdf.set_index(\"time\", inplace=True)\n", " return gdf\n", "\n", - "m20_waypoints_json = \"https://mars.nasa.gov/mmgis-maps/M20/Layers/json/M20_waypoints.json\"\n", - "heli_waypoints_json = \"https://mars.nasa.gov/mmgis-maps/M20/Layers/json/m20_heli_waypoints.json\"\n", + "\n", + "m20_waypoints_json = (\n", + " \"https://mars.nasa.gov/mmgis-maps/M20/Layers/json/M20_waypoints.json\"\n", + ")\n", + "heli_waypoints_json = (\n", + " \"https://mars.nasa.gov/mmgis-maps/M20/Layers/json/m20_heli_waypoints.json\"\n", + ")\n", "m20_df = get_df_from_url(m20_waypoints_json)\n", "heli_df = get_df_from_url(heli_waypoints_json)\n", - "print(f'M20 records: {len(m20_df)}')\n", - "print(f'Heli records: {len(heli_df)}')" + "print(f\"M20 records: {len(m20_df)}\")\n", + "print(f\"Heli records: {len(heli_df)}\")" ] }, { @@ -117,7 +126,9 @@ "metadata": {}, "outputs": [], "source": [ - "m20_df.hvplot(title=\"M20 & heli waypoints\", hover_cols=['sol'], **hvplot_defaults) * heli_df.hvplot()" + "m20_df.hvplot(\n", + " title=\"M20 & heli waypoints\", hover_cols=[\"sol\"], **hvplot_defaults\n", + ") * heli_df.hvplot()" ] }, { @@ -126,8 +137,8 @@ "metadata": {}, "outputs": [], "source": [ - "m20_traj = mpd.Trajectory(m20_df, 'm20')\n", - "heli_traj = mpd.Trajectory(heli_df, 'heli')" + "m20_traj = mpd.Trajectory(m20_df, \"m20\")\n", + "heli_traj = mpd.Trajectory(heli_df, \"heli\")" ] }, { @@ -136,8 +147,10 @@ "metadata": {}, "outputs": [], "source": [ - "traj_plot = m20_traj.hvplot(title=\"M20 & heli trajectories\", line_width=3, **hvplot_defaults) * heli_traj.hvplot(line_width=3, color='red', **hvplot_defaults)\n", - "traj_plot " + "traj_plot = m20_traj.hvplot(\n", + " title=\"M20 & heli trajectories\", line_width=3, **hvplot_defaults\n", + ") * heli_traj.hvplot(line_width=3, color=\"red\", **hvplot_defaults)\n", + "traj_plot" ] }, { @@ -146,8 +159,12 @@ "metadata": {}, "outputs": [], "source": [ - "m20_traj.hvplot(title=\"Rover speed (only suitable for relative comparison)\", \n", - " c='speed', line_width=7, **hvplot_defaults) " + "m20_traj.hvplot(\n", + " title=\"Rover speed (only suitable for relative comparison)\",\n", + " c=\"speed\",\n", + " line_width=7,\n", + " **hvplot_defaults\n", + ")" ] }, { @@ -157,8 +174,10 @@ "outputs": [], "source": [ "m20_detector = mpd.TrajectoryStopDetector(m20_traj)\n", - "stop_points = m20_detector.get_stop_points(min_duration=timedelta(seconds=60), max_diameter=100)\n", - "stop_points['duration_days'] = stop_points['duration_s']/(60*60*24)\n", + "stop_points = m20_detector.get_stop_points(\n", + " min_duration=timedelta(seconds=60), max_diameter=100\n", + ")\n", + "stop_points[\"duration_days\"] = stop_points[\"duration_s\"] / (60 * 60 * 24)\n", "stop_points.head()" ] }, @@ -169,8 +188,10 @@ "outputs": [], "source": [ "heli_detector = mpd.TrajectoryStopDetector(heli_traj)\n", - "heli_stop_points = heli_detector.get_stop_points(min_duration=timedelta(seconds=60), max_diameter=100)\n", - "heli_stop_points['duration_days'] = heli_stop_points['duration_s']/(60*60*24)\n", + "heli_stop_points = heli_detector.get_stop_points(\n", + " min_duration=timedelta(seconds=60), max_diameter=100\n", + ")\n", + "heli_stop_points[\"duration_days\"] = heli_stop_points[\"duration_s\"] / (60 * 60 * 24)\n", "heli_stop_points.head()" ] }, @@ -180,11 +201,21 @@ "metadata": {}, "outputs": [], "source": [ - "stop_point_plot = stop_points.hvplot(title='M20 & heli stops ', \n", - " geo=True, size=np.log(dim('duration_days'))*10, \n", - " hover_cols=['duration_days'], color='blue', alpha=0.5) \n", - "heli_stop_plot = heli_stop_points.hvplot(geo=True, size=np.log(dim('duration_days'))*10, \n", - " hover_cols=['duration_days'], color='red', alpha=0.5) \n", + "stop_point_plot = stop_points.hvplot(\n", + " title=\"M20 & heli stops \",\n", + " geo=True,\n", + " size=np.log(dim(\"duration_days\")) * 10,\n", + " hover_cols=[\"duration_days\"],\n", + " color=\"blue\",\n", + " alpha=0.5,\n", + ")\n", + "heli_stop_plot = heli_stop_points.hvplot(\n", + " geo=True,\n", + " size=np.log(dim(\"duration_days\")) * 10,\n", + " hover_cols=[\"duration_days\"],\n", + " color=\"red\",\n", + " alpha=0.5,\n", + ")\n", "stop_point_plot * heli_stop_plot * traj_plot" ] }, @@ -205,12 +236,16 @@ "source": [ "from bokeh.models import TMSTileSource\n", "\n", - "tile_url = 'http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/celestia_mars-shaded-16k_global/{Z}/{X}/{Y}.png'\n", + "tile_url = \"http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/celestia_mars-shaded-16k_global/{Z}/{X}/{Y}.png\"\n", + "\n", "\n", "def mars_tiles(plot, element):\n", - " plot.state.add_tile(TMSTileSource(url=tile_url), level='underlay')\n", + " plot.state.add_tile(TMSTileSource(url=tile_url), level=\"underlay\")\n", + "\n", "\n", - "traj_map = m20_traj.hvplot(title=\"M20 & heli trajectories\", tiles=None) * heli_traj.hvplot(color='red', **hvplot_defaults)\n", + "traj_map = m20_traj.hvplot(\n", + " title=\"M20 & heli trajectories\", tiles=None\n", + ") * heli_traj.hvplot(color=\"red\", **hvplot_defaults)\n", "traj_map.opts(hooks=[mars_tiles])" ] }, @@ -230,10 +265,13 @@ "from geoviews.element import WMTS\n", "\n", "MarsImagery = WMTS(\n", - " 'https://trek.nasa.gov/tiles/Mars/EQ/Mars_MGS_MOLA_ClrShade_merge_global_463m/1.0.0/default/default028mm/{Z}/{Y}/{X}.jpg',\n", - " name=\"Mars\")\n", + " \"https://trek.nasa.gov/tiles/Mars/EQ/Mars_MGS_MOLA_ClrShade_merge_global_463m/1.0.0/default/default028mm/{Z}/{Y}/{X}.jpg\",\n", + " name=\"Mars\",\n", + ")\n", "\n", - "m20_traj.hvplot(title=\"M20 & heli trajectories\", tiles=MarsImagery) * heli_traj.hvplot(color='red', **hvplot_defaults)\n" + "m20_traj.hvplot(title=\"M20 & heli trajectories\", tiles=MarsImagery) * heli_traj.hvplot(\n", + " color=\"red\", **hvplot_defaults\n", + ")" ] }, { @@ -251,7 +289,8 @@ "1. [Soccer game](soccer-game.ipynb)\n", "1. [Mars rover & heli](mars-rover.ipynb)\n", "1. [Ever Given](ever-given.ipynb)\n", - "1. [Iceberg](iceberg.ipynb)" + "1. [Iceberg](iceberg.ipynb)\n", + "1. [Pollution data](pollution-data.ipynb)" ] } ], diff --git a/2-analysis-examples/osm-traces.ipynb b/2-analysis-examples/osm-traces.ipynb index a829ee6..46c9c0f 100644 --- a/2-analysis-examples/osm-traces.ipynb +++ b/2-analysis-examples/osm-traces.ipynb @@ -26,7 +26,7 @@ "import geopandas as gpd\n", "import movingpandas as mpd\n", "import shapely as shp\n", - "import hvplot.pandas \n", + "import hvplot.pandas\n", "import matplotlib.pyplot as plt\n", "\n", "from geopandas import GeoDataFrame, read_file\n", @@ -37,11 +37,14 @@ "from urllib.request import urlretrieve\n", "\n", "import warnings\n", - "warnings.filterwarnings('ignore')\n", "\n", - "plot_defaults = {'linewidth':5, 'capstyle':'round', 'figsize':(9,3), 'legend':True}\n", - "opts.defaults(opts.Overlay(active_tools=['wheel_zoom'], frame_width=500, frame_height=400))\n", - "hvplot_defaults = {'tiles':None, 'cmap':'Viridis', 'colorbar':True}\n", + "warnings.filterwarnings(\"ignore\")\n", + "\n", + "plot_defaults = {\"linewidth\": 5, \"capstyle\": \"round\", \"figsize\": (9, 3), \"legend\": True}\n", + "opts.defaults(\n", + " opts.Overlay(active_tools=[\"wheel_zoom\"], frame_width=500, frame_height=400)\n", + ")\n", + "hvplot_defaults = {\"tiles\": None, \"cmap\": \"Viridis\", \"colorbar\": True}\n", "\n", "mpd.show_versions()" ] @@ -59,16 +62,38 @@ "metadata": {}, "outputs": [], "source": [ - "def get_osm_traces(page=0, bbox='16.18,48.09,16.61,48.32'):\n", - " file = 'osm_traces.gpx'\n", - " url = f'https://api.openstreetmap.org/api/0.6/trackpoints?bbox={bbox}&page={page}'\n", + "def get_osm_traces(page=0, bbox=\"16.18,48.09,16.61,48.32\"):\n", + " file = \"osm_traces.gpx\"\n", + " url = f\"https://api.openstreetmap.org/api/0.6/trackpoints?bbox={bbox}&page={page}\"\n", " if not exists(file):\n", " urlretrieve(url, file)\n", - " gdf = gpd.read_file(file, layer='track_points')\n", + " gdf = gpd.read_file(file, layer=\"track_points\")\n", " # OPTIONAL: dropping empty columns\n", - " gdf.drop(columns=['ele', 'course', 'speed', 'magvar', 'geoidheight', 'name', 'cmt', 'desc',\n", - " 'src', 'url', 'urlname', 'sym', 'type', 'fix', 'sat', 'hdop', 'vdop',\n", - " 'pdop', 'ageofdgpsdata', 'dgpsid'], inplace=True) \n", + " gdf.drop(\n", + " columns=[\n", + " \"ele\",\n", + " \"course\",\n", + " \"speed\",\n", + " \"magvar\",\n", + " \"geoidheight\",\n", + " \"name\",\n", + " \"cmt\",\n", + " \"desc\",\n", + " \"src\",\n", + " \"url\",\n", + " \"urlname\",\n", + " \"sym\",\n", + " \"type\",\n", + " \"fix\",\n", + " \"sat\",\n", + " \"hdop\",\n", + " \"vdop\",\n", + " \"pdop\",\n", + " \"ageofdgpsdata\",\n", + " \"dgpsid\",\n", + " ],\n", + " inplace=True,\n", + " )\n", " return gdf" ] }, @@ -86,8 +111,8 @@ "outputs": [], "source": [ "gdf = get_osm_traces()\n", - "osm_traces = mpd.TrajectoryCollection(gdf, 'track_fid', t='time')\n", - "print(f'The OSM traces download contains {len(osm_traces)} tracks')" + "osm_traces = mpd.TrajectoryCollection(gdf, \"track_fid\", t=\"time\")\n", + "print(f\"The OSM traces download contains {len(osm_traces)} tracks\")" ] }, { @@ -96,7 +121,8 @@ "metadata": {}, "outputs": [], "source": [ - "for track in osm_traces: print(f'Track {track.id}: length={track.get_length(units=\"km\"):.2f} km')" + "for track in osm_traces:\n", + " print(f'Track {track.id}: length={track.get_length(units=\"km\"):.2f} km')" ] }, { @@ -123,8 +149,10 @@ "metadata": {}, "outputs": [], "source": [ - "osm_traces = mpd.MinTimeDeltaGeneralizer(osm_traces).generalize(tolerance=timedelta(minutes=1))\n", - "osm_traces.hvplot(title='OSM Traces', line_width=7, width=700, height=400)" + "osm_traces = mpd.MinTimeDeltaGeneralizer(osm_traces).generalize(\n", + " tolerance=timedelta(minutes=1)\n", + ")\n", + "osm_traces.hvplot(title=\"OSM Traces\", line_width=7, width=700, height=400)" ] }, { @@ -133,10 +161,17 @@ "metadata": {}, "outputs": [], "source": [ - "osm_traces.trajectories[0].add_speed(overwrite=True, units=(\"km\",\"h\"))\n", + "osm_traces.trajectories[0].add_speed(overwrite=True, units=(\"km\", \"h\"))\n", "osm_traces.trajectories[0].hvplot(\n", - " title='Speed (km/h) along track', c='speed', cmap='RdYlBu',\n", - " line_width=7, width=700, height=400, tiles='CartoLight', colorbar=True)" + " title=\"Speed (km/h) along track\",\n", + " c=\"speed\",\n", + " cmap=\"RdYlBu\",\n", + " line_width=7,\n", + " width=700,\n", + " height=400,\n", + " tiles=\"CartoLight\",\n", + " colorbar=True,\n", + ")" ] }, { @@ -152,7 +187,8 @@ "1. [Soccer game](soccer-game.ipynb)\n", "1. [Mars rover & heli](mars-rover.ipynb)\n", "1. [Ever Given](ever-given.ipynb)\n", - "1. [Iceberg](iceberg.ipynb)" + "1. [Iceberg](iceberg.ipynb)\n", + "1. [Pollution data](pollution-data.ipynb)" ] } ], diff --git a/2-analysis-examples/pollution-data.ipynb b/2-analysis-examples/pollution-data.ipynb new file mode 100644 index 0000000..257df20 --- /dev/null +++ b/2-analysis-examples/pollution-data.ipynb @@ -0,0 +1,502 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Pollution data analysis example\n", + "\n", + "\n", + "\n", + "This tutorial uses data published by the Department of Computer Science and Engineering, Indian Institute of Technology Delhi, specifically: [Delhi Pollution Dataset](http://cse.iitd.ac.in/pollutiondata/delhi). The workflow consists of the following steps:\n", + "\n", + "1. Establishing an overview by visualizing raw input data records\n", + "2. Converting data into trajectories\n", + "3. Removing problematic trajectories using ObservationGapSplitter and filtering by speed\n", + "4. Plotting cleaned trajectories\n", + "5. Assigning H3 cell IDs to each trajectory point\n", + "6. Plotting H3 cells as polygons with pollution measurements\n", + "\n", + "Some of the steps working with H3 are based on the following: [Medium article](https://medium.com/@jesse.b.nestler/how-to-convert-h3-cell-boundaries-to-shapely-polygons-in-python-f7558add2f63)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import geopandas as gpd\n", + "import movingpandas as mpd\n", + "import shapely as shp\n", + "import hvplot.pandas\n", + "import matplotlib.pyplot as plt\n", + "import h3\n", + "import folium\n", + "\n", + "from geopandas import GeoDataFrame, read_file\n", + "from shapely.geometry import Point, LineString, Polygon\n", + "from datetime import datetime, timedelta\n", + "from holoviews import opts, dim\n", + "from os.path import exists\n", + "from urllib.request import urlretrieve\n", + "\n", + "import warnings\n", + "\n", + "warnings.filterwarnings(\"ignore\")\n", + "\n", + "plot_defaults = {\"linewidth\": 5, \"capstyle\": \"round\", \"figsize\": (9, 3), \"legend\": True}\n", + "opts.defaults(\n", + " opts.Overlay(active_tools=[\"wheel_zoom\"], frame_width=300, frame_height=500)\n", + ")\n", + "hvplot_defaults = {\"tiles\": None, \"cmap\": \"Viridis\", \"colorbar\": True}\n", + "\n", + "mpd.show_versions()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Loading pollution data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%time\n", + "df = pd.read_csv(\"../data/2021-01-30_all.zip\", index_col=0)\n", + "print(f\"Finished reading {len(df)}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's see what the data looks like:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df.plot(c=\"pm2_5\", x=\"long\", y=\"lat\", kind=\"scatter\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's create trajectories:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tc = mpd.TrajectoryCollection(df, \"deviceId\", t=\"dateTime\", x=\"long\", y=\"lat\")\n", + "print(tc)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Removing problematic trajectories" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We use Particulate Matter (PM) as an indicator for air pollution:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "traj_gdf = tc.to_traj_gdf(agg={\"pm2_5\": \"mean\"})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "traj_gdf.plot(\"pm2_5_mean\", cmap=\"YlOrRd\", linewidth=0.7, legend=True, aspect=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's remove problematic trajectories as much as we can:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "split = mpd.ObservationGapSplitter(tc).split(gap=timedelta(minutes=10))\n", + "split" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "split = split.add_speed(units=(\"km\", \"h\"))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "traj_gdf = split.to_traj_gdf(agg={\"pm2_5\": \"mean\", \"speed\": \"max\"})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Anything over a speed of 108km/h or 30m/s seems unlikely for a bus, so let's filter these points out:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "traj_gdf = traj_gdf[traj_gdf.speed_max < 108]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plotting trajectories" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's plot the resulting trajectories:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "traj_gdf[\"start_t\"] = traj_gdf[\"start_t\"].astype(str)\n", + "traj_gdf[\"end_t\"] = traj_gdf[\"end_t\"].astype(str)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "traj_gdf = traj_gdf.round(2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "traj_gdf.explore(\n", + " \"pm2_5_mean\",\n", + " tiles=\"CartoDB positron\",\n", + " cmap=\"YlOrRd\",\n", + " linewidth=0.7,\n", + " legend=True,\n", + " aspect=1,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Assigning H3 cell IDs to trajectory points" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's again filter by realistic speed:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "point_gdf = split.to_point_gdf()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "point_gdf = point_gdf[point_gdf.speed < 30]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "point_gdf[\"x\"] = point_gdf.geometry.x\n", + "point_gdf[\"y\"] = point_gdf.geometry.y" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can assign H3 cell IDs to each point in a trajectory:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "res = 7\n", + "point_gdf[\"h3_cell\"] = point_gdf.apply(\n", + " lambda r: str(h3.geo_to_h3(r.y, r.x, res)), axis=1\n", + ")\n", + "point_gdf.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can use the mean of PM2.5 as a pollution measurement:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "h3_df_mean = point_gdf.groupby([\"h3_cell\"])[\"pm2_5\"].mean().round(0).reset_index()\n", + "h3_df_mean = h3_df_mean.rename(columns={\"pm2_5\": \"pm2_5_mean\"})\n", + "h3_df_mean.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also use the maximum of PM2.5 as a pollution measurement:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "h3_df_max = point_gdf.groupby([\"h3_cell\"])[\"pm2_5\"].max().reset_index()\n", + "h3_df_max = h3_df_max.rename(columns={\"pm2_5\": \"pm2_5_max\"})\n", + "h3_df_max.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualizing pollution measurements" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's create polygons with pollution data:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def cell_to_shapely(cell):\n", + " coords = h3.h3_to_geo_boundary(cell)\n", + " flipped = tuple(coord[::-1] for coord in coords)\n", + " return Polygon(flipped)\n", + "\n", + "\n", + "h3_geoms_mean = h3_df_mean[\"h3_cell\"].apply(lambda x: cell_to_shapely(x))\n", + "h3_gdf_mean = gpd.GeoDataFrame(data=h3_df_mean, geometry=h3_geoms_mean, crs=4326)\n", + "\n", + "h3_geoms_max = h3_df_max[\"h3_cell\"].apply(lambda x: cell_to_shapely(x))\n", + "h3_gdf_max = gpd.GeoDataFrame(data=h3_df_max, geometry=h3_geoms_max, crs=4326)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's plot the results for mean pollution data:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "h3_gdf_mean.explore(\"pm2_5_mean\", cmap=\"YlOrRd\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can plot polygons and trajectories together:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "map = h3_gdf_mean.explore(\"pm2_5_mean\", cmap=\"YlOrRd\", name=\"PM2.5 mean\")\n", + "\n", + "traj_gdf.explore(m=map, name=\"Bus trajectories\")\n", + "\n", + "folium.TileLayer(\"Cartodb Positron\").add_to(map)\n", + "\n", + "folium.LayerControl().add_to(map)\n", + "\n", + "map" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Lastly, let's plot mean and maximum values next to each other for comparison:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "h3_gdf_max = h3_gdf_max.rename(columns={\"geometry\": \"geometry1\"})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pollution = pd.concat([h3_gdf_mean, h3_gdf_max], axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "(\n", + " pollution.hvplot.polygons(\n", + " geo=True, tiles=\"OSM\", c=\"pm2_5_mean\", alpha=0.8, title=\"Mean pollution data\"\n", + " )\n", + " + pollution.hvplot.polygons(\n", + " geo=True, tiles=\"OSM\", c=\"pm2_5_max\", alpha=0.8, title=\"Maximum pollution data\"\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Continue exploring MovingPandas\n", + "\n", + "1. [Bird migration analysis](bird-migration.ipynb)\n", + "1. [Ship data analysis](ship-data.ipynb)\n", + "1. [Horse collar data exploration](horse-collar.ipynb)\n", + "1. [OSM traces](osm-traces.ipynb)\n", + "1. [Soccer game](soccer-game.ipynb)\n", + "1. [Mars rover & heli](mars-rover.ipynb)\n", + "1. [Ever Given](ever-given.ipynb)\n", + "1. [Iceberg](iceberg.ipynb) \n", + "1. [Pollution data](pollution-data.ipynb)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "movingpandas", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/2-analysis-examples/ship-data.ipynb b/2-analysis-examples/ship-data.ipynb index fa9ba89..8c8703e 100644 --- a/2-analysis-examples/ship-data.ipynb +++ b/2-analysis-examples/ship-data.ipynb @@ -40,7 +40,7 @@ "import geopandas as gpd\n", "import movingpandas as mpd\n", "import shapely as shp\n", - "import hvplot.pandas \n", + "import hvplot.pandas\n", "import matplotlib.pyplot as plt\n", "\n", "from geopandas import GeoDataFrame, read_file\n", @@ -51,11 +51,14 @@ "from urllib.request import urlretrieve\n", "\n", "import warnings\n", - "warnings.filterwarnings('ignore')\n", "\n", - "plot_defaults = {'linewidth':5, 'capstyle':'round', 'figsize':(9,3), 'legend':True}\n", - "opts.defaults(opts.Overlay(active_tools=['wheel_zoom'], frame_width=500, frame_height=400))\n", - "hvplot_defaults = {'tiles':None, 'cmap':'Viridis', 'colorbar':True}\n", + "warnings.filterwarnings(\"ignore\")\n", + "\n", + "plot_defaults = {\"linewidth\": 5, \"capstyle\": \"round\", \"figsize\": (9, 3), \"legend\": True}\n", + "opts.defaults(\n", + " opts.Overlay(active_tools=[\"wheel_zoom\"], frame_width=500, frame_height=400)\n", + ")\n", + "hvplot_defaults = {\"tiles\": None, \"cmap\": \"Viridis\", \"colorbar\": True}\n", "\n", "mpd.show_versions()" ] @@ -74,7 +77,7 @@ "outputs": [], "source": [ "%%time\n", - "df = read_file('../data/ais.gpkg')\n", + "df = read_file(\"../data/ais.gpkg\")\n", "print(f\"Finished reading {len(df)}\")" ] }, @@ -116,7 +119,7 @@ "metadata": {}, "outputs": [], "source": [ - "df['SOG'].hist(bins=100, figsize=(15,3))" + "df[\"SOG\"].hist(bins=100, figsize=(15, 3))" ] }, { @@ -133,9 +136,9 @@ "outputs": [], "source": [ "print(f\"Original size: {len(df)} rows\")\n", - "df = df[df.SOG>0]\n", + "df = df[df.SOG > 0]\n", "print(f\"Reduced to {len(df)} rows after removing 0 speed records\")\n", - "df['SOG'].hist(bins=100, figsize=(15,3))" + "df[\"SOG\"].hist(bins=100, figsize=(15, 3))" ] }, { @@ -151,7 +154,7 @@ "metadata": {}, "outputs": [], "source": [ - "df['ShipType'].value_counts().plot(kind='bar', figsize=(15,3))" + "df[\"ShipType\"].value_counts().plot(kind=\"bar\", figsize=(15, 3))" ] }, { @@ -168,8 +171,8 @@ "outputs": [], "source": [ "%%time\n", - "df['t'] = pd.to_datetime(df['Timestamp'], format='%d/%m/%Y %H:%M:%S')\n", - "traj_collection = mpd.TrajectoryCollection(df, 'MMSI', t='t', min_length=100)\n", + "df[\"t\"] = pd.to_datetime(df[\"Timestamp\"], format=\"%d/%m/%Y %H:%M:%S\")\n", + "traj_collection = mpd.TrajectoryCollection(df, \"MMSI\", t=\"t\", min_length=100)\n", "print(f\"Finished creating {len(traj_collection)} trajectories\")" ] }, @@ -179,7 +182,9 @@ "metadata": {}, "outputs": [], "source": [ - "traj_collection = mpd.MinTimeDeltaGeneralizer(traj_collection).generalize(tolerance=timedelta(minutes=1))" + "traj_collection = mpd.MinTimeDeltaGeneralizer(traj_collection).generalize(\n", + " tolerance=timedelta(minutes=1)\n", + ")" ] }, { @@ -197,10 +202,27 @@ "metadata": {}, "outputs": [], "source": [ - "shiptype_to_color = {'Passenger': 'blue', 'HSC': 'green', 'Tanker': 'red', 'Cargo': 'orange', 'Sailing': 'grey', 'Other': 'grey', \n", - " 'Tug': 'grey', 'SAR': 'grey', 'Undefined': 'grey', 'Pleasure': 'grey', 'Dredging': 'grey', 'Law enforcement': 'grey',\n", - " 'Pilot': 'grey', 'Fishing': 'grey', 'Diving':'grey', 'Spare 2': 'grey'}\n", - "traj_collection.plot(column='ShipType', column_to_color=shiptype_to_color, linewidth=1, capstyle='round')" + "shiptype_to_color = {\n", + " \"Passenger\": \"blue\",\n", + " \"HSC\": \"green\",\n", + " \"Tanker\": \"red\",\n", + " \"Cargo\": \"orange\",\n", + " \"Sailing\": \"grey\",\n", + " \"Other\": \"grey\",\n", + " \"Tug\": \"grey\",\n", + " \"SAR\": \"grey\",\n", + " \"Undefined\": \"grey\",\n", + " \"Pleasure\": \"grey\",\n", + " \"Dredging\": \"grey\",\n", + " \"Law enforcement\": \"grey\",\n", + " \"Pilot\": \"grey\",\n", + " \"Fishing\": \"grey\",\n", + " \"Diving\": \"grey\",\n", + " \"Spare 2\": \"grey\",\n", + "}\n", + "traj_collection.plot(\n", + " column=\"ShipType\", column_to_color=shiptype_to_color, linewidth=1, capstyle=\"round\"\n", + ")" ] }, { @@ -209,8 +231,10 @@ "metadata": {}, "outputs": [], "source": [ - "passenger = traj_collection.filter('ShipType', 'Passenger')\n", - "passenger.hvplot(title='Passenger ferries', line_width=2, frame_width=700, frame_height=500)" + "passenger = traj_collection.filter(\"ShipType\", \"Passenger\")\n", + "passenger.hvplot(\n", + " title=\"Passenger ferries\", line_width=2, frame_width=700, frame_height=500\n", + ")" ] }, { @@ -252,7 +276,14 @@ "metadata": {}, "outputs": [], "source": [ - "my_traj.hvplot(title=f'Trajectory {my_traj.id}', frame_width=700, frame_height=500, line_width=5.0, c='NavStatus', cmap='Dark2') " + "my_traj.hvplot(\n", + " title=f\"Trajectory {my_traj.id}\",\n", + " frame_width=700,\n", + " frame_height=500,\n", + " line_width=5.0,\n", + " c=\"NavStatus\",\n", + " cmap=\"Dark2\",\n", + ")" ] }, { @@ -269,7 +300,15 @@ "metadata": {}, "outputs": [], "source": [ - "area_of_interest = Polygon([(11.89935, 57.69270), (11.90161, 57.68902), (11.90334, 57.68967), (11.90104, 57.69354), (11.89935, 57.69270)])" + "area_of_interest = Polygon(\n", + " [\n", + " (11.89935, 57.69270),\n", + " (11.90161, 57.68902),\n", + " (11.90334, 57.68967),\n", + " (11.90104, 57.69354),\n", + " (11.89935, 57.69270),\n", + " ]\n", + ")" ] }, { @@ -289,7 +328,14 @@ "outputs": [], "source": [ "bridge_traj = intersecting.trajectories[0]\n", - "bridge_traj.hvplot(title=f'Trajectory {bridge_traj.id}', frame_width=700, frame_height=500, line_width=5.0, c='NavStatus', cmap='Dark2') " + "bridge_traj.hvplot(\n", + " title=f\"Trajectory {bridge_traj.id}\",\n", + " frame_width=700,\n", + " frame_height=500,\n", + " line_width=5.0,\n", + " c=\"NavStatus\",\n", + " cmap=\"Dark2\",\n", + ")" ] }, { @@ -322,7 +368,9 @@ "outputs": [], "source": [ "trips = mpd.ObservationGapSplitter(passenger).split(gap=timedelta(minutes=5))\n", - "print(f\"Extracted {len(trips)} individual trips from {len(passenger)} continuous vessel tracks\")" + "print(\n", + " f\"Extracted {len(trips)} individual trips from {len(passenger)} continuous vessel tracks\"\n", + ")" ] }, { @@ -338,7 +386,9 @@ "metadata": {}, "outputs": [], "source": [ - "trips.hvplot(title='Passenger ferry trips', line_width=2, frame_width=700, frame_height=500)" + "trips.hvplot(\n", + " title=\"Passenger ferry trips\", line_width=2, frame_width=700, frame_height=500\n", + ")" ] }, { @@ -362,7 +412,14 @@ "outputs": [], "source": [ "origins = trips.get_start_locations()\n", - "origins.hvplot(title='Trip origins by ship type', c='Name', geo=True, tiles='OSM', frame_width=700, frame_height=500)" + "origins.hvplot(\n", + " title=\"Trip origins by ship type\",\n", + " c=\"Name\",\n", + " geo=True,\n", + " tiles=\"OSM\",\n", + " frame_width=700,\n", + " frame_height=500,\n", + ")" ] }, { @@ -380,7 +437,14 @@ "metadata": {}, "outputs": [], "source": [ - "origins.hvplot(title='Origins by speed', c='SOG', geo=True, tiles='OSM', frame_width=700, frame_height=500)" + "origins.hvplot(\n", + " title=\"Origins by speed\",\n", + " c=\"SOG\",\n", + " geo=True,\n", + " tiles=\"OSM\",\n", + " frame_width=700,\n", + " frame_height=500,\n", + ")" ] }, { @@ -397,7 +461,15 @@ "outputs": [], "source": [ "trips = mpd.ObservationGapSplitter(traj_collection).split(gap=timedelta(minutes=5))\n", - "area_of_interest = Polygon([(11.86815, 57.68273), (11.86992, 57.68047), (11.87419, 57.68140), (11.87288, 57.68348), (11.86815, 57.68273)])" + "area_of_interest = Polygon(\n", + " [\n", + " (11.86815, 57.68273),\n", + " (11.86992, 57.68047),\n", + " (11.87419, 57.68140),\n", + " (11.87288, 57.68348),\n", + " (11.86815, 57.68273),\n", + " ]\n", + ")" ] }, { @@ -413,7 +485,12 @@ "metadata": {}, "outputs": [], "source": [ - "departures = [traj for traj in trips if traj.get_start_location().intersects(area_of_interest) and traj.get_length() > 100] \n", + "departures = [\n", + " traj\n", + " for traj in trips\n", + " if traj.get_start_location().intersects(area_of_interest)\n", + " and traj.get_length() > 100\n", + "]\n", "print(f\"Found {len(departures)} departures\")" ] }, @@ -424,7 +501,13 @@ "outputs": [], "source": [ "tc = mpd.TrajectoryCollection(departures)\n", - "tc.hvplot(title=f'Ships departing from Sjöfartsverket', line_width=3, frame_width=700, frame_height=500, hover_cols=['Name']) " + "tc.hvplot(\n", + " title=f\"Ships departing from Sjöfartsverket\",\n", + " line_width=3,\n", + " frame_width=700,\n", + " frame_height=500,\n", + " hover_cols=[\"Name\"],\n", + ")" ] }, { @@ -441,7 +524,9 @@ "outputs": [], "source": [ "for traj in departures:\n", - " print(f\"{traj.df['ShipType'].iloc[0]} vessel '{traj.df['Name'].iloc[0]}' departed at {traj.get_start_time()}\")" + " print(\n", + " f\"{traj.df['ShipType'].iloc[0]} vessel '{traj.df['Name'].iloc[0]}' departed at {traj.get_start_time()}\"\n", + " )" ] }, { @@ -457,11 +542,17 @@ "metadata": {}, "outputs": [], "source": [ - "arrivals = [traj for traj in trips if traj.get_end_location().intersects(area_of_interest) and traj.get_length() > 100]\n", + "arrivals = [\n", + " traj\n", + " for traj in trips\n", + " if traj.get_end_location().intersects(area_of_interest) and traj.get_length() > 100\n", + "]\n", "print(f\"Found {len(arrivals)} arrivals\")\n", "\n", "for traj in arrivals:\n", - " print(f\"{traj.df['ShipType'].iloc[0]} vessel '{traj.df['Name'].iloc[0]}' arrived at {traj.get_end_time()}\")" + " print(\n", + " f\"{traj.df['ShipType'].iloc[0]} vessel '{traj.df['Name'].iloc[0]}' arrived at {traj.get_end_time()}\"\n", + " )" ] }, { @@ -471,7 +562,13 @@ "outputs": [], "source": [ "tc = mpd.TrajectoryCollection(arrivals)\n", - "tc.hvplot(title=f'Ships arriving in Sjöfartsverket', line_width=3, frame_width=700, frame_height=500, hover_cols=['Name']) " + "tc.hvplot(\n", + " title=f\"Ships arriving in Sjöfartsverket\",\n", + " line_width=3,\n", + " frame_width=700,\n", + " frame_height=500,\n", + " hover_cols=[\"Name\"],\n", + ")" ] }, { @@ -501,9 +598,9 @@ "outputs": [], "source": [ "origins = trips.get_start_locations()\n", - "origins['lat'] = origins.geometry.y\n", - "origins['lon'] = origins.geometry.x\n", - "matrix = origins[['lat','lon']].values" + "origins[\"lat\"] = origins.geometry.y\n", + "origins[\"lon\"] = origins.geometry.x\n", + "matrix = origins[[\"lat\", \"lon\"]].values" ] }, { @@ -522,11 +619,13 @@ "metadata": {}, "outputs": [], "source": [ - "db = DBSCAN(eps=epsilon, min_samples=1, algorithm='ball_tree', metric='haversine').fit(np.radians(matrix))\n", + "db = DBSCAN(eps=epsilon, min_samples=1, algorithm=\"ball_tree\", metric=\"haversine\").fit(\n", + " np.radians(matrix)\n", + ")\n", "cluster_labels = db.labels_\n", "num_clusters = len(set(cluster_labels))\n", "clusters = pd.Series([matrix[cluster_labels == n] for n in range(num_clusters)])\n", - "print(f'Number of clusters: {num_clusters}')" + "print(f\"Number of clusters: {num_clusters}\")" ] }, { @@ -535,7 +634,7 @@ "metadata": {}, "outputs": [], "source": [ - "origins['cluster'] = cluster_labels" + "origins[\"cluster\"] = cluster_labels" ] }, { @@ -548,6 +647,8 @@ " centroid = (MultiPoint(cluster).centroid.x, MultiPoint(cluster).centroid.y)\n", " centermost_point = min(cluster, key=lambda point: great_circle(point, centroid).m)\n", " return Point(tuple(centermost_point)[1], tuple(centermost_point)[0])\n", + "\n", + "\n", "centermost_points = clusters.map(get_centermost_point)" ] }, @@ -557,7 +658,15 @@ "metadata": {}, "outputs": [], "source": [ - "origins.hvplot(title='Clustered origins', c='cluster', geo=True, tiles='OSM', cmap='glasbey_dark', frame_width=700, frame_height=500)" + "origins.hvplot(\n", + " title=\"Clustered origins\",\n", + " c=\"cluster\",\n", + " geo=True,\n", + " tiles=\"OSM\",\n", + " cmap=\"glasbey_dark\",\n", + " frame_width=700,\n", + " frame_height=500,\n", + ")" ] }, { @@ -566,12 +675,12 @@ "metadata": {}, "outputs": [], "source": [ - "origins_by_cluster = pd.DataFrame(origins).groupby(['cluster'])\n", - "summary = origins_by_cluster['ShipType'].unique().to_frame(name='types')\n", - "summary['n'] = origins_by_cluster.size()\n", - "summary['sog'] = origins_by_cluster['SOG'].mean()\n", - "summary['geometry'] = centermost_points\n", - "summary = summary[summary['n']>1].sort_values(by='n', ascending=False)\n", + "origins_by_cluster = pd.DataFrame(origins).groupby([\"cluster\"])\n", + "summary = origins_by_cluster[\"ShipType\"].unique().to_frame(name=\"types\")\n", + "summary[\"n\"] = origins_by_cluster.size()\n", + "summary[\"sog\"] = origins_by_cluster[\"SOG\"].mean()\n", + "summary[\"geometry\"] = centermost_points\n", + "summary = summary[summary[\"n\"] > 1].sort_values(by=\"n\", ascending=False)\n", "summary.head()" ] }, @@ -582,8 +691,14 @@ "outputs": [], "source": [ "cluster_of_interest_id = 28\n", - "origins[origins['cluster']==cluster_of_interest_id].hvplot(\n", - " title=f'Cluster {cluster_of_interest_id}', c='ShipType', geo=True, tiles='OSM', frame_width=700, frame_height=500)" + "origins[origins[\"cluster\"] == cluster_of_interest_id].hvplot(\n", + " title=f\"Cluster {cluster_of_interest_id}\",\n", + " c=\"ShipType\",\n", + " geo=True,\n", + " tiles=\"OSM\",\n", + " frame_width=700,\n", + " frame_height=500,\n", + ")" ] }, { @@ -592,8 +707,17 @@ "metadata": {}, "outputs": [], "source": [ - "( trips.hvplot(title='Origin clusters by speed', color='gray', line_width=1, frame_width=700, frame_height=500) *\n", - " GeoDataFrame(summary, crs=4326).hvplot(c='sog', size=np.sqrt(dim('n'))*3, geo=True, cmap='RdYlGn')\n", + "(\n", + " trips.hvplot(\n", + " title=\"Origin clusters by speed\",\n", + " color=\"gray\",\n", + " line_width=1,\n", + " frame_width=700,\n", + " frame_height=500,\n", + " )\n", + " * GeoDataFrame(summary, crs=4326).hvplot(\n", + " c=\"sog\", size=np.sqrt(dim(\"n\")) * 3, geo=True, cmap=\"RdYlGn\"\n", + " )\n", ")" ] }, @@ -610,7 +734,8 @@ "1. [Soccer game](soccer-game.ipynb)\n", "1. [Mars rover & heli](mars-rover.ipynb)\n", "1. [Ever Given](ever-given.ipynb)\n", - "1. [Iceberg](iceberg.ipynb)" + "1. [Iceberg](iceberg.ipynb)\n", + "1. [Pollution data](pollution-data.ipynb)" ] } ], diff --git a/2-analysis-examples/soccer-game.ipynb b/2-analysis-examples/soccer-game.ipynb index 3faf093..ad3b6b8 100644 --- a/2-analysis-examples/soccer-game.ipynb +++ b/2-analysis-examples/soccer-game.ipynb @@ -30,7 +30,7 @@ "import movingpandas as mpd\n", "import shapely as shp\n", "import holoviews as hv\n", - "import hvplot.pandas \n", + "import hvplot.pandas\n", "import matplotlib.pyplot as plt\n", "\n", "from geopandas import GeoDataFrame, read_file\n", @@ -41,9 +41,17 @@ "from urllib.request import urlretrieve\n", "\n", "import warnings\n", - "warnings.filterwarnings('ignore')\n", "\n", - "hvplot_defaults = {'line_width':5, 'frame_height':350, 'frame_width':700, 'colorbar':True, 'tiles':None, 'geo':False,}\n", + "warnings.filterwarnings(\"ignore\")\n", + "\n", + "hvplot_defaults = {\n", + " \"line_width\": 5,\n", + " \"frame_height\": 350,\n", + " \"frame_width\": 700,\n", + " \"colorbar\": True,\n", + " \"tiles\": None,\n", + " \"geo\": False,\n", + "}\n", "\n", "mpd.show_versions()" ] @@ -63,10 +71,11 @@ "outputs": [], "source": [ "def get_file_from_url(url):\n", - " file = url.split('/')[-1]\n", + " file = url.split(\"/\")[-1]\n", " if not exists(file):\n", " urlretrieve(url, file)\n", - " return file \n", + " return file\n", + "\n", "\n", "def get_df_from_gh_url(url):\n", " file = get_file_from_url(url)\n", @@ -81,8 +90,8 @@ "source": [ "input_file = \"https://raw.githubusercontent.com/Friends-of-Tracking-Data-FoTD/Last-Row/master/datasets/positional_data/liverpool_2019.csv\"\n", "df = get_df_from_gh_url(input_file)\n", - "df.drop(columns=['Unnamed: 0'], inplace=True)\n", - "print(f'Number of records: {len(df)}')" + "df.drop(columns=[\"Unnamed: 0\"], inplace=True)\n", + "print(f\"Number of records: {len(df)}\")" ] }, { @@ -124,22 +133,24 @@ "source": [ "plays = list(df.play.unique())\n", "\n", + "\n", "def to_timestamp(row):\n", " # plays to date\n", - " day = plays.index(row.play)+1\n", - " start_time = datetime(2019,1,day,12,0,0)\n", + " day = plays.index(row.play) + 1\n", + " start_time = datetime(2019, 1, day, 12, 0, 0)\n", " # frames to time\n", - " td = timedelta(milliseconds=1000/20*row.frame)\n", + " td = timedelta(milliseconds=1000 / 20 * row.frame)\n", " return start_time + td\n", "\n", + "\n", "# frame: the frame number for the current location. Data provided has 20 frames per second\n", - "df['time'] = df.apply(to_timestamp, axis=1)\n", - "df.set_index('time', inplace=True)\n", + "df[\"time\"] = df.apply(to_timestamp, axis=1)\n", + "df.set_index(\"time\", inplace=True)\n", "\n", "# the preferred size for many professional teams' stadiums is 105 by 68 metres, accoring to https://en.wikipedia.org/wiki/Football_pitch\n", "pitch_length = 105\n", "pitch_width = 68\n", - "df.x = df.x / 100 * pitch_length \n", + "df.x = df.x / 100 * pitch_length\n", "df.y = df.y / 100 * pitch_width\n", "\n", "df" @@ -151,7 +162,7 @@ "metadata": {}, "outputs": [], "source": [ - "df['team'].value_counts().plot(title='team', kind='bar', figsize=(15,3))" + "df[\"team\"].value_counts().plot(title=\"team\", kind=\"bar\", figsize=(15, 3))" ] }, { @@ -160,7 +171,7 @@ "metadata": {}, "outputs": [], "source": [ - "df['player_num'].value_counts().plot(title='player_num', kind='bar', figsize=(15,3))" + "df[\"player_num\"].value_counts().plot(title=\"player_num\", kind=\"bar\", figsize=(15, 3))" ] }, { @@ -169,9 +180,9 @@ "metadata": {}, "outputs": [], "source": [ - "df['team'] = df['team'].astype('category').cat.as_ordered()\n", - "df['player'] = df['player'].astype('category').cat.as_ordered()\n", - "df['player_num'] = df['player_num'].astype('category').cat.as_ordered()" + "df[\"team\"] = df[\"team\"].astype(\"category\").cat.as_ordered()\n", + "df[\"player\"] = df[\"player\"].astype(\"category\").cat.as_ordered()\n", + "df[\"player_num\"] = df[\"player_num\"].astype(\"category\").cat.as_ordered()" ] }, { @@ -198,7 +209,7 @@ "source": [ "%%time\n", "CRS = None\n", - "tc = mpd.TrajectoryCollection(df, 'player', x='x', y='y', crs=CRS)\n", + "tc = mpd.TrajectoryCollection(df, \"player\", x=\"x\", y=\"y\", crs=CRS)\n", "mpd.TemporalSplitter(tc).split(mode=\"day\")\n", "print(f\"Finished creating {len(tc)} trajectories\")" ] @@ -209,8 +220,12 @@ "metadata": {}, "outputs": [], "source": [ - "pitch = Polygon([(0, 0), (0, pitch_width), (pitch_length, pitch_width), (pitch_length, 0), (0, 0)])\n", - "plotted_pitch = GeoDataFrame(pd.DataFrame([{'geometry': pitch, 'id': 1}]), crs=CRS).hvplot(color='white', alpha=0.5)" + "pitch = Polygon(\n", + " [(0, 0), (0, pitch_width), (pitch_length, pitch_width), (pitch_length, 0), (0, 0)]\n", + ")\n", + "plotted_pitch = GeoDataFrame(\n", + " pd.DataFrame([{\"geometry\": pitch, \"id\": 1}]), crs=CRS\n", + ").hvplot(color=\"white\", alpha=0.5)" ] }, { @@ -219,7 +234,7 @@ "metadata": {}, "outputs": [], "source": [ - "plotted_pitch * tc.filter('player_num', 20).hvplot(**hvplot_defaults)" + "plotted_pitch * tc.filter(\"player_num\", 20).hvplot(**hvplot_defaults)" ] }, { @@ -237,8 +252,8 @@ "outputs": [], "source": [ "PLAY = 2\n", - "title = f'Play {PLAY} {plays[PLAY]}'\n", - "play_trajs = tc.filter('play', plays[PLAY])\n", + "title = f\"Play {PLAY} {plays[PLAY]}\"\n", + "play_trajs = tc.filter(\"play\", plays[PLAY])\n", "play_trajs" ] }, @@ -248,7 +263,7 @@ "metadata": {}, "outputs": [], "source": [ - "play_trajs.plot(column='team', colormap={'attack':'hotpink', 'defense':'turquoise'})" + "play_trajs.plot(column=\"team\", colormap={\"attack\": \"hotpink\", \"defense\": \"turquoise\"})" ] }, { @@ -257,7 +272,9 @@ "metadata": {}, "outputs": [], "source": [ - "generalized = mpd.MinTimeDeltaGeneralizer(play_trajs).generalize(tolerance=timedelta(seconds=0.5))" + "generalized = mpd.MinTimeDeltaGeneralizer(play_trajs).generalize(\n", + " tolerance=timedelta(seconds=0.5)\n", + ")" ] }, { @@ -277,7 +294,9 @@ "metadata": {}, "outputs": [], "source": [ - "generalized.hvplot(title=title, c='speed', hover_cols=['player', 'team'], **hvplot_defaults)" + "generalized.hvplot(\n", + " title=title, c=\"speed\", hover_cols=[\"player\", \"team\"], **hvplot_defaults\n", + ")" ] }, { @@ -287,8 +306,10 @@ "outputs": [], "source": [ "(\n", - " plotted_pitch * \n", - " generalized.hvplot(title=title, c='speed', hover_cols=['player'], cmap='Viridis', **hvplot_defaults)\n", + " plotted_pitch\n", + " * generalized.hvplot(\n", + " title=title, c=\"speed\", hover_cols=[\"player\"], cmap=\"Viridis\", **hvplot_defaults\n", + " )\n", ")" ] }, @@ -298,13 +319,23 @@ "metadata": {}, "outputs": [], "source": [ - "get_file_from_url('https://github.com/movingpandas/movingpandas/raw/main/tutorials/data/soccer_field.png')\n", + "get_file_from_url(\n", + " \"https://github.com/movingpandas/movingpandas/raw/main/tutorials/data/soccer_field.png\"\n", + ")\n", "\n", - "pitch_img = hv.RGB.load_image('soccer_field.png', bounds=(0,0,pitch_length,pitch_width)) \n", + "pitch_img = hv.RGB.load_image(\n", + " \"soccer_field.png\", bounds=(0, 0, pitch_length, pitch_width)\n", + ")\n", "(\n", - " pitch_img * \n", - " generalized.hvplot(title=title, c='team', colormap={'attack':'limegreen', 'defense':'purple'}, hover_cols=['team'], **hvplot_defaults) * \n", - " generalized.get_start_locations().hvplot(label='start', color='orange')\n", + " pitch_img\n", + " * generalized.hvplot(\n", + " title=title,\n", + " c=\"team\",\n", + " colormap={\"attack\": \"limegreen\", \"defense\": \"purple\"},\n", + " hover_cols=[\"team\"],\n", + " **hvplot_defaults\n", + " )\n", + " * generalized.get_start_locations().hvplot(label=\"start\", color=\"orange\")\n", ")" ] }, @@ -317,9 +348,16 @@ "outputs": [], "source": [ "(\n", - " pitch_img * \n", - " generalized.hvplot(title=title, c='team', hover_cols=['team'], **hvplot_defaults) * \n", - " generalized.get_start_locations().hvplot(label='start', c='team', hover_cols=['team'], colormap={'attack':'limegreen', 'defense':'purple'}, colorbar=True, legend=True)\n", + " pitch_img\n", + " * generalized.hvplot(title=title, c=\"team\", hover_cols=[\"team\"], **hvplot_defaults)\n", + " * generalized.get_start_locations().hvplot(\n", + " label=\"start\",\n", + " c=\"team\",\n", + " hover_cols=[\"team\"],\n", + " colormap={\"attack\": \"limegreen\", \"defense\": \"purple\"},\n", + " colorbar=True,\n", + " legend=True,\n", + " )\n", ")" ] }, @@ -337,7 +375,8 @@ "1. [Soccer game](soccer-game.ipynb)\n", "1. [Mars rover & heli](mars-rover.ipynb)\n", "1. [Ever Given](ever-given.ipynb)\n", - "1. [Iceberg](iceberg.ipynb)" + "1. [Iceberg](iceberg.ipynb)\n", + "1. [Pollution data](pollution-data.ipynb)" ] } ], diff --git a/data/2021-01-30_all.zip b/data/2021-01-30_all.zip new file mode 100644 index 0000000..4e60608 Binary files /dev/null and b/data/2021-01-30_all.zip differ diff --git a/data/README.md b/data/README.md index 72ef848..46e5cb1 100644 --- a/data/README.md +++ b/data/README.md @@ -38,5 +38,6 @@ Horse collar tracking data provided by Prof. Lene Fischer (University of Copenha The consolidated [BYU/NIC iceberg database](https://www.scp.byu.edu/data/iceberg/) is described in the paper J.S. Budge and D.G. Long, "A Comprehensive Database for Antarctic Iceberg Tracking Using Scatterometer Data," IEEE Journal of Selected Topics in Applied Earth Observations, Vol. 11, No. 2, doi:10.1109/JSTARS.2017.2784186, 2017. +## 2021-01-30_all.zip - +Data from [Delhi Pollution Dataset](http://cse.iitd.ac.in/pollutiondata/delhi), published by the Department of Computer Science and Engineering, Indian Institute of Technology Delhi.