Stop detection in Blue Whales GPS tracking — Movingpandas 0.6
By: Bryan R. Vallejo
Tags: Movingpandas, Geospatial, Wildlife, Whales, Gps Tracking System

Here we go again with Movingpandas. The python library developed by Anita Graser is a powerful tool for analyzing movement data. In a late post, I published how to create a map animation and how to extract stops as points with Bird migration data (GPS tracking). The stop detection algorithm in the new release of Movingpandas 0.6 gives back directly the stops as points and this is definitely what I want to include in a workflow with movement data because it simplifies coding a lot. Especially with a TrajectoryCollection .

For this tutorial/workflow, I am using GPS data for Blue Whale tracking in Southern California to create a map animation with a stop’s duration. The dataset was collected to study the effect of the deep-diving behavior of marine megafauna on location error. For a better understanding, you can review the paper published on Animal Biotelemetry by Irvin et al (2020), and check the details of the GPS dataset in Movebank.

The final map animation of this demo is HERE!

Press play and explore!

The repository with the analysis workflow HERE!

Image by the author. Whale tracks with stop’s duration in minutes

The Whale movement dataset contains 13 whale trajectories of Balaenoptera musculus and Balaenoptera physalusand, it was collected from 2014.08 until 2015.08. For this demo practice, I am going to use only 5 trajectories that have a time range of 2 months: 2015.07 until 2015.08. Keep in mind, that while using the stop detection algorithm in movingpandas you have to specify the parameters of the stop referring to the time duration and search radio. In this case, I specified 5 minutes as the minimum and a search radio of 30 meters. However, you can specify what you consider suitable for your research. If you are studying the feeding behavior of whales then consider they catch the food in the same spot in one jump. I decided to choose 5 minutes on a search radio of 30 meters because It is enough to find stops. I would consider overlap information about Phytoplankton so we can confirm the spot the whales serve their lunch.

Let’s put our hands on. You can review the material in the repository of this post but here the analysis example will be explained into three parts:

1) Formatting movement dataset to Movingpandas.

2) Writing a function that gives back the stops as points in Movingpandas 0.6.

3) Map animation in KeplerGL.

1) Formatting movement dataset to Movingpandas

The process is done in a Jupyter notebook so first, we import all needed libraries. Be sure that you are using Movingpandas 0.6.

import pandas as pd

import geopandas as gpd

from datetime import datetime, timedelta

from keplergl import KeplerGl import movingpandas as mpd

print(mpd.__version__) import warnings

warnings.simplefilter(“ignore”)

Then, we read the Whale movement dataset that is included in the repository in a Geodataframe df . On the fly, subset the table with the 5 whales (tag ID) that we are using in this demo.

# opening file

cd = r’data/whale-movement.geojson’

file = open(cd)

df= gpd.read_file(file) # subset of 5 whales

fiveset = ['2015CA-MK10-00838', '2015CA-MK10-00840', '2015CA-MK10-04177', '2015CA-MK10-05650', '2015CA-MK10-05654']

df = df.loc[df['tag_ident'].isin(fiveset)]

To have the movement dataset ready to use in Movingpandas it is necessary to format the index as DateTime Format. It goes as next:

# preparing the data for movingpandas

df[‘t’] = pd.to_datetime(df[‘timestamp’])

df = df.set_index(‘t’).tz_localize(None)

As for advice. Be sure that your geodataframe df has CRS WGS84 . At the moment we have formatted the table with DateTime index and a subset of 5 whales. The new subset has a time range from 2015.07 until 2015.08.

Now we are going to use it in Movingpandas.

2) Function that gives back the stops as points in Movingpandas 0.6

In this section, I am creating a function that gives back a geodataframe with the stops as points and includes a column with stop duration in minutes and another column with the tag id of the Whale. Be aware that this function uses parameters in minutes. You can find examples with parameters in hours in my late post and examples with seconds in the Anita Graser repository. The stops represent a segment of the trajectory and the stops as points are the start of this mentioned segment.

The parameters of the function are: moving_df <geodataframe>, traject_id_column <string>, minutes <number>, searchradio <number>. They are explained in the Notebook but here simply works as next:

def get_stop_point_traj_collection(moving_df, traject_id_column, minutes, searchradio):



all_stop_points = gpd.GeoDataFrame()



# create a traj collection with movingpandas

traj_collection = mpd.TrajectoryCollection(moving_df, traject_id_column)



for i in range(len(traj_collection)): # create a stop detector

detector = mpd.TrajectoryStopDetector(traj_collection.trajectories[i])



# stop points

stop_points = detector.get_stop_points(min_duration=timedelta(minutes=minutes), max_diameter=searchradio)



# add duration to table

stop_points['duration_m'] = (stop_points['end_time']-stop_points['start_time']).dt.total_seconds()/60



# add ID

stop_points['tag_id'] = [tag.split('_')[0] for tag in stop_points.index.to_list()]



all_stop_points= all_stop_points.append(stop_points)



return all_stop_points

Then we use it with our geodataframe df with GPS records, we include the tag id of the whales with the column tag_ident , 5 minutes for stop detection and 30 meters as search radio.

%%time

whale_stops = get_stop_point_traj_collection(df, ‘tag_ident’, 5, 30)

If you check the final table whale_stops with the line whale_stops.head() you will see a nice table formated as next:

Image by the author. Table with whale stops as points from Movingpandas analysis

3) Map animation in KeplerGL

The first step to work in KeplerGL is to avoid DateTime Format in columns. We are going to remove DateTime Format in geodataframe with all GPS tracks df and geodataframe whale_stops . With next code:

# remove datetime format for GPS tracks

df = df.reset_index(drop=True)

# remove datetime format for whale stops

whale_stops[[‘start_time’, ‘end_time’]] = whale_stops[[‘start_time’, ‘end_time’]].astype(str)

whale_stops= whale_stops.reset_index(drop=True)

Then, we create a KeplerGL instance, and add the 2 geodataframes: df and whale_stops with the next code:

# Create KeplerGl instance

m = KeplerGl(height=600) # Add stop durations

m.add_data(whale_stops, ‘stops’) # Add gps records

m.add_data(df, ‘trajectories’)

Now you can format the map animation with KeplerGL invoking the instance.