diff --git a/.bumpversion.cfg b/.bumpversion.cfg new file mode 100644 index 00000000..dc0a4ff1 --- /dev/null +++ b/.bumpversion.cfg @@ -0,0 +1,19 @@ +[bumpversion] +current_version = 0.2.0.dev0 +commit = True +tag = False +files = traja/__init__.py +parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\.(?P[a-z]+)(?P\d+))? +serialize = + {major}.{minor}.{patch}.{release}{n} + {major}.{minor}.{patch} + +[bumpversion:part:release] +optional_value = post +first_value = dev +values = + dev + post + +[bumpversion:part:n] + diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 00000000..723ba835 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,10 @@ +[report] +exclude_lines = + pragma: no cover + def __repr__ + raise AssertionError + raise NotImplementedError + if __name__ == .__main__.: +omit = + traja/tests/* + traja/contrib/* \ No newline at end of file diff --git a/.flake8 b/.flake8 new file mode 100644 index 00000000..7bf302cd --- /dev/null +++ b/.flake8 @@ -0,0 +1,5 @@ +[flake8] +ignore = E203, E266, E501, W503, F403, F401 +max-line-length = 120 +max-complexity = 18 +select = B,C,E,F,W,T4,B9 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..dd84ea78 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..bbcbbe7d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/draft-pdf.yml b/.github/workflows/draft-pdf.yml new file mode 100644 index 00000000..76310246 --- /dev/null +++ b/.github/workflows/draft-pdf.yml @@ -0,0 +1,23 @@ +on: [push] + +jobs: + paper: + runs-on: ubuntu-latest + name: Paper Draft + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Build draft PDF + uses: openjournals/openjournals-draft-action@master + with: + journal: joss + # This should be the path to the paper within your repo. + paper-path: paper/paper.md + - name: Upload + uses: actions/upload-artifact@v1 + with: + name: paper + # This is the output path where Pandoc will write the compiled + # PDF. Note, this should be the same directory as the input + # paper.md + path: paper/paper.pdf diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml new file mode 100644 index 00000000..046c4ec3 --- /dev/null +++ b/.github/workflows/tests.yaml @@ -0,0 +1,54 @@ +name: Tests + +on: + push: + branches: [master] + tags: [v*] + pull_request: + branches: [master] + +jobs: + miniconda: + name: Miniconda ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: ["ubuntu-latest", "windows-latest"] + steps: + - uses: actions/checkout@v2 + - uses: conda-incubator/setup-miniconda@v2 + with: + activate-environment: test + channels: conda-forge,defaults + environment-file: environment.yml + python-version: 3.8 + auto-activate-base: false + - shell: bash -l {0} + run: | + conda info + conda list + - name: Lint + shell: bash -l {0} + run: | + conda install flake8 + python -m flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + python -m flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Run pytest + shell: bash -l {0} + run: | + pip install -r requirements/dev.txt + pip install -r requirements/docs.txt + pip install --upgrade pytest flake8 sphinx + pip install scipy --force-reinstall # for https://github.com/conda/conda/issues/6396 + pip install . + conda install pytest + py.test . --cov-report=xml --cov=traja -vvv + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + flags: unittests + env_vars: OS,PYTHON + name: codecov-umbrella + fail_ci_if_error: false + verbose: false diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..c3f65827 --- /dev/null +++ b/.gitignore @@ -0,0 +1,129 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +.DS_Store + +# Visualstudio code file +.vscode +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +.idea + +_build/ + +# BUILD FILES +*.zip +hypers.json +model + +docs/source/gallery +docs/source/savefig +docs/source/reference + +# Editor files +*.swp +*.swo + + +# Model parameter files +*.pt diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..3bd738d8 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,11 @@ +repos: +- repo: https://github.com/ambv/black + rev: stable + hooks: + - id: black + language_version: python3.7 +- repo: https://gitlab.com/pycqa/flake8 + rev: 3.8.3 + hooks: + - id: flake8 + language: python_venv diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 00000000..49541741 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,13 @@ +version: 2 +sphinx: + configuration: docs/source/conf.py + +formats: all + +build: + image: latest + +python: + version: 3.7 + install: + - requirements: requirements/docs.txt diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..61f82ac5 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,52 @@ +sudo: false + +dist: xenial + +language: python + +python: + - '3.7' + - '3.8' + +git: + depth: false + +env: + - MPLBACKEND=Agg CODECOV_TOKEN="287389e5-8f99-42e1-8844-17acef7c454f" + +cache: pip + +before_install: + - sudo apt-get update + +install: +- wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh + -O miniconda.sh +- bash miniconda.sh -b -p $HOME/miniconda +- export PATH="$HOME/miniconda/bin:$PATH" +- hash -r +- conda config --set always_yes yes --set changeps1 no +- conda update -q conda +- conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION +- source activate test-environment +- pip install -r requirements/dev.txt +- pip install -r requirements/docs.txt +- pip install --upgrade pytest flake8 sphinx +- pip install . +script: + - cd docs && make doctest && cd .. + - py.test . --cov-report term --cov=traja + +after_success: + - codecov + +deploy: + provider: pypi + user: jshenk + skip_cleanup: true + skip_existing: true + on: + tags: true + branch: master + password: + secure: o5ON/6Q4aORM4dgTVUQ39w0N+Gc+6Ala+K5J16b5lnNWGgHglqIlJzYXJo8THpeNYTm6ZbEDQEFurCTEKA/MZ2WzreePWQ4Z4E2dIihqhI+71rSbForRPKunV2CEr/QQdUEzXe6npO2UTnO0zDS5XMSrlBncKO4F4zUvrYTuXLj5fES0IFiFHMWxEpNaXMKiypfcRIKJriRbHY22/H8uSgzFluxRG+UqpbJz+R94bqIg30wBJw4nI9JMI00Du67eCO91t+aQ26+5Am+DqA6+jawd89OVPxtlLSdWtgtxPmWAD/IBLP2d7sqfK+QnezmH8NuAMB6DJdTkbscHcvYT8itHg8csBDdvfH8xoA9x8f+Cc60gviKaBoayORFF7FXkjyAYTCSfEi2dfxTTDR0UisbEG99k0+25+DMHxdC8z7/NQz4qal2vKfhPe8kTsOPQLwh0EHmdVU+v9M9LgrLhN55/lI/a6w+zL1/BJ6ZO6arMhHLVmgRtHP+Ckq6OKwQJYNwZxsg8PfwZxl0jFfd3yVX9lS9s95An90z9mEPheC8zQNz2fzAZUZun6GI9u/FCrGpMbrzKzq4R0UtNc8mfipHJ/v027+C2x43wkXA0c6Zvf9b7i6Bgm6EonnTagWrkQ0RdwqiKDd3smfgK2QZzD4G9vuv6z0w5CFhHL9v1Oc0= diff --git a/CITATION b/CITATION new file mode 100644 index 00000000..1b5d2dfa --- /dev/null +++ b/CITATION @@ -0,0 +1,11 @@ +@software{justin_shenk_2019_3237827, + author = {Justin Shenk and + the Traja development team}, + title = {justinshenk/traja}, + month = jun, + year = 2019, + publisher = {Zenodo}, + version = {latest}, + doi = {10.5281/zenodo.3237827}, + url = {https://doi.org/10.5281/zenodo.3237827} +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..f5805af3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,7 @@ +Copyright 2019 Justin Shenk + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.rst b/README.rst new file mode 100644 index 00000000..0f3c067d --- /dev/null +++ b/README.rst @@ -0,0 +1,205 @@ +Traja |Python-ver| |Travis| |PyPI| |Conda| |RTD| |Gitter| |Black| |License| |Binder| |Codecov| |DOI| |JOSS| +=========================================================================================================== + +|Colab| + +.. |Python-ver| image:: https://img.shields.io/badge/python-3.6+-blue.svg + :target: https://www.python.org/downloads/release/python-360/ + :alt: Python 3.6+ + +.. |Travis| image:: https://travis-ci.org/traja-team/traja.svg?branch=master + :target: https://travis-ci.org/traja-team/traja + +.. |PyPI| image:: https://badge.fury.io/py/traja.svg + :target: https://badge.fury.io/py/traja + +.. |Conda| image:: https://img.shields.io/conda/vn/conda-forge/traja.svg + :target: https://anaconda.org/conda-forge/traja + +.. |Gitter| image:: https://badges.gitter.im/traja-chat/community.svg + :target: https://gitter.im/traja-chat/community + +.. |RTD| image:: https://readthedocs.org/projects/traja/badge/?version=latest + :target: https://traja.readthedocs.io/en/latest/?badge=latest + :alt: Documentation Status + +.. |Black| image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/ambv/black + +.. |License| image:: https://img.shields.io/badge/License-MIT-blue.svg + :target: https://opensource.org/licenses/MIT + :alt: License: MIT + +.. |Binder| image:: https://mybinder.org/badge_logo.svg + :target: https://mybinder.org/v2/gh/justinshenk/traja/master?filepath=demo.ipynb + +.. |Codecov| image:: https://codecov.io/gh/traja-team/traja/branch/master/graph/badge.svg + :target: https://codecov.io/gh/traja-team/traja + +.. |DOI| image:: https://zenodo.org/badge/DOI/10.5281/zenodo.5069231.svg + :target: https://doi.org/10.5281/zenodo.5069231 + +.. |Colab| image:: https://colab.research.google.com/assets/colab-badge.svg + :target: https://colab.research.google.com/github/justinshenk/traja/blob/master/demo.ipynb + +.. |JOSS| image:: https://joss.theoj.org/papers/0f25dc08671e0ec54714f09597d116cb/status.svg + :target: https://joss.theoj.org/papers/0f25dc08671e0ec54714f09597d116cb + +Traja is a Python library for trajectory analysis. It extends the capability of +pandas DataFrame specific for animal trajectory analysis in 2D, and provides +convenient interfaces to other geometric analysis packages (eg, R and shapely). + +Introduction +------------ + +The traja Python package is a toolkit for the numerical characterization +and analysis of the trajectories of moving animals. Trajectory analysis +is applicable in fields as diverse as optimal foraging theory, +migration, and behavioral mimicry (e.g. for verifying similarities in +locomotion). A trajectory is simply a record of the path followed by a +moving animal. Traja operates on trajectories in the form of a series of +locations (as x, y coordinates) with times. Trajectories may be obtained +by any method which provides this information, including manual +tracking, radio telemetry, GPS tracking, and motion tracking from +videos. + +The goal of this package (and this document) is to aid biological +researchers, who may not have extensive experience with Python, to +analyze trajectories without being restricted by a limited knowledge of +Python or programming. However, a basic understanding of Python is +useful. + +If you use traja in your publications, please cite the repo + +.. code-block:: + + @software{justin_shenk_2019_3237827, + author = {Justin Shenk and + the Traja development team}, + title = {justinshenk/traja}, + month = jun, + year = 2019, + publisher = {Zenodo}, + version = {latest}, + doi = {10.5281/zenodo.3237827}, + url = {https://doi.org/10.5281/zenodo.3237827} + } + + +Installation and setup +---------------------- + +To install traja with conda, run + +``conda install -c conda-forge traja`` + +or with pip + +``pip install traja``. + +Import traja into your Python script or via the Python command-line with +``import traja``. + +Trajectories with traja +----------------------- + +Traja stores trajectories in pandas DataFrames, allowing any pandas +functions to be used. + +Load trajectory with x, y and time coordinates: + +.. code-block:: python + + import traja + + df = traja.read_file('coords.csv') + +Once a DataFrame is loaded, use the ``.traja`` accessor to access the +visualization and analysis methods: + +.. code-block:: python + + df.traja.plot(title='Cage trajectory') + + +Analyze Trajectory +------------------ + +.. csv-table:: The following functions are available via ``traja.trajectory.[method]`` + :header: "Function", "Description" + :widths: 30, 80 + + "``calc_derivatives``", "Calculate derivatives of x, y values " + "``calc_turn_angles``", "Calculate turn angles with regard to x-axis " + "``transitions``", "Calculate first-order Markov model for transitions between grid bins" + "``generate``", "Generate random walk" + "``resample_time``", "Resample to consistent step_time intervals" + "``rediscretize_points``", "Rediscretize points to given step length" + +For up-to-date documentation, see `https://traja.readthedocs.io `_. + +Random walk +----------- + +Generate random walks with + +.. code-block:: python + + df = traja.generate(n=1000, step_length=2) + df.traja.plot() + +.. image:: https://raw.githubusercontent.com/justinshenk/traja/master/docs/source/_static/walk_screenshot.png + :alt: walk\_screenshot.png + + +Resample time +------------- +``traja.trajectory.resample_time`` allows resampling trajectories by a ``step_time``. + + +Flow Plotting +------------- + +.. code-block:: python + + df = traja.generate() + traja.plot_surface(df) + +.. image:: https://traja.readthedocs.io/en/latest/_images/sphx_glr_plot_average_direction_001.png + :alt: 3D plot + +.. code-block:: python + + traja.plot_quiver(df, bins=32) + +.. image:: https://traja.readthedocs.io/en/latest/_images/sphx_glr_plot_average_direction_002.png + :alt: quiver plot + +.. code-block:: python + + traja.plot_contour(df, filled=False, quiver=False, bins=32) + +.. image:: https://traja.readthedocs.io/en/latest/_images/sphx_glr_plot_average_direction_003.png + :alt: contour plot + +.. code-block:: python + + traja.plot_contour(df, filled=False, quiver=False, bins=32) + +.. image:: https://traja.readthedocs.io/en/latest/_images/sphx_glr_plot_average_direction_004.png + :alt: contour plot filled + +.. code-block:: python + + traja.plot_contour(df, bins=32, contourfplot_kws={'cmap':'coolwarm'}) + +.. image:: https://traja.readthedocs.io/en/latest/_images/sphx_glr_plot_average_direction_005.png + :alt: streamplot + +Acknowledgements +---------------- + +traja code implementation and analytical methods (particularly +``rediscretize_points``) are heavily inspired by Jim McLean's R package +`trajr `__. Many thanks to Jim for his +feedback. diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..44819a03 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,25 @@ +codecov: + require_ci_to_pass: yes + +coverage: + precision: 2 + round: down + range: "70...100" + +parsers: + gcov: + branch_detection: + conditional: yes + loop: yes + method: yes + macro: yes + +comment: + layout: "reach,diff,flags,files,footer" + behavior: default + require_changes: no + +ignore: + - "test_*.py" + - "traja-gui.py*" + diff --git a/contributing.rst b/contributing.rst new file mode 100644 index 00000000..3130acfc --- /dev/null +++ b/contributing.rst @@ -0,0 +1,107 @@ +Contributing to Traja +===================== + +Traja is a research library. Functionality must therefore be both +cutting-edge and reliable. Traja is part of a wider project to +increase collaboration in research, through the adoption of +open-source contribution models. It is our hope that traja +remains accessible to researchers and help them do higher-quality +research. + +Current status +-------------- + +Traja is currently undergoing active development with approximately +60 % of features present. Significant interface changes are still +possible, however we avoid these unless absolutely necessary. + +The work is currently focussed on reaching version 1.0 with feature +completeness and 95 % test coverage. + +The following features are required for feature completeness: + +* Latent space visualisers + * Eigenspace-based + * Colour-coded to visualise evolution over time + * Delay coordinate embeddings +* State-space visualisers +* Additional encoder and decoder options in AE and VAE models + * MLP + * 1d convolution +* Pituitary gland example dataset +* Regression output visualisers +* VAE GAN models +* Additional VAE latent-space shapes + * Uniform + * A shape that works for periodic trajectories (Torus?) +* Delay coordinate embeddings + * Persistent homology diagrams of the embeddings +* Automatic code formatter +* Tutorials + * Find time of day based on activity + * `Recover parameters from Pituitary ODE `_ + * `Predict stock prices with LSTMs `_ + +How to contribute +----------------- + +Traja welcomes contributions! To get started, pick up any issue +labeled with `good first issue`! Alternatively you can read some +background material or try a tutorial. + +Testing and code quality +------------------------ + +Since Traja is a library, we strive for sensible tests achieving a +high level of code coverage. Future commits are required to maintain +or improve code quality, test coverage. To aid in this, Travis runs +automated tests on each pull request. Additionally, we run codecov +on PRs. + +Background material +------------------- + +This is a collection of papers and resources that explain the +main problems we are working on with Traja. + +Analysis of mice that have suffered a stroke: + + @article{10.3389/fnins.2020.00518, + author={Justin Shenk and + Klara J. Lohkamp and + Maximilian Wiesmann and + Amanda J. Kiliaan}, + title={Automated Analysis of Stroke Mouse Trajectory Data With Traja}, + journal={Frontiers in Neuroscience}, + volume={14}, + pages={518}, + year={2020}, + url={https://www.frontiersin.org/article/10.3389/fnins.2020.00518}, + doi={10.3389/fnins.2020.00518}, + issn={1662-453X}, + } + + +Understanding the parameter space of the pituitary gland ODE (https://www.math.fsu.edu/~bertram/papers/bursting/JCNS_16.pdf): + + + @article{10.1007/s10827-016-0600-1, + author = {Fletcher, Patrick and Bertram, Richard and Tabak, Joel}, + title = {From Global to Local: Exploring the Relationship between Parameters and Behaviors in Models of Electrical Excitability}, + year = {2016}, + publisher = {Springer-Verlag}, + address = {Berlin, Heidelberg}, + volume = {40}, + number = {3}, + issn = {0929-5313}, + url = {https://doi.org/10.1007/s10827-016-0600-1}, + doi = {10.1007/s10827-016-0600-1}, + journal = {J. Comput. Neurosci.}, + month = June, + pages = {331ā€“345}, + } + + +Style guide +----------- +TODO diff --git a/demo.ipynb b/demo.ipynb new file mode 100644 index 00000000..b1f4395d --- /dev/null +++ b/demo.ipynb @@ -0,0 +1,529 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Analyzing Spatial Trajectories with Traja\n", + "Full documentation is available at [traja.readthedocs.io](http://traja.readthedocs.io)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "!pip install traja\n", + "import traja" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Create sample random walk\n", + "df = traja.generate()\n", + "\n", + "# Visualize x and y values with built-in pandas methods\n", + "df.plot()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plot Trajectory" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plot trajectory with traja accessor method (`.traja.plot()`)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "fig = df.traja.plot()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Visualize distribution of angles and turn-angles" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "df.traja.calc_angle().hist() # with regard to x-axis" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "df.traja.calc_turn_angle().hist() # deviation from strait ahead" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Visualize flow between grid units" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "for kind in ['stream', 'quiver', 'contourf']:\n", + " fig = df.traja.plot_flow(kind=kind)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Visualize distribution of turn angles over time" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "df.traja.calc_turn_angle().plot()" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Bins: 8\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Bins: 32\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Bins: 8\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Bins: 32\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "for log in [True, False]:\n", + " for bins in [8, 32]:\n", + " print(f\"Bins: {bins}\")\n", + " df.traja.trip_grid(bins=bins, log=log)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plot polar bar chart showing turn preference" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/justinshenk/Projects/mousetrack/traja/plotting.py:745: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n", + " trj[\"turn_angle\"] = feature_series\n", + "/Users/justinshenk/anaconda3/envs/traja/lib/python3.6/site-packages/pandas/core/generic.py:5096: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n", + " self[name] = value\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "traja.plotting.polar_bar(df)" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/justinshenk/Projects/mousetrack/traja/plotting.py:745: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n", + " trj[\"turn_angle\"] = feature_series\n", + "/Users/justinshenk/anaconda3/envs/traja/lib/python3.6/site-packages/pandas/core/generic.py:5096: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n", + " self[name] = value\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Show non-overlapping histogram\n", + "traja.plotting.polar_bar(df, overlap=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Resample Trajectory" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Resample to arbitrary step length (here, 20 meters)\n", + "fig = df.traja.rediscretize(R=20).traja.plot()" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Resample to arbitrary time (here, 1 second)\n", + "fig = df.traja.resample_time(step_time='1s').traja.plot()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "traja", + "language": "python", + "name": "traja" + }, + "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.6.8" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} \ No newline at end of file diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..69fe55ec --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,19 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/environment.yml b/docs/environment.yml new file mode 100644 index 00000000..aeda683d --- /dev/null +++ b/docs/environment.yml @@ -0,0 +1,14 @@ +name: traja +channels: + - pytorch + - conda-forge + - defaults +dependencies: + - python>=3.7 + - sphinx-gallery + - sphinx + - scikit-learn + - fastdtw + - tzlocal + - seaborn + - pytorch>=1.7.0 diff --git a/docs/examples/README.txt b/docs/examples/README.txt new file mode 100644 index 00000000..90ccff7c --- /dev/null +++ b/docs/examples/README.txt @@ -0,0 +1,4 @@ +Gallery +================== + +A gallery of examples diff --git a/docs/examples/animate.py b/docs/examples/animate.py new file mode 100644 index 00000000..a736c7d0 --- /dev/null +++ b/docs/examples/animate.py @@ -0,0 +1,20 @@ +""" +Animate trajectories +------------------------------- +traja allows animating trajectories. +""" +import traja + +df = traja.generate(1000, seed=0) + +############################################################################### +# Plot a animation of trajectory +# ============================== +# An animation is generated using :func:`~traja.plotting.animate`. + +anim = traja.plotting.animate(df) # save=True saves to 'trajectory.mp4' + +#################################################################################### +# .. raw:: html +# +# \ No newline at end of file diff --git a/docs/examples/plot_3d.py b/docs/examples/plot_3d.py new file mode 100644 index 00000000..9adf0366 --- /dev/null +++ b/docs/examples/plot_3d.py @@ -0,0 +1,19 @@ +""" +3D Plotting with traja +---------------------- +Plot trajectories with time in the vertical axis. +Note: Adjust matplotlib args ``dist``, ``labelpad``, ``aspect`` and ``adjustable``` +as needed. +""" + +import traja + +df = traja.TrajaDataFrame({"x": [0, 1, 2, 3, 4], "y": [1, 3, 2, 4, 5]}) +trj = traja.generate(seed=0) + +############################################################################### +# Plot a trajectory in 3D +# ======================= +# A 3D plot is generated using :func:`~traja.plotting.plot_3d`. + +trj.traja.plot_3d(dist=15, labelpad=32, title="Traja 3D Plot") \ No newline at end of file diff --git a/docs/examples/plot_autocorrelation.py b/docs/examples/plot_autocorrelation.py new file mode 100644 index 00000000..100ee02e --- /dev/null +++ b/docs/examples/plot_autocorrelation.py @@ -0,0 +1,12 @@ +""" +Autocorrelation plotting with traja +----------------------------------- +Plot autocorrelation of a trajectory with :meth:`traja.plotting.plot_autocorrelation` + +Wrapper for pandas :meth:`pandas.plotting.autocorrelation_plot`. + +""" +import traja + +trj = traja.generate(seed=0) +trj.traja.plot_autocorrelation('x') \ No newline at end of file diff --git a/docs/examples/plot_average_direction.py b/docs/examples/plot_average_direction.py new file mode 100644 index 00000000..5c465742 --- /dev/null +++ b/docs/examples/plot_average_direction.py @@ -0,0 +1,59 @@ +""" +Average direction for each grid cell +==================================== +See the flow between grid cells. +""" +import traja + +df = traja.generate(seed=0) + +############################################################################### +# Average Flow (3D) +# ----------------- +# Flow can be plotted by specifying the `kind` parameter of :func:`traja.plotting.plot_flow` +# or by calling the respective functions. + +import traja + +traja.plotting.plot_surface(df, bins=32) + +############################################################################### +# Quiver +# ------ +# Quiver plot +# Additional arguments can be specified as a dictionary to `quiverplot_kws`. + +traja.plotting.plot_quiver(df, bins=32) + +############################################################################### +# Contour +# ------- +# Parameters `filled` and `quiver` are both enabled by default and can be +# disabled. +# Additional arguments can be specified as a dictionary to `contourplot_kws`. + +traja.plotting.plot_contour(df, filled=False, quiver=False, bins=32) + +############################################################################### +# Contour (Filled) +# ---------------- + +traja.plotting.plot_contour(df, bins=32, contourfplot_kws={"cmap": "coolwarm"}) + +############################################################################### +# Stream +# ------ +# 'cmap' can be specified, eg, 'coolwarm', 'viridis', etc. +# Additional arguments can be specified as a dictionary to 'streamplot_kws'. + +traja.plotting.plot_stream(df, cmap="jet", bins=32) + +############################################################################### +# Polar bar +# --------- +traja.plotting.polar_bar(df) + +############################################################################### +# Polar bar (histogram) +# --------------------- +traja.plotting.polar_bar(df, overlap=False) diff --git a/docs/examples/plot_collection.py b/docs/examples/plot_collection.py new file mode 100644 index 00000000..5bb8a8f2 --- /dev/null +++ b/docs/examples/plot_collection.py @@ -0,0 +1,21 @@ +""" +Plotting Multiple Trajectories +------------------------------ +Plotting multiple trajectories is easy with :meth:`~traja.frame.TrajaCollection.plot`. +""" +import traja +from traja import TrajaCollection + +# Create a dictionary of DataFrames, with 'id' as key. +dfs = {idx: traja.generate(idx, seed=idx) for idx in range(10, 15)} + +# Create a TrajaCollection. +trjs = TrajaCollection(dfs) + +# Note: A TrajaCollection can also be instantiated with a DataFrame, containing and id column, +# eg, TrajaCollection(df, id_col="id") + +# 'colors' also allows substring matching, eg, {"car":"red", "person":"blue"} +lines = trjs.plot( + colors={10: "red", 11: "blue", 12: "blue", 13: "orange", 14: "purple"} +) diff --git a/docs/examples/plot_comparing.py b/docs/examples/plot_comparing.py new file mode 100644 index 00000000..3fb7fd16 --- /dev/null +++ b/docs/examples/plot_comparing.py @@ -0,0 +1,42 @@ +""" +Comparing +--------- +traja allows comparing trajectories using various methods. +""" +import traja + +df = traja.generate(seed=0) +df.traja.plot() + +############################################################################### +# Fast Dynamic Time Warping of Trajectories +# ========================================= +# +# Fast dynamic time warping can be performed using ``fastdtw``. +# Source article: `link `_. +import numpy as np + +rotated = traja.rotate(df, angle=np.pi / 10) +rotated.traja.plot() + +############################################################################### +# Compare trajectories hierarchically +# =================================== +# Hierarchical agglomerative clustering allows comparing trajectories as actograms +# and finding nearest neighbors. This is useful for comparing circadian rhythms, +# for example. + +# Generate random trajectories +trjs = [traja.generate(seed=i) for i in range(20)] + +# Calculate displacement +displacements = [trj.traja.calc_displacement() for trj in trjs] + +traja.plot_clustermap(displacements) + +############################################################################### +# Compare trajectories point-wise +# =============================== +dist = traja.distance_between(df.traja.xy, rotated.traja.xy) + +print(f"Distance between the two trajectories is {dist}") diff --git a/docs/examples/plot_grid.py b/docs/examples/plot_grid.py new file mode 100644 index 00000000..b5cf283b --- /dev/null +++ b/docs/examples/plot_grid.py @@ -0,0 +1,38 @@ +""" +Plotting trajectories on a grid +------------------------------- +traja allows comparing trajectories using various methods. +""" +import traja + +df = traja.generate(seed=0) + +############################################################################### +# Plot a heat map of the trajectory +# ================================= +# A heat map can be generated using :func:`~traja.trajectory.trip_grid`. +df.traja.trip_grid() + +############################################################################### +# Increase the grid resolution +# ============================ +# Number of bins can be specified with the ``bins`` parameter. +df.traja.trip_grid(bins=40) + +############################################################################### +# Convert coordinates to grid indices +# =================================== +# Number of x and y bins can be specified with the ``bins``` parameter. + +from traja.trajectory import grid_coordinates + +grid_coords = grid_coordinates(df, bins=32) +print(grid_coords.head()) + +############################################################################### +# Transitions as Markov first-order Markov model +# ============================================== +# Probability of transitioning between cells is computed using :func:`traja.trajectory.transitions`. + +transitions_matrix = traja.trajectory.transitions(df, bins=32) +print(transitions_matrix[:10]) diff --git a/docs/examples/plot_pca.py b/docs/examples/plot_pca.py new file mode 100644 index 00000000..f145b5ec --- /dev/null +++ b/docs/examples/plot_pca.py @@ -0,0 +1,13 @@ +""" +Plot PCA with traja +------------------- +Plot PCA of a trip grid with :meth:`traja.plotting.plot_pca` + +""" +import traja + +# Load sample jaguar dataset with trajectories for 9 animals +df = traja.dataset.example.jaguar() + +# Bin trajectory into a trip grid then perform PCA +traja.plotting.plot_pca(df, id_col="ID", bins=(8,8)) \ No newline at end of file diff --git a/docs/examples/plot_periodogram.py b/docs/examples/plot_periodogram.py new file mode 100644 index 00000000..24739e57 --- /dev/null +++ b/docs/examples/plot_periodogram.py @@ -0,0 +1,12 @@ +""" +Periodogram plot with traja +----------------------------------- +Plot periodogram or power spectrum with :meth:`traja.plotting.plot_periodogram`. + +Wrapper for pandas :meth:`scipy.signal.periodogram`. + +""" +import traja + +trj = traja.generate(seed=0) +trj.traja.plot_periodogram('x') \ No newline at end of file diff --git a/docs/images/3d_plot.png b/docs/images/3d_plot.png new file mode 100644 index 00000000..38aafa29 Binary files /dev/null and b/docs/images/3d_plot.png differ diff --git a/docs/images/clustering.png b/docs/images/clustering.png new file mode 100644 index 00000000..ad647349 Binary files /dev/null and b/docs/images/clustering.png differ diff --git a/docs/images/collection_plot.png b/docs/images/collection_plot.png new file mode 100644 index 00000000..74784593 Binary files /dev/null and b/docs/images/collection_plot.png differ diff --git a/docs/images/resampled.png b/docs/images/resampled.png new file mode 100644 index 00000000..ddafacad Binary files /dev/null and b/docs/images/resampled.png differ diff --git a/docs/images/smoothed.png b/docs/images/smoothed.png new file mode 100644 index 00000000..43a7459b Binary files /dev/null and b/docs/images/smoothed.png differ diff --git a/docs/neuralnets/train_lstm.py b/docs/neuralnets/train_lstm.py new file mode 100644 index 00000000..07f48704 --- /dev/null +++ b/docs/neuralnets/train_lstm.py @@ -0,0 +1,14 @@ +""" +Train LSTM model for time series forecasting +""" +import traja +from traja.model import LSTM +from traja.dataset import dataset + +df = traja.TrajaDataFrame({"x": [0, 1, 2, 3, 4], "y": [1, 3, 2, 4, 5]}) + +# Dataloader + +# Model instance + +# Trainer diff --git a/docs/source/_static/after_rdp.png b/docs/source/_static/after_rdp.png new file mode 100644 index 00000000..dd9f8759 Binary files /dev/null and b/docs/source/_static/after_rdp.png differ diff --git a/docs/source/_static/dvc_screenshot.png b/docs/source/_static/dvc_screenshot.png new file mode 100644 index 00000000..881c1eee Binary files /dev/null and b/docs/source/_static/dvc_screenshot.png differ diff --git a/docs/source/_static/ltraj_plot.png b/docs/source/_static/ltraj_plot.png new file mode 100644 index 00000000..b9454e52 Binary files /dev/null and b/docs/source/_static/ltraj_plot.png differ diff --git a/docs/source/_static/resampled.png b/docs/source/_static/resampled.png new file mode 100644 index 00000000..21b4bc28 Binary files /dev/null and b/docs/source/_static/resampled.png differ diff --git a/docs/source/_static/rnn_prediction.png b/docs/source/_static/rnn_prediction.png new file mode 100644 index 00000000..a28796c9 Binary files /dev/null and b/docs/source/_static/rnn_prediction.png differ diff --git a/docs/source/_static/trajectory.mp4 b/docs/source/_static/trajectory.mp4 new file mode 100644 index 00000000..3b6ca5b9 Binary files /dev/null and b/docs/source/_static/trajectory.mp4 differ diff --git a/docs/source/_static/trip_grid.png b/docs/source/_static/trip_grid.png new file mode 100644 index 00000000..91d5b8d5 Binary files /dev/null and b/docs/source/_static/trip_grid.png differ diff --git a/docs/source/_static/walk_screenshot.png b/docs/source/_static/walk_screenshot.png new file mode 100644 index 00000000..f7e3c46d Binary files /dev/null and b/docs/source/_static/walk_screenshot.png differ diff --git a/docs/source/_templates/autosummary.rst b/docs/source/_templates/autosummary.rst new file mode 100644 index 00000000..f2f010d6 --- /dev/null +++ b/docs/source/_templates/autosummary.rst @@ -0,0 +1,7 @@ +{{ fullname | escape | underline}} + +.. currentmodule:: {{ module }} + +{% if objtype in ['class', 'method', 'function'] %} + +{% endif %} diff --git a/docs/source/calculations.rst b/docs/source/calculations.rst new file mode 100644 index 00000000..f79faffc --- /dev/null +++ b/docs/source/calculations.rst @@ -0,0 +1,49 @@ +Smoothing and Analysis +====================== + +Smoothing +--------- + +Smoothing can be performed using :func:`~traja.trajectory.smooth_sg`. + +.. autofunction:: traja.trajectory.smooth_sg + +.. ipython:: + + df = traja.generate() + smoothed = traja.smooth_sg(df, w=101) + smoothed.traja.plot() + +.. image:: https://raw.githubusercontent.com/justinshenk/traja/master/docs/images/smoothed.png + + +Length +------ + +Length of trajectory can be calculated using :func:`~traja.trajectory.length`. + +.. autofunction:: traja.trajectory.length + +Distance +-------- + +Net displacement of trajectory (start to end) can be calculated using :func:`~traja.trajectory.distance`. + +.. autofunction:: traja.trajectory.distance + +Displacement +------------ + +Displacement (distance travelled) can be calculated using :func:`~traja.trajectory.calc_displacement`. + +.. autofunction:: traja.trajectory.calc_displacement + +Derivatives +----------- + +.. autofunction:: traja.trajectory.get_derivatives + +Speed Intervals +--------------- + +.. autofunction:: traja.trajectory.speed_intervals \ No newline at end of file diff --git a/docs/source/clustering.rst b/docs/source/clustering.rst new file mode 100644 index 00000000..601bff58 --- /dev/null +++ b/docs/source/clustering.rst @@ -0,0 +1,19 @@ +Clustering and Dimensionality Reduction +======================================= + +Clustering Trajectories +----------------------- + +Trajectories can be clustered using :func:`traja.plotting.plot_clustermap`. + +Colors corresponding to each trajectory can be specified with the ``colors`` argument. + +.. autofunction:: traja.plotting.plot_clustermap + +PCA +--- + +Prinicipal component analysis can be used to cluster trajectories based on grid cell occupancy. +PCA is computed by converting the trajectory to a trip grid (see :meth:`traja.plotting.trip_grid`) followed by PCA (:class:`sklearn.decomposition.PCA`). + +.. autofunction:: traja.plotting.plot_pca \ No newline at end of file diff --git a/docs/source/collections.rst b/docs/source/collections.rst new file mode 100644 index 00000000..8e4a5135 --- /dev/null +++ b/docs/source/collections.rst @@ -0,0 +1,76 @@ +Trajectory Collections +====================== + +TrajaCollection +------------------- + +When handling multiple trajectories, Traja allows plotting and analysis simultaneously. + +Initialize a :func:`~traja.frame.TrajaCollection` with a dictionary or ``DataFrame`` and ``id_col``. + +Initializing with Dictionary +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The keys of the dictionary can be used to identify types of objects in the scene, eg, "bus", "car", "person":: + + dfs = {"car0":df0, "car1":df1, "bus0: df2, "person0": df3} + + +Or, arbitrary numbers can be used to initialize + +.. autoclass:: traja.frame.TrajaCollection + +.. ipython:: + + from traja import TrajaCollection + + dfs = {idx: traja.generate(idx, seed=idx) for idx in range(10,13)} + trjs = TrajaCollection(dfs) + + print(trjs) + +Initializing with a DataFrame +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A dataframe containing an id column can be passed directly to :func:`~traja.frame.TrajaCollection`, as long as the ``id_col`` is specified:: + + trjs = TrajaCollection(df, id_col="id") + +Grouped Operations +------------------ + +Operations can be applied to each trajectory with :func:`~traja.frame.TrajaCollection.apply_all`. + +.. automethod:: traja.frame.TrajaCollection.apply_all + +Plottting Multiple Trajectories +------------------------------- + +Plotting multiple trajectories can be achieved with :func:`~traja.frame.TrajaCollection.plot`. + +.. automethod:: traja.frame.TrajaCollection.plot + +Colors can be specified for ids by supplying ``colors`` with a lookup dictionary: + +.. ipython:: + + colors = ["10":"red", + "11":"red", + "12":"red", + "13":"orange", + "14":"orange"] + +or with a substring lookup: + + colors = ["car":"red", + "bus":"orange", + "12":"red", + "13":"orange", + "14":"orange"] + + +.. image:: https://raw.githubusercontent.com/justinshenk/traja/master/docs/images/collection_plot.png + + + + diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 00000000..f6df1e1a --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,275 @@ +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os, sys + +sys.path.insert(0, os.path.abspath("../..")) + + +# -- Project information ----------------------------------------------------- + +project = "Traja" +copyright = "2018-2021, Traja developers" +author = "Justin Shenk" + +# The short X.Y version +import traja + +version = release = traja.__version__ + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "IPython.sphinxext.ipython_console_highlighting", + "IPython.sphinxext.ipython_directive", + "matplotlib.sphinxext.plot_directive", + "sphinx.ext.autosummary", + "sphinx.ext.autodoc", + "sphinx.ext.doctest", + "sphinx.ext.mathjax", + "sphinx.ext.napoleon", + "sphinx.ext.viewcode", + "sphinx.ext.inheritance_diagram", + "sphinx.ext.intersphinx", + "sphinx_gallery.gen_gallery" +] + +# continue doc build and only print warnings/errors in examples +ipython_warning_is_error = False + + +doctest_global_setup = """ +import pandas as pd +import traja +""" + +autosummary_generate = True + +# Sphinx gallery configuration +from sphinx_gallery.sorting import FileNameSortKey + +sphinx_gallery_conf = { + "examples_dirs": ["../examples"], + #'filename_pattern': '^((?!sgskip).)*$', + "gallery_dirs": ["gallery"], + "doc_module": ("traja",), + "reference_url": { + # "geopandas": "https://geopandas.readthedocs.io/en/latest/", + # "pandas": "https://geopandas.readthedocs.io/en/latest/", + # "matplotlib": "https://matplotlib.org" + }, + # "plot_gallery": None, + "backreferences_dir": "reference", + "within_subsection_order": FileNameSortKey, +} + +# Napoleon settings +napoleon_google_docstring = True + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = ".rst" + +# The master toctree document. +master_doc = "index" + + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "sphinx" + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = "sphinx_rtd_theme" + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ["_static"] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = "trajadoc" + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, "traja.tex", "traja Documentation", "Justin Shenk", "manual") +] + + +# -- Options for manual page output ------------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [(master_doc, "traja", "traja Documentation", [author], 1)] + + +# -- Options for Texinfo output ---------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, sequence_id) +texinfo_documents = [ + ( + master_doc, + "traja", + "traja Documentation", + author, + "traja", + "One line description of project.", + "Miscellaneous", + ) +] + + +# -- Options for Epub output ------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +# +# epub_identifier = '' + +# A unique identification for the text. +# +# epub_uid = '' + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ["search.html"] + + +# -- Extension configuration ------------------------------------------------- + +# -- Options for intersphinx extension --------------------------------------- + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = { + "python": ("https://docs.python.org", None), + "numpy": ("http://docs.scipy.org/doc/numpy", None), + "matplotlib": ("http://matplotlib.org/stable", None), + "pandas": ( + "https://pandas.pydata.org/pandas-docs/stable/", + "https://pandas.pydata.org/pandas-docs/stable/objects.inv", + ), + "scipy": ("http://docs.scipy.org/doc/scipy/reference", None), + "PyTorch": ("http://pytorch.org/docs/master/", None), +} + +autodoc_member_order = "bysource" + +def setup(app): + """ + Enable documenting 'special methods' using the autodoc_ extension. + :param app: The Sphinx application object. + This function connects the :func:`special_methods_callback()` function to + ``autodoc-skip-member`` events. + .. _autodoc: http://www.sphinx-doc.org/en/stable/ext/autodoc.html + """ + app.connect("autodoc-skip-member", special_methods_callback) + + +def special_methods_callback(app, what, name, obj, skip, options): + """ + Enable documenting 'special methods' using the autodoc_ extension. + Refer to :func:`enable_special_methods()` to enable the use of this + function (you probably don't want to call + :func:`special_methods_callback()` directly). + This function implements a callback for ``autodoc-skip-member`` events to + include documented 'special methods' (method names with two leading and two + trailing underscores) in your documentation. The result is similar to the + use of the ``special-members`` flag with one big difference: Special + methods are included but other types of members are ignored. This means + that attributes like ``__weakref__`` will always be ignored (this was my + main annoyance with the ``special-members`` flag). + The parameters expected by this function are those defined for Sphinx event + callback functions (i.e. I'm not going to document them here :-). + """ + import types + + if getattr(obj, "__doc__", None) and isinstance( + obj, (types.FunctionType, types.MethodType) + ): + return False + else: + return skip + + +# Tell sphinx what the primary language being documented is. +primary_domain = "py" + +# Tell sphinx what the pygments highlight language should be. +highlight_language = "py" diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst new file mode 100644 index 00000000..2a08464a --- /dev/null +++ b/docs/source/contributing.rst @@ -0,0 +1,272 @@ +Contributing to traja +===================== + +(Contribution guidelines largely copied from `geopandas `_) + +Overview +-------- + +Contributions to traja are very welcome. They are likely to +be accepted more quickly if they follow these guidelines. + +At this stage of traja development, the priorities are to define a +simple, usable, and stable API and to have clean, maintainable, +readable code. Performance matters, but not at the expense of those +goals. + +In general, traja follows the conventions of the pandas project +where applicable. + +In particular, when submitting a pull request: + +- All existing tests should pass. Please make sure that the test + suite passes, both locally and on + `Travis CI `_. Status on + Travis will be visible on a pull request. If you want to enable + Travis CI on your own fork, please read the pandas guidelines link + above or the + `getting started docs `_. + +- New functionality should include tests. Please write reasonable + tests for your code and make sure that they pass on your pull request. + +- Classes, methods, functions, etc. should have docstrings. The first + line of a docstring should be a standalone summary. Parameters and + return values should be ducumented explicitly. + +- traja supports python 3 (3.6+). Use modern python idioms when possible. + +- Follow PEP 8 when possible. + +- Imports should be grouped with standard library imports first, + 3rd-party libraries next, and traja imports third. Within each + grouping, imports should be alphabetized. Always use absolute + imports when possible, and explicit relative imports for local + imports when necessary in tests. + + +Seven Steps for Contributing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There are seven basic steps to contributing to *traja*: + +1) Fork the *traja* git repository +2) Create a development environment +3) Install *traja* dependencies +4) Make a ``development`` build of *traja* +5) Make changes to code and add tests +6) Update the documentation +7) Submit a Pull Request + +Each of these 7 steps is detailed below. + + +1) Forking the *traja* repository using Git +------------------------------------------------ + +To the new user, working with Git is one of the more daunting aspects of contributing to *traja**. +It can very quickly become overwhelming, but sticking to the guidelines below will help keep the process +straightforward and mostly trouble free. As always, if you are having difficulties please +feel free to ask for help. + +The code is hosted on `GitHub `_. To +contribute you will need to sign up for a `free GitHub account +`_. We use `Git `_ for +version control to allow many people to work together on the project. + +Some great resources for learning Git: + +* Software Carpentry's `Git Tutorial `_ +* `Atlassian `_ +* the `GitHub help pages `_. +* Matthew Brett's `Pydagogue `_. + +Getting started with Git +~~~~~~~~~~~~~~~~~~~~~~~~~ + +`GitHub has instructions `__ for installing git, +setting up your SSH key, and configuring git. All these steps need to be completed before +you can work seamlessly between your local repository and GitHub. + +.. _contributing.forking: + +Forking +~~~~~~~~ + +You will need your own fork to work on the code. Go to the `traja project +page `_ and hit the ``Fork`` button. You will +want to clone your fork to your machine:: + + git clone git@github.com:your-user-name/traja.git traja-yourname + cd traja-yourname + git remote add upstream git://github.com/traja-team/traja.git + +This creates the directory `traja-yourname` and connects your repository to +the upstream (main project) *traja* repository. + +The testing suite will run automatically on Travis-CI once your pull request is +submitted. However, if you wish to run the test suite on a branch prior to +submitting the pull request, then Travis-CI needs to be hooked up to your +GitHub repository. Instructions for doing so are `here +`__. + +Creating a branch +~~~~~~~~~~~~~~~~~~ + +You want your master branch to reflect only production-ready code, so create a +feature branch for making your changes. For example:: + + git branch shiny-new-feature + git checkout shiny-new-feature + +The above can be simplified to:: + + git checkout -b shiny-new-feature + +This changes your working directory to the shiny-new-feature branch. Keep any +changes in this branch specific to one bug or feature so it is clear +what the branch brings to *traja*. You can have many shiny-new-features +and switch in between them using the git checkout command. + +To update this branch, you need to retrieve the changes from the master branch:: + + git fetch upstream + git rebase upstream/master + +This will replay your commits on top of the latest traja git master. If this +leads to merge conflicts, you must resolve these before submitting your pull +request. If you have uncommitted changes, you will need to ``stash`` them prior +to updating. This will effectively store your changes and they can be reapplied +after updating. + +.. _contributing.dev_env: + +2) Creating a development environment +--------------------------------------- +A development environment is a virtual space where you can keep an independent installation of *traja*. +This makes it easy to keep both a stable version of python in one place you use for work, and a development +version (which you may break while playing with code) in another. + +An easy way to create a *traja* development environment is as follows: + +- Install either `Anaconda `_ or + `miniconda `_ +- Make sure that you have :ref:`cloned the repository ` +- ``cd`` to the *traja** source directory + +Tell conda to create a new environment, named ``traja_dev``, or any other name you would like +for this environment, by running:: + + conda create -n traja_dev + +For a python 3 environment:: + + conda create -n traja_dev python=3.8 + +This will create the new environment, and not touch any of your existing environments, +nor any existing python installation. + +To work in this environment, Windows users should ``activate`` it as follows:: + + activate traja_dev + +Mac OSX and Linux users should use:: + + source activate traja_dev + +You will then see a confirmation message to indicate you are in the new development environment. + +To view your environments:: + + conda info -e + +To return to you home root environment:: + + deactivate + +See the full conda docs `here `__. + +At this point you can easily do a *development* install, as detailed in the next sections. + +3) Installing Dependencies +-------------------------- + +To run *traja* in an development environment, you must first install +*traja*'s dependencies. We suggest doing so using the following commands +(executed after your development environment has been activated):: + + conda install -c conda-forge shapely + pip install -r requirements/dev.txt + +This should install all necessary dependencies. + +Next activate pre-commit hooks by running:: + + pre-commit install + +4) Making a development build +----------------------------- + +Once dependencies are in place, make an in-place build by navigating to the git +clone of the *traja* repository and running:: + + python setup.py develop + + +5) Making changes and writing tests +------------------------------------- + +*traja* is serious about testing and strongly encourages contributors to embrace +`test-driven development (TDD) `_. +This development process "relies on the repetition of a very short development cycle: +first the developer writes an (initially failing) automated test case that defines a desired +improvement or new function, then produces the minimum amount of code to pass that test." +So, before actually writing any code, you should write your tests. Often the test can be +taken from the original GitHub issue. However, it is always worth considering additional +use cases and writing corresponding tests. + +Adding tests is one of the most common requests after code is pushed to *traja*. Therefore, +it is worth getting in the habit of writing tests ahead of time so this is never an issue. + +*traja* uses the `pytest testing system +`_ and the convenient +extensions in `numpy.testing +`_. + +Writing tests +~~~~~~~~~~~~~ + +All tests should go into the ``tests`` directory. This folder contains many +current examples of tests, and we suggest looking to these for inspiration. + + +Running the test suite +~~~~~~~~~~~~~~~~~~~~~~ + +The tests can then be run directly inside your Git clone (without having to +install *traja*) by typing:: + + pytest + +6) Updating the Documentation +----------------------------- + +*traja* documentation resides in the `doc` folder. Changes to the docs are +make by modifying the appropriate file in the `source` folder within `doc`. +*traja* docs us reStructuredText syntax, `which is explained here `_ +and the docstrings follow the `Numpy Docstring standard `_. + +Once you have made your changes, you can build the docs by navigating to the `doc` folder and typing:: + + make html + +The resulting html pages will be located in `doc/build/html`. + + +7) Submitting a Pull Request +------------------------------ + +Once you've made changes and pushed them to your forked repository, you then +submit a pull request to have them integrated into the *traja* code base. + +You can find a pull request (or PR) tutorial in the `GitHub's Help Docs `_. diff --git a/docs/source/generate.rst b/docs/source/generate.rst new file mode 100644 index 00000000..9a1131a4 --- /dev/null +++ b/docs/source/generate.rst @@ -0,0 +1,16 @@ +Generate Random Walk +==================== + +Random walks can be generated using :func:`~traja.trajectory.generate`. + + +.. ipython:: python :okwarning: + + import traja + + # Generate random walk + df = traja.generate(1000) + +.. autofunction:: traja.trajectory.generate + +.. image:: https://raw.githubusercontent.com/justinshenk/traja/master/docs/source/_static/walk_screenshot.png diff --git a/docs/source/grid_cell.rst b/docs/source/grid_cell.rst new file mode 100644 index 00000000..f5961eec --- /dev/null +++ b/docs/source/grid_cell.rst @@ -0,0 +1,73 @@ +Plotting Grid Cell Flow +======================= + +Trajectories can be discretized into grid cells and the average flow from +each grid cell to its neighbor can be plotted with :func:`~traja.plotting.plot_flow`, eg: + +.. code-block:: python + + traja.plot_flow(df, kind='stream') + +:func:`~traja.plotting.plot_flow` ``kind`` Arguments +---------------------------------------------------- + +* `surface` - 3D surface plot extending :meth:`mpl_toolkits.mplot3D.Axes3D.plot_surface`` +* `contourf` - Filled contour plot extending :meth:`matplotlib.axes.Axes.contourf` +* `quiver` - Quiver plot extending :meth:`matplotlib.axes.Axes.quiver` +* `stream` - Stream plot extending :meth:`matplotlib.axes.Axes.streamplot` + +See the :ref:`gallery` for more examples. + +3D Surface Plot +--------------- + +.. autofunction:: traja.plotting.plot_surface + +.. image:: https://traja.readthedocs.io/en/latest/_images/sphx_glr_plot_average_direction_001.png + :alt: 3D plot + +Quiver Plot +----------- + +.. autofunction:: traja.plotting.plot_quiver + +.. code-block:: python + + traja.plot_quiver(df, bins=32) + +.. image:: https://traja.readthedocs.io/en/latest/_images/sphx_glr_plot_average_direction_002.png + :alt: quiver plot + +Contour Plot +------------ + +.. autofunction:: traja.plotting.plot_contour + +.. code-block:: python + + traja.plot_contour(df, filled=False, quiver=False, bins=32) + +.. image:: https://traja.readthedocs.io/en/latest/_images/sphx_glr_plot_average_direction_003.png + :alt: contour plot + +Contour Plot (Filled) +--------------------- + +.. code-block:: python + + traja.plot_contour(df, filled=False, quiver=False, bins=32) + +.. image:: https://traja.readthedocs.io/en/latest/_images/sphx_glr_plot_average_direction_004.png + :alt: contour plot filled + +Stream Plot +----------- + +.. autofunction:: traja.plotting.plot_stream + +.. code-block:: python + + traja.plot_contour(df, bins=32, contourfplot_kws={'cmap':'coolwarm'}) + +.. image:: https://traja.readthedocs.io/en/latest/_images/sphx_glr_plot_average_direction_005.png + :alt: streamplot diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 00000000..8bbcddf0 --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,95 @@ +.. traja documentation master file, created by + sphinx-quickstart on Mon Jan 28 23:36:32 2019. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +traja |version| +=============== + +Trajectory Analysis in Python + +Traja allows analyzing trajectory datasets using a wide range of tools, including pandas and R. +Traja extends the capability of pandas :class:`~pandas.DataFrame` specific for animal or object trajectory +analysis in 2D, and provides convenient interfaces to other geometric analysis packages (eg, shapely). + +Description +----------- + +The Traja Python package is a toolkit for the numerical characterization and analysis +of the trajectories of moving animals. Trajectory analysis is applicable in fields as +diverse as optimal foraging theory, migration, and behavioural mimicry +(e.g. for verifying similarities in locomotion). +A trajectory is simply a record of the path followed by a moving object. +Traja operates on trajectories in the form of a series of locations (as x, y coordinates) with times. +Trajectories may be obtained by any method which provides this information, +including manual tracking, radio telemetry, GPS tracking, and motion tracking from videos. + +The goal of this package (and this document) is to aid biological researchers, who may not have extensive +experience with Python, to analyse trajectories +without being restricted by a limited knowledge of Python or programming. +However, a basic understanding of Python is useful. + +If you use Traja in your publications, please cite our paper_ in Journal of Open Source +Software: + +.. code-block:: txt + + @article{Shenk2021, + doi = {10.21105/joss.03202}, + url = {https://doi.org/10.21105/joss.03202}, + year = {2021}, + publisher = {The Open Journal}, + volume = {6}, + number = {63}, + pages = {3202}, + author = {Justin Shenk and Wolf Byttner and Saranraj Nambusubramaniyan and Alexander Zoeller}, + title = {Traja: A Python toolbox for animal trajectory analysis}, + journal = {Journal of Open Source Software} + } + +.. _paper: https://joss.theoj.org/papers/10.21105/joss.03202 + +.. toctree:: + :maxdepth: 1 + :caption: Getting Started + + Installation + Examples Gallery + +.. toctree:: + :maxdepth: 2 + :caption: User Guide + + Reading and Writing Files + Pandas Indexing and Resampling + Generate Random Walk + Smoothing and Analysis + Turns + Plotting Paths + Periodicity + Plotting Grid Cell Flow + Rediscretizing Trajectories + Clustering and Dimensionality Reduction + Collections / Scenes + Predicting Trajectories + +.. toctree:: + :maxdepth: 1 + :caption: Reference Guide + + Reference to All Attributes and Methods + Bugs and Support + +.. toctree:: + :maxdepth: 1 + :caption: Developer + + Contributing to Traja + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/source/install.rst b/docs/source/install.rst new file mode 100644 index 00000000..d3e75d15 --- /dev/null +++ b/docs/source/install.rst @@ -0,0 +1,51 @@ +Installation +============ + +Installing traja +---------------- + +traja requires Python 3.6+ to be installed. For installing on Windows, +it is recommend to download and install via conda_. + +To install via conda:: + + conda install -c conda-forge traja + +To install via pip:: + + pip install traja + +To install the latest development version, clone the `GitHub` repository and use the setup script:: + + git clone https://github.com/traja-team/traja.git + cd traja + pip install . + +Dependencies +------------ + +Installation with pip should also include all dependencies, but a complete list is + +- numpy_ +- matplotlib_ +- scipy_ +- pandas_ + +To install all optional dependencies run:: + + pip install 'traja[all]' + + +.. _GitHub: https://github.com/justinshenk/github + +.. _numpy: http://www.numpy.org + +.. _pandas: http://pandas.pydata.org + +.. _scipy: https://docs.scipy.org/doc/scipy/reference/ + +.. _shapely: http://toblerity.github.io/shapely + +.. _matplotlib: http://matplotlib.org + +.. _conda: https://docs.conda.io/en/latest/ \ No newline at end of file diff --git a/docs/source/pandas.rst b/docs/source/pandas.rst new file mode 100644 index 00000000..05c14a8e --- /dev/null +++ b/docs/source/pandas.rst @@ -0,0 +1,36 @@ +Pandas Indexing and Resampling +============================== + +Traja is built on top of pandas :class:`~pandas.DataFrame`, giving access to low-level pandas indexing functions. + +This allows indexing, resampling, etc., just as in pandas:: + + from traja import generate, plot + import pandas as pd + + # Generate random walk + df = generate(n=1000, fps=30) + + # Select every second row + df[::2] + + Output: + x y time + 0 0.000000 0.000000 0.000000 + 2 2.364589 3.553398 0.066667 + 4 0.543251 6.347378 0.133333 + 6 -3.307575 5.404562 0.200000 + 8 -6.697132 3.819403 0.266667 + +You can also do resampling to select average coordinate every second, for example:: + + # Convert 'time' column to timedelta + df.time = pd.to_timedelta(df.time, unit='s') + df = df.set_index('time') + + # Resample with average for every second + resampled = df.resample('S').mean() + plot(resampled) + +.. image:: https://raw.githubusercontent.com/justinshenk/traja/master/docs/source/_static/resampled.png + diff --git a/docs/source/periodicity.rst b/docs/source/periodicity.rst new file mode 100644 index 00000000..9298b051 --- /dev/null +++ b/docs/source/periodicity.rst @@ -0,0 +1,18 @@ +Periodicity +=========== + +Several methods for analyzing periodicity are included. + +Autocorrelation +--------------- + +Autocorrelation is plotted using :meth:`pandas.plotting.autocorrelation_plot`. + +.. autofunction:: traja.plotting.plot_autocorrelation + +Periodogram (Power Spectum) +--------------------------- + +Convenience wrapper for :meth:`scipy.signal.periodogram`. + +.. autofunction:: traja.plotting.plot_periodogram \ No newline at end of file diff --git a/docs/source/plots.rst b/docs/source/plots.rst new file mode 100644 index 00000000..11b03b99 --- /dev/null +++ b/docs/source/plots.rst @@ -0,0 +1,67 @@ +.. ipython:: python :okwarning: + :suppress: + + import matplotlib + import pandas as pd + from traja.plotting import trip_grid + orig = matplotlib.rcParams['figure.figsize'] + matplotlib.rcParams['figure.figsize'] = [orig[0] * 1.5, orig[1]] + import matplotlib.pyplot as plt + plt.close('all') + + +Plotting Paths +============== + +Making plots of trajectories is easy using the :meth:`~traja.accessor.TrajaAccessor.plot` method. + +See the :ref:`gallery` for more examples. + +.. automodule:: traja.plotting + :members: bar_plot, plot, plot_quiver, plot_contour, plot_surface, plot_stream, plot_flow, plot_actogram, polar_bar + +Trip Grid +--------- + +Trip grid can be plotted for :class:`~traja.frame.TrajaDataFrame`s with :func:`~traja.accessor.TrajaAccessor.trip_grid`: + +.. ipython:: python :okwarning: + + import traja + from traja import trip_grid + + df = traja.TrajaDataFrame({'x':range(10),'y':range(10)}) + @savefig trip_grid.png + hist, image = trip_grid(df); + + +If only the histogram is need for further computation, use the `hist_only` option: + +.. ipython:: python + + hist, _ = trip_grid(df, hist_only=True) + print(hist[:5]) + + +Highly dense plots be more easily visualized using the `bins` and `log` argument: + +.. ipython:: python :okwarning: + + # Generate random walk + df = traja.generate(1000) + + @savefig trip_grid_log.png + trip_grid(df, bins=32, log=True); + +The plot can also be normalized into a density function with `normalize`: + +.. ipython:: python :okwarning: + + @savefig trip_grid_normalized.png + hist, _ = trip_grid(df, normalize=True); + + +Animate +------- + +.. autofunction:: traja.plotting.animate \ No newline at end of file diff --git a/docs/source/predictions.rst b/docs/source/predictions.rst new file mode 100644 index 00000000..a05d60a4 --- /dev/null +++ b/docs/source/predictions.rst @@ -0,0 +1,160 @@ +Predicting Trajectories +======================= + +Predicting trajectories with traja can be done with a recurrent neural network (RNN). Traja includes +the Long Short Term Memory (LSTM), LSTM Autoencoder (LSTM AE) and LSTM Variational Autoencoder (LSTM VAE) +RNNs. Traja also supports custom RNNs. + +To model a trajectory using RNNs, one needs to fit the network to the model. Traja includes the MultiTaskRNNTrainer +that can solve a prediction, classification and regression problem with traja DataFrames. + +`Traja` also includes a DataLoader that handles traja dataframes. + +Below is an example with a prediction LSTM via :py:class:`traja.models.predictive_models.lstm.LSTM`. + +.. code-block:: python + + import traja + + df = traja.dataset.example.jaguar() + +.. note:: + LSTMs work better with data between -1 and 1. Therefore the data loader + scales the data. + +.. code-block:: python + + batch_size = 10 # How many sequences to train every step. Constrained by GPU memory. + num_past = 10 # How many time steps from which to learn the time series + num_future = 10 # How many time steps to predict + split_by_id = False # Whether to split data into training, test and validation sets based on + # the animal's ID or not. If True, an animal's entire trajectory will only + # be used for training, or only for testing and so on. + # If your animals are territorial (like Jaguars) and you want to forecast + # their trajectories, you want this to be false. If, however, you want to + # classify the group membership of an animal, you want this to be true, + # so that you can verify that previously unseen animals get assigned to + # the correct class. + + +.. autoclass:: traja.models.predictive_models.lstm.LSTM + :members: + + dataloaders = traja.dataset.MultiModalDataLoader(df, + batch_size=batch_size, + n_past=num_past, + n_future=num_future, + num_workers=0, + split_by_id=split_by_id) + +.. note:: + + The width of the hidden layers and depth of the network are the two main ways in which + one tunes the performance of the network. More complex datasets require wider and deeper + networks. Below are sensible defaults. + +.. code-block:: python + + from traja.models.predictive_models.lstm import LSTM + input_size = 2 # Number of input dimensions (normally x, y) + output_size = 2 # Same as input_size when predicting + num_layers = 2 # Number of LSTM layers. Deeper learns more complex patterns but overfits. + hidden_size = 32 # Width of layers. Wider learns bigger patterns but overfits. Try 32, 64, 128, 256, 512 + dropout = 0.1 # Ignore some network connections. Improves generalisation. + + model = LSTM(input_size=input_size, + hidden_size=hidden_size, + num_layers=num_layers, + output_size=output_size, + dropout=dropout, + batch_size=batch_size) + +.. code-block:: python + + from traja.models.train import HybridTrainer + + optimizer_type = 'Adam' # Nonlinear optimiser with momentum + loss_type = 'huber' + + # Trainer + trainer = HybridTrainer(model=model, + optimizer_type=optimizer_type, + loss_type=loss_type) + # Train the model + trainer.fit(dataloaders, model_save_path='./model.pt', epochs=10, training_mode='forecasting') + +After training, you can determine the network's final performance with test data, if you want to pick +the best model, or with validation data, if you want to determine the performance of your model. + +The ``dataloaders`` dictionary contains the ``sequential_test_loader`` and ``sequential_validation_loader``, +that preserve the order of the original data. The dictionary also contains the 'test_loader' and +``validation_loader`` data loaders, where the order of the time series is randomised. + +.. code-block:: python + + validation_loader = dataloaders['sequential_validation_loader'] + + trainer.validate(validation_loader) + +Finally, you can display your training results using the built-in plotting libraries. + +.. code-block:: python + + from traja.plotting import plot_prediction + + batch_index = 0 # The batch you want to plot + plot_prediction(model, validation_loader, batch_index) + +.. image:: _static/rnn_prediction.png + +Parameter searching +------------------- + +When optimising neural networks, you often want to change the parameters. When training a forecaster, +you have to reinitialise and retrain your model. However, when training a classifier or regressor, you +can reset these on the fly, since they work directly on the latent space of your model. +VAE models provide utility functions to make this easy. + +.. code-block:: python + + from traja.models import MultiModelVAE + input_size = 2 # Number of input dimensions (normally x, y) + output_size = 2 # Same as input_size when predicting + num_layers = 2 # Number of LSTM layers. Deeper learns more complex patterns but overfits. + hidden_size = 32 # Width of layers. Wider learns bigger patterns but overfits. Try 32, 64, 128, 256, 512 + dropout = 0.1 # Ignore some network connections. Improves generalisation. + + # Classifier parameters + classifier_hidden_size = 32 + num_classifier_layers = 4 + num_classes = 42 + + # Regressor parameters + regressor_hidden_size = 18 + num_regressor_layers = 1 + num_regressor_parameters = 3 + + model = MultiModelVAE(input_size=input_size, + hidden_size=hidden_size, + num_layers=num_layers, + output_size=output_size, + dropout=dropout, + batch_size=batch_size, + num_future=num_future, + classifier_hidden_size=classifier_hidden_size, + num_classifier_layers=num_classifier_layers, + num_classes=num_classes, + regressor_hidden_size=regressor_hidden_size, + num_regressor_layers=num_regressor_layers, + num_regressor_parameters=num_regressor_parameters) + + new_classifier_hidden_size = 64 + new_num_classifier_layers = 2 + + model.reset_classifier(classifier_hidden_size=new_classifier_hidden_size, + num_classifier_layers=new_num_classifier_layers) + + new_regressor_hidden_size = 64 + new_num_regressor_layers = 2 + model.reset_regressor(regressor_hidden_size=new_regressor_hidden_size, + num_regressor_layers=new_num_regressor_layers) \ No newline at end of file diff --git a/docs/source/reading.rst b/docs/source/reading.rst new file mode 100644 index 00000000..00325e02 --- /dev/null +++ b/docs/source/reading.rst @@ -0,0 +1,57 @@ +Reading and Writing Files +========================= + +Reading trajectory data +----------------------- + +traja allows reading files via :func:`traja.parsers.read_file`. For example a CSV file ``trajectory.csv`` with the +following contents:: + + + x,y + 1,1 + 1,2 + 1,3 + +Could be read in like: + +.. code-block:: python + + import traja + + df = traja.read_file('trajectory.csv') + +``read_file`` returns a `TrajaDataFrame` with access to all pandas and traja methods. + +.. automodule:: traja.accessor + .. automethod:: + +Any keyword arguments passed to `read_file` will be passed to :meth:`pandas.read_csv`. + +Data frames can also be read with pandas :func:`pandas.read_csv` and then converted to TrajaDataFrames +with: + +.. code-block:: python + + import traja + import pandas as pd + + df = pd.read_csv('data.csv') + + # If x and y columns are named different than "x" and "y", rename them, eg: + df = df.rename(columns={"x_col": "x", "y_col": "y"}) # original column names x_col, y_col + + # If the time column doesn't include "time" in the name, similarly rename it to "time" + + trj = traja.TrajaDataFrame(df) + + + +Writing trajectory data +----------------------- + +Files can be saved using the built-in pandas :func:`pandas.to_csv`. + +.. code-block:: python + + df.to_csv('trajectory.csv') diff --git a/docs/source/rediscretize.rst b/docs/source/rediscretize.rst new file mode 100644 index 00000000..f23c7ca6 --- /dev/null +++ b/docs/source/rediscretize.rst @@ -0,0 +1,74 @@ +Resampling Trajectories +======================= + +Rediscretize +------------ +Rediscretize the trajectory into consistent step lengths with :meth:`~traja.trajectory.rediscretize` where the `R` parameter is +the new step length. + +.. note:: + + Based on the appendix in Bovet and Benhamou, (1988) and Jim McLean's + `trajr `_ implementation. + + +Resample time +------------- +:meth:`~traja.trajectory.resample_time` allows resampling trajectories by a ``step_time``. + +.. autofunction:: traja.trajectory.resample_time + + +For example: + +.. ipython:: python :okwarning: + + import traja + + # Generate a random walk + df = traja.generate(n=1000) # Time is in 0.02-second intervals + df.head() + +.. ipython:: python :okwarning: + + resampled = traja.resample_time(df, "50L") # 50 milliseconds + resampled.head() + + fig = resampled.traja.plot() + +.. image:: https://raw.githubusercontent.com/justinshenk/traja/master/docs/images/resampled.png + + +Ramerā€“Douglasā€“Peucker algorithm +------------------------------- + +.. note:: + + Graciously yanked from Fabian Hirschmann's PyPI package ``rdp``. + +:func:`~traja.contrib.rdp` reduces the number of points in a line using the Ramerā€“Douglasā€“Peucker algorithm:: + + from traja.contrib import rdp + + # Create dataframe of 1000 x, y coordinates + df = traja.generate(n=1000) + + # Extract xy coordinates + xy = df.traja.xy + + # Reduce points with epsilon between 0 and 1: + xy_ = rdp(xy, epsilon=0.8) + + + len(xy_) + + Output: + 317 + +Plotting, we can now see the many fewer points are needed to cover a similar area.:: + + df = traja.from_xy(xy_) + df.traja.plot() + +.. image:: https://raw.githubusercontent.com/justinshenk/traja/master/docs/source/_static/after_rdp.png + diff --git a/docs/source/reference.rst b/docs/source/reference.rst new file mode 100644 index 00000000..507d3e85 --- /dev/null +++ b/docs/source/reference.rst @@ -0,0 +1,182 @@ +Reference +============= + +Accessor Methods +---------------- + +The following methods are available via :class:`traja.accessor.TrajaAccessor`: + +.. automodule:: traja.accessor + :members: + :undoc-members: + :noindex: + +Plotting functions +------------------ + +The following methods are available via :mod:`traja.plotting`: + +.. automethod:: traja.plotting.animate + +.. automethod:: traja.plotting.bar_plot + +.. automethod:: traja.plotting.color_dark + +.. automethod:: traja.plotting.fill_ci + +.. automethod:: traja.plotting.find_runs + +.. automethod:: traja.plotting.plot + +.. automethod:: traja.plotting.plot_3d + +.. automethod:: traja.plotting.plot_actogram + +.. automethod:: traja.plotting.plot_autocorrelation + +.. automethod:: traja.plotting.plot_contour + +.. automethod:: traja.plotting.plot_clustermap + +.. automethod:: traja.plotting.plot_flow + +.. automethod:: traja.plotting.plot_quiver + +.. automethod:: traja.plotting.plot_stream + +.. automethod:: traja.plotting.plot_surface + +.. automethod:: traja.plotting.plot_transition_matrix + +.. automethod:: traja.plotting.plot_xy + +.. automethod:: traja.plotting.polar_bar + +.. automethod:: traja.plotting.plot_prediction + +.. automethod:: traja.plotting.sans_serif + +.. automethod:: traja.plotting.stylize_axes + +.. automethod:: traja.plotting.trip_grid + + +Analysis +-------- + +The following methods are available via :mod:`traja.trajectory`: + +.. automethod:: traja.trajectory.angles + +.. automethod:: traja.trajectory.calc_angle + +.. automethod:: traja.trajectory.calc_convex_hull + +.. automethod:: traja.trajectory.calc_derivatives + +.. automethod:: traja.trajectory.calc_displacement + +.. automethod:: traja.trajectory.calc_heading + +.. automethod:: traja.trajectory.calc_turn_angle + +.. automethod:: traja.trajectory.calc_flow_angles + +.. automethod:: traja.trajectory.cartesian_to_polar + +.. automethod:: traja.trajectory.coords_to_flow + +.. automethod:: traja.trajectory.determine_colinearity + +.. automethod:: traja.trajectory.distance_between + +.. automethod:: traja.trajectory.distance + +.. automethod:: traja.trajectory.euclidean + +.. automethod:: traja.trajectory.expected_sq_displacement + +.. automethod:: traja.trajectory.fill_in_traj + +.. automethod:: traja.trajectory.from_xy + +.. automethod:: traja.trajectory.generate + +.. automethod:: traja.trajectory.get_derivatives + +.. automethod:: traja.trajectory.grid_coordinates + +.. automethod:: traja.trajectory.inside + +.. automethod:: traja.trajectory.length + +.. automethod:: traja.trajectory.polar_to_z + +.. automethod:: traja.trajectory.rediscretize_points + +.. automethod:: traja.trajectory.resample_time + +.. automethod:: traja.trajectory.return_angle_to_point + +.. automethod:: traja.trajectory.rotate + +.. automethod:: traja.trajectory.smooth_sg + +.. automethod:: traja.trajectory.speed_intervals + +.. automethod:: traja.trajectory.step_lengths + +.. automethod:: traja.trajectory.to_shapely + +.. automethod:: traja.trajectory.traj_from_coords + +.. automethod:: traja.trajectory.transition_matrix + +.. automethod:: traja.trajectory.transitions + +io functions +------------ + +The following methods are available via :mod:`traja.parsers`: + +.. automethod:: traja.parsers.read_file + +.. automethod:: traja.parsers.from_df + + +TrajaDataFrame +-------------- + +A ``TrajaDataFrame`` is a tabular data structure that contains ``x``, ``y``, and ``time`` columns. + +All pandas ``DataFrame`` methods are also available, although they may +not operate in a meaningful way on the ``x``, ``y``, and ``time`` columns. + +Inheritance diagram: + +.. inheritance-diagram:: traja.TrajaDataFrame + +TrajaCollection +--------------- + +A ``TrajaCollection`` holds multiple trajectories for analyzing and comparing trajectories. +It has limited accessibility to lower-level methods. + +.. autoclass:: traja.frame.TrajaCollection + +.. automethod:: traja.frame.TrajaCollection.apply_all + +.. automethod:: traja.frame.TrajaCollection.plot + + +API Pages +--------- + +.. currentmodule:: traja +.. autosummary:: + :template: autosummary.rst + :toctree: reference/ + + TrajaDataFrame + TrajaCollection + read_file diff --git a/docs/source/reference/traja.DataFrame.examples b/docs/source/reference/traja.DataFrame.examples new file mode 100644 index 00000000..b2446169 --- /dev/null +++ b/docs/source/reference/traja.DataFrame.examples @@ -0,0 +1,22 @@ + + +Examples using ``traja.DataFrame`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. raw:: html + +
+ +.. only:: html + + .. figure:: /gallery/images/thumb/sphx_glr_plot_test_thumb.png + + :ref:`sphx_glr_gallery_plot_test.py` + +.. raw:: html + +
+ +.. only:: not html + + * :ref:`sphx_glr_gallery_plot_test.py` diff --git a/docs/source/reference/traja.TrajaDataFrame.examples b/docs/source/reference/traja.TrajaDataFrame.examples new file mode 100644 index 00000000..25ecf49e --- /dev/null +++ b/docs/source/reference/traja.TrajaDataFrame.examples @@ -0,0 +1,23 @@ + + +Examples using ``traja.TrajaDataFrame`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. raw:: html + +
+ +.. only:: html + + .. figure:: /gallery/images/thumb/sphx_glr_plot_animate_thumb.png + :alt: Animate trajectories + + :ref:`sphx_glr_gallery_plot_animate.py` + +.. raw:: html + +
+ +.. only:: not html + + * :ref:`sphx_glr_gallery_plot_animate.py` diff --git a/docs/source/reference/traja.accessor.TrajaAccessor._check_has_time.examples b/docs/source/reference/traja.accessor.TrajaAccessor._check_has_time.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.accessor.TrajaAccessor._rediscretize_points.examples b/docs/source/reference/traja.accessor.TrajaAccessor._rediscretize_points.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.accessor.TrajaAccessor.between.examples b/docs/source/reference/traja.accessor.TrajaAccessor.between.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.accessor.TrajaAccessor.calc_angle.examples b/docs/source/reference/traja.accessor.TrajaAccessor.calc_angle.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.accessor.TrajaAccessor.calc_derivatives.examples b/docs/source/reference/traja.accessor.TrajaAccessor.calc_derivatives.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.accessor.TrajaAccessor.calc_displacement.examples b/docs/source/reference/traja.accessor.TrajaAccessor.calc_displacement.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.accessor.TrajaAccessor.calc_heading.examples b/docs/source/reference/traja.accessor.TrajaAccessor.calc_heading.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.accessor.TrajaAccessor.calc_turn_angle.examples b/docs/source/reference/traja.accessor.TrajaAccessor.calc_turn_angle.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.accessor.TrajaAccessor.day.examples b/docs/source/reference/traja.accessor.TrajaAccessor.day.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.accessor.TrajaAccessor.examples b/docs/source/reference/traja.accessor.TrajaAccessor.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.accessor.TrajaAccessor.get_derivatives.examples b/docs/source/reference/traja.accessor.TrajaAccessor.get_derivatives.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.accessor.TrajaAccessor.get_time_col.examples b/docs/source/reference/traja.accessor.TrajaAccessor.get_time_col.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.accessor.TrajaAccessor.night.examples b/docs/source/reference/traja.accessor.TrajaAccessor.night.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.accessor.TrajaAccessor.plot.examples b/docs/source/reference/traja.accessor.TrajaAccessor.plot.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.accessor.TrajaAccessor.rediscretize.examples b/docs/source/reference/traja.accessor.TrajaAccessor.rediscretize.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.accessor.TrajaAccessor.scale.examples b/docs/source/reference/traja.accessor.TrajaAccessor.scale.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.accessor.TrajaAccessor.set.examples b/docs/source/reference/traja.accessor.TrajaAccessor.set.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.accessor.TrajaAccessor.speed_intervals.examples b/docs/source/reference/traja.accessor.TrajaAccessor.speed_intervals.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.accessor.TrajaAccessor.to_shapely.examples b/docs/source/reference/traja.accessor.TrajaAccessor.to_shapely.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.accessor.TrajaAccessor.trip_grid.examples b/docs/source/reference/traja.accessor.TrajaAccessor.trip_grid.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.accessor.TrajaAccessor.xy.examples b/docs/source/reference/traja.accessor.TrajaAccessor.xy.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.accessor.examples b/docs/source/reference/traja.accessor.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.examples b/docs/source/reference/traja.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.generate.examples b/docs/source/reference/traja.generate.examples new file mode 100644 index 00000000..80bd498b --- /dev/null +++ b/docs/source/reference/traja.generate.examples @@ -0,0 +1,23 @@ + + +Examples using ``traja.generate`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. raw:: html + +
+ +.. only:: html + + .. figure:: /gallery/images/thumb/sphx_glr_animate_thumb.png + :alt: Animate trajectories + + :ref:`sphx_glr_gallery_animate.py` + +.. raw:: html + +
+ +.. only:: not html + + * :ref:`sphx_glr_gallery_animate.py` diff --git a/docs/source/reference/traja.main.TrajaDataFrame.__finalize__.examples b/docs/source/reference/traja.main.TrajaDataFrame.__finalize__.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.main.TrajaDataFrame.copy.examples b/docs/source/reference/traja.main.TrajaDataFrame.copy.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.main.TrajaDataFrame.examples b/docs/source/reference/traja.main.TrajaDataFrame.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.main.examples b/docs/source/reference/traja.main.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.main.main.examples b/docs/source/reference/traja.main.main.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/reference/traja.main.parse_arguments.examples b/docs/source/reference/traja.main.parse_arguments.examples new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/support.rst b/docs/source/support.rst new file mode 100644 index 00000000..4db69ffa --- /dev/null +++ b/docs/source/support.rst @@ -0,0 +1,12 @@ +Support for Traja +================= + +Bugs +---- + +Bugs, issues and improvement requests can be logged in `Github Issues `_. + +Community +--------- + +Community support is provided via `Gitter `_. Just ask a question there. diff --git a/docs/source/traja.contrib.rst b/docs/source/traja.contrib.rst new file mode 100644 index 00000000..8348bd31 --- /dev/null +++ b/docs/source/traja.contrib.rst @@ -0,0 +1,14 @@ +traja.contrib package +===================== + +Submodules +---------- + + +Module contents +--------------- + +.. automodule:: traja.contrib + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/turns.rst b/docs/source/turns.rst new file mode 100644 index 00000000..4262312c --- /dev/null +++ b/docs/source/turns.rst @@ -0,0 +1,24 @@ +Turns and Angular Analysis +========================== + +Turns +----- + +Turns can be calculated using :func:`~traja.trajectory.calc_angle`. + +.. autofunction:: traja.trajectory.calc_angle + +Heading +------- + +Heading can be calculated using :func:`~traja.trajectory.calc_heading`. + +.. autofunction:: traja.trajectory.calc_heading + +Angles +------ + +Angles can be calculated using :func:`~traja.trajectory.angles`. + +.. autofunction:: traja.trajectory.angles + diff --git a/environment.yml b/environment.yml new file mode 100644 index 00000000..c959db94 --- /dev/null +++ b/environment.yml @@ -0,0 +1,27 @@ +name: traja +channels: + - conda-forge + - pytorch +dependencies: + - ipython + - pip: + - fastdtw + - tzlocal + - seaborn + - pip + - pandas + - numpy + - matplotlib + - shapely + - scipy + - sphinx + - pillow + - shapely + - scikit-learn + - networkx + - seaborn + - pytorch + - pytest==6.2.2 + - numba>=0.50.0 + - pyDOE2>=1.3.0 + - statsmodels \ No newline at end of file diff --git a/main.py b/main.py deleted file mode 100644 index 1cdef9c1..00000000 --- a/main.py +++ /dev/null @@ -1,510 +0,0 @@ -#! /usr/local/env python3 -import argparse -import glob -import logging -import multiprocessing as mp -import os -import psutil -import sys - -import matplotlib.pyplot as plt -import numpy as np -import pandas as pd -import seaborn as sns - -logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG) - - -class MouseData(object): - def __init__(self, experiment_name, centroids_dir, - meta_filepath='/Users/justinshenk/neurodata/data/Stroke_olive_oil/DVC cageids HT Maximilian Wiesmann updated.xlsx', - cage_xmax = 0.058*2, cage_ymax= 0.125*2): - # TODO: Fix in prod version - self._init() - self.basedir = '/Users/justinshenk/neurodata/' - self._cpu_count = psutil.cpu_count() - self.centroids_dir = centroids_dir - search_path = glob.glob(os.path.join(centroids_dir, '*')) - self.centroids_files = sorted( - [x.split('/')[-1] for x in search_path if 'csv' in x and 'filelist' not in x]) - self.mouse_lookup = self.load_meta(meta_filepath) - self.cage_xmax = cage_xmax - self.cage_ymax = cage_ymax - self.experiment_name = experiment_name - self.outdir = os.path.join(self.basedir, 'output', self._str2filename(experiment_name)) - self.cages = self.get_cages(centroids_dir) - - def _init(self): - plt.rc('font', family='serif') - - @staticmethod - def _str2filename(string): - filename = string.replace(' ', '_') - # TODO: Implement filename security - filename = filename.replace('/', '') - return filename - - def get_weekly_activity(self): - activity = self.get_daily_activity() - weekly_list = [] - - for week in range(-3, 5): - for group in activity['Group+Diet'].unique(): - for period in ['Daytime', 'Nighttime']: - df = activity[(activity.Days_from_surgery >= week * 7 + 1) # ...-6, 1, 8, 15... - & (activity.Days_from_surgery < (week + 1) * 7 + 1) # ...1, 8, 15, 21... - & (activity['Group+Diet'] == group) - & (activity.Period == period)].groupby(['Cage']).Activity.mean().to_frame() - df['Group+Diet'] = group - df['Week'] = week - df['Period'] = period - # df['Cohort'] = [get_cohort(x) for x in df.index] - weekly_list.append(df) - weekly = pd.concat(weekly_list) - return weekly - - def plot_weekly(self, weekly, groups): - for group in groups: - fig, ax = plt.subplots(figsize=(4, 3)) - for period in ['Daytime', 'Nighttime']: - sns.pointplot(x='Week', y='Activity', hue='Cohort', - data=weekly[(weekly['Group+Diet'] == group) & (weekly['Period'] == period)].groupby( - 'Activity').mean().reset_index(), - ci=68) - plt.title(group) - handles, labels = ax.get_legend_handles_labels() - # sort both labels and handles by labels - labels, handles = zip(*sorted(zip(labels[:2], handles[:2]), key=lambda t: t[0])) - ax.legend(handles, labels) - plt.tight_layout() - plt.show() - - def get_presurgery_average_weekly_activity(self): - """Average pre-stroke weeks into one point.""" - pre_average_weekly_act = os.path.join(self.outdir, 'pre_average_weekly_act.csv') - if not os.path.exists(pre_average_weekly_act): - weekly = self.get_weekly_activity() - for period in ['Daytime', 'Nighttime']: - for cage in self.get_cages(): - mean = weekly[ - (weekly.index == cage) & (weekly.Week < 0) & (weekly.Period == period)].Activity.mean() - weekly.loc[ - (weekly.index == cage) & (weekly.Week < 0) & (weekly.Period == period), 'Activity'] = mean - else: - weekly = self.read_csv(pre_average_weekly_act) - return weekly - - def norm_weekly_activity(self, weekly): - # Normalize activity - weekly['Normed_Activity'] = 0 - for period in ['Daytime', 'Nighttime']: - for cage in self.get_cages(): - df_night = weekly[(weekly['Week'] >= -1) & (weekly.index == cage) & (weekly.Period == 'Nighttime')] - df = weekly[(weekly['Week'] >= -1) & (weekly.index == cage) & (weekly.Period == period)] - assert df.Week.is_monotonic_increasing == True, "Not monotonic" - normed = [x / df_night.Activity.values[0] for x in df.Activity.values] - weekly.loc[(weekly.index == cage) & (weekly.Period == period) & ( - weekly.Week >= -1), 'Normed_Activity'] = normed - return weekly - - def _stylize_axes(self, ax): - ax.spines['top'].set_visible(False) - ax.spines['right'].set_visible(False) - - ax.xaxis.set_tick_params(top='off', direction='out', width=1) - ax.yaxis.set_tick_params(right='off', direction='out', width=1) - - def _shift_xtick_labels(self, xtick_labels, first_index=None): - for idx, x in enumerate(xtick_labels): - label = x.get_text() - xtick_labels[idx].set_text(str(int(label) + 1)) - if first_index is not None: - xtick_labels[0] = first_index - return xtick_labels - - def _norm_daily_activity(self, activity): - norm_daily_activity_csv = os.path.join(self.outdir, 'norm_daily_activity.csv') - if not os.path.exists(norm_daily_activity_csv): - activity['Normed_Activity'] = 0 - for period in ['Daytime', 'Nighttime']: - for cage in self.get_cages(): - # Get prestroke - prestroke_night_average = activity[(activity.Days_from_surgery <= -1) & (activity.Cage == cage) & ( - activity.Period == 'Nighttime')].Activity.mean() - df = activity[ - (activity.Days_from_surgery >= -1) & (activity.Cage == cage) & (activity.Period == period)] - assert df.Days_from_surgery.is_monotonic_increasing == True, "Not monotonic" - mean = activity[(activity.Days_from_surgery <= -1) & (activity.Cage == cage) & ( - activity.Period == period)].Activity.mean() - df.loc[(df.Cage == cage) & (df.Period == period) & (df.Days_from_surgery == -1), 'Activity'] = mean - normed = [x / prestroke_night_average for x in df.Activity.values] - activity.loc[(activity.Cage == cage) & (activity.Period == period) & ( - activity.Days_from_surgery >= -1), 'Normed_Activity'] = normed - activity.to_csv(norm_daily_activity_csv) - else: - activity = pd.read_csv(norm_daily_activity_csv) - return activity - - def plot_daily_normed_activity(self): - activity = self.get_daily_activity() - activity = self._norm_daily_activity(activity) - - def plot_weekly_normed_activity(self, presurgery_average=True): - """Plot weekly normed activity. Optionally, average presurgery points.""" - if presurgery_average: - weekly = self.get_presurgery_average_weekly_activity() - # for cohort in [2,4]: - fig, ax = plt.subplots(figsize=(6.25, 3.8)) - hue_order = weekly['Group+Diet'].unique() - group_cnt = len(hue_order) - for period in ['Daytime', 'Nighttime']: - linestyles = ['--'] * group_cnt if period is 'Daytime' else ['-'] * group_cnt - sns.pointplot(x='Week', y='Normed_Activity', hue='Group+Diet', data=weekly[(weekly.Week >= -1) & - (weekly.Period == period)], - # (weekly.Cohort==cohort)], - palette=['k', 'gray', 'C0', 'C1'][:group_cnt], - linestyles=linestyles, - # hue_order=['Sham - Control', 'Sham - HT', 'Stroke - Control', 'Stroke - HT'], - hue_order=hue_order, - markers=["d", "s", "^", "x"][:group_cnt], # TODO: Generalize for larger sets - dodge=True, - ci=68) - ax.set_xlabel('Weeks from Surgery') - handles, labels = ax.get_legend_handles_labels() - # sort both labels and handles by labels - labels, handles = zip(*sorted(zip(labels[:4], handles[:4]), key=lambda t: t[0])) - ax.legend(handles, labels) - self._stylize_axes(ax) - fig.set_facecolor('white') - xtick_labels = ax.get_xticklabels() - xtick_labels = self._shift_xtick_labels(xtick_labels, 'Pre-surgery') - - plt.ylabel('Normalized Activity') - ax.set_xticklabels(xtick_labels) - plt.title('Normalized Activity') - plt.show() - - def load_meta(self, meta_filepath): - # TODO: Generalize - mouse_data = pd.read_excel(meta_filepath)[ - ['position', 'Diet', 'Sham_or_Stroke', 'Stroke'] - ] - mouse_data = pd.read_excel(meta_filepath)[ - ['position', 'Diet', 'Sham_or_Stroke', 'Stroke']] - mouse_data['position'] = mouse_data['position'].apply(lambda x: x[1] + x[0].zfill(2)) - return mouse_data.set_index('position').to_dict('index') - - def get_diet(self, cage): - return self.mouse_lookup[cage]['Diet'] - - def get_group(self, cage): - return self.mouse_lookup[cage]['Sham_or_Stroke'] - - def get_stroke(self, cage): - return self.mouse_lookup[cage]['Stroke'] - - def get_group_and_diet(self, cage): - diet = self.get_diet(cage) - surgery = self.get_group(cage) - return f"{'Sham' if surgery is 1 else 'Stroke'} - {'Control' if diet is 1 else 'HT'}" - - def get_cohort(self, cage): - # TODO: Generalize - return self.mouse_lookup[cage]['Stroke'].month - - def get_cages(self, centroid_dir): - # FIXME: Complete implementation - return ['A04'] - - def read_csv(self, path, index_col='time_stamp'): - def strip(text): - try: - return text.strip() - except AttributeError: - return pd.to_numeric(text, errors='coerce') - - date_parser = lambda x: pd.datetime.strptime(x, '%Y-%m-%d %H:%M:%S:%f') - - df_test = pd.read_csv(path, nrows=100) - if index_col not in df_test: - logging.info(f'{index_col} not in {df_test.columns}') - - whitespace_cols = [c for c in df_test if ' ' in df_test[c].name] - stripped_cols = {c: strip for c in whitespace_cols} - # TODO: Add converters for processed 'datetime', 'x', etc. features - converters = stripped_cols - - float_cols = [c for c in df_test if df_test[c].dtype == 'float64'] - float16_cols = {c: np.float16 for c in float_cols} - - string_cols = [c for c in df_test if df_test[c].dtype == 'string'] - category_cols = {c: 'category' for c in string_cols} - dtype = {**float16_cols, **category_cols} - - df = pd.read_csv(path, - infer_datetime_format=True, - date_parser=date_parser, - converters=converters, - dtype=dtype, - ) - return df - - def get_cages(self): - return [x for x in self.mouse_lookup.keys()] - - def get_ratios(self, file, angle_thresh, distance_thresh): - ratios = [] - cage = file.split('/')[-1].split('_')[0] - # Get x,y coordinates from centroids - date_parser = lambda x: pd.datetime.strptime(x, '%Y-%m-%d %H:%M:%S:%f') - df = self.read_csv(file, index_col='time_stamps_vec')[['x', 'y']] - df.x = df.x.round(7) - df.y = df.y.round(7) - # Calculate euclidean distance (m) travelled - df['distance'] = np.sqrt(np.power(df['x'].shift() - df['x'], 2) + - np.power(df['y'].shift() - df['y'], 2)) - df['dx'] = df['x'].diff() - df['dy'] = df['y'].diff() - # TODO: Replace with generic intervention method name and lookup logic - surgery_date = self.get_stroke(cage) - df['Days_from_surgery'] = (df.index - surgery_date).days - - # Calculate angle w.r.t. x axis - df['angle'] = np.rad2deg(np.arccos(np.abs(df['dx']) / df['distance'])) - # Get heading from angle - mask = (df['dx'] > 0) & (df['dy'] >= 0) - df.loc[mask, 'heading'] = df['angle'][mask] - mask = (df['dx'] >= 0) & (df['dy'] < 0) - df.loc[mask, 'heading'] = -df['angle'][mask] - mask = (df['dx'] < 0) & (df['dy'] <= 0) - df.loc[mask, 'heading'] = -(180 - df['angle'][mask]) - mask = (df['dx'] <= 0) & (df['dy'] > 0) - df.loc[mask, 'heading'] = (180 - df['angle'])[mask] - df['turn_angle'] = df['heading'].diff() - # Correction for 360-degree angle range - df.loc[df.turn_angle >= 180, 'turn_angle'] -= 360 - df.loc[df.turn_angle < -180, 'turn_angle'] += 360 - # df['turn_angle'].where((df['distance']>1e-3) & ((df.turn_angle > -15) & (df.turn_angle < 15))).hist(bins=30) - # df['turn_bias'] = df['turn_angle'] / .25 # 0.25s - # Only look at distances over .01 meters, resample to minute intervals - distance_mask = df['distance'] > (distance_thresh) - angle_mask = ((df.turn_angle > angle_thresh) & (df.turn_angle < 90)) | ( - (df.turn_angle < -angle_thresh) & (df.turn_angle > -90)) - - day_mask = (df.index.hour >= 7) & (df.index.hour < 19) - day_mean = df.loc[distance_mask & angle_mask & day_mask, 'turn_angle'].dropna() - night_mean = df.loc[distance_mask & angle_mask & ~day_mask, 'turn_angle'].dropna() - right_turns_day = day_mean[day_mean > 0].shape[0] - left_turns_day = day_mean[day_mean < 0].shape[0] - right_turns_night = night_mean[night_mean > 0].shape[0] - left_turns_night = night_mean[night_mean < 0].shape[0] - ratios.append((df.Days_from_surgery[0], right_turns_day, left_turns_day, False)) - ratios.append((df.Days_from_surgery[0], right_turns_night, left_turns_night, True)) - - ratios = [(day, right, left, period) for day, right, left, period in ratios if - (left + right) > 0] # fix div by 0 errror - return ratios - # days = [day for day, _, _, nighttime in ratios if nighttime] - - # laterality = [right_turns/(left_turns+right_turns) for day, right_turns, left_turns, nighttime in ratios if nighttime] - # fig, ax = plt.subplots() - # ax.plot(days, laterality, label='Laterality') - # ax.set(title=f"{cage} laterality index (right/right+left)\nDistance threshold: 0.25 cm\nAngle threshold: {thresh}\nRight turn is > 0.5\n{get_diet(cage)}", - # xlabel="Days from surgery", - # ylabel="Laterality index") - # ax.legend() - # ax.set_ylim((0,1.0)) - # ax2 = ax.twinx() - # ax2.plot(days, [right+left for _, right, left, nighttime in ratios if nighttime],color='C1', label='Number of turns') - # ax2.set_ylabel('Number of turns') - # ax2.legend() - # plt.show() - - def calculate_turns(self, angle_thresh=30, distance_thresh=0.0025): - ratio_dict = {} - for cage in self.get_cages(): - ratio_dict[cage] = [] - - with mp.Pool(processes=self._cpu_count) as p: - args = [(file, angle_thresh, distance_thresh) for file in self.centroids_files if cage in file] - ratios = p.starmap(self.get_ratios, args) - ratio_dict[cage].append(ratios) - logging.info(f'Processed {cage}') - - turn_ratio_csv = os.path.join(self.outdir, - f'ratios_angle-{angle_thresh}_distance-{distance_thresh}_period_turnangle.npy') - np.save(turn_ratio_csv, ratio_dict) - logging.info(f'Saved to {turn_ratio_csv}') - return ratio_dict - - def get_centroid(self, cage): - path = os.path.join(self.outdir, 'centroids', cage) - df = self.read_csv(path) - return df - - def plot_position_heatmap(self, cage): - from numpy import unravel_index - # TODO: Generate from y in +-0.12, x in +-0.058 - x_edges = np.array([-0.1201506, -0.11524541, -0.11034022, -0.10543504, -0.10052985, - -0.09562466, -0.09071947, -0.08581429, -0.0809091, -0.07600391, - -0.07109872, -0.06619353, -0.06128835, -0.05638316, -0.05147797, - -0.04657278, -0.0416676, -0.03676241, -0.03185722, -0.02695203, - -0.02204684, -0.01714166, -0.01223647, -0.00733128, -0.00242609, - 0.00247909, 0.00738428, 0.01228947, 0.01719466, 0.02209984, - 0.02700503, 0.03191022, 0.03681541, 0.0417206, 0.04662578, - 0.05153097, 0.05643616, 0.06134135, 0.06624653, 0.07115172, - 0.07605691, 0.0809621, 0.08586729, 0.09077247, 0.09567766, - 0.10058285, 0.10548804, 0.11039322, 0.11529841, 0.1202036]) - - y_edges = np.array([-0.05804244, -0.05567644, -0.05331044, -0.05094444, -0.04857844, - -0.04621243, -0.04384643, -0.04148043, -0.03911443, -0.03674843, - -0.03438243, -0.03201643, -0.02965043, -0.02728443, -0.02491843, - -0.02255242, -0.02018642, -0.01782042, -0.01545442, -0.01308842, - -0.01072242, -0.00835642, -0.00599042, -0.00362442, -0.00125842, - 0.00110759, 0.00347359, 0.00583959, 0.00820559, 0.01057159, - 0.01293759, 0.01530359, 0.01766959, 0.02003559, 0.02240159, - 0.0247676, 0.0271336, 0.0294996, 0.0318656, 0.0342316, - 0.0365976, 0.0389636, 0.0413296, 0.0436956, 0.0460616, - 0.04842761, 0.05079361, 0.05315961, 0.05552561, 0.05789161]) - - df = self.get_centroid(cage) - x, y = zip(*df[['x', 'y']].values) - # TODO: Remove redundant histogram calculation - H, x_edges, y_edges = np.histogram2d(x, y, bins=(x_edges, y_edges)) - cmax = H.flatten().argsort()[-2] # Peak point is too hot, bug? - - fig, ax = plt.subplots() - hist, x_edges, y_edges, image = ax.hist2d(np.array(y), np.array(x), - bins=[np.linspace(df.y.min(), df.y.max(), 50), - np.linspace(df.x.min(), df.x.max(), 50)], - cmax=cmax) - ax.colorbar() - # peak_index = unravel_index(hist.argmax(),hist.shape) - - def get_activity_files(self): - activity_dir = os.path.join(self.basedir, 'data', self.experiment_name, 'dvc_activation', '*') - activity_files = glob.glob(activity_dir) - assert activity_files, "No activity files" - return activity_files - - def aggregate_files(self): - """Aggregate cage files into csvs""" - os.makedirs(os.path.join(self.outdir,'centroids'), exist_ok=True) - for cage in self.centroid_files: - logging.info(f'Processing {cage}') - # Check for aggregated cage file (eg, 'A04.csv') - cage_path = os.path.join(self.outdir, 'centroids', f'{cage}.csv') - if os.path.exists(cage_path): - continue - # Otherwise, generate one - search_path = os.path.join(self.centroids_dir, cage, '*.csv') - files = glob.glob(search_path) - - days = [] - for file in files: - _df = self.read_csv(file) - _df.columns = [x.strip() for x in _df.columns] - days.append(_df) - df = pd.concat(days).sort_index() - # for col in ['x','y','distance']: - # df.applymap(lambda x: x.str.strip() if isinstance(x,str) else x) - # df[col] = pd.to_numeric(df[col],errors='coerce') - cage_path = os.path.join(self.outdir, 'centroids', f'{cage}.csv') - df.to_csv(cage_path) - logging.info(f'saved to {cage_path}') - # activity_df = self.read_csv('data/Stroke_olive_oil/dvc_activation/A04.csv', index_col='time_stamp_start') - return - - def _get_ratio_dict(self, angle=30, distance=0.0025): - npy_path = os.path.join(self.outdir, 'ratios_angle-{angle}_distance-{distance}_period_turnangle.npy') - r = np.load(npy_path) - ratio_dict = r.item(0) - return ratio_dict - - def get_cage_laterality(self, cage): - ratio_dict = self._get_ratio_dict() - ratios = ratio_dict[cage] - ratios = [x for x in ratios if (x[1] + x[2] > 0)] - days = [day for day, _, _, nighttime in ratios if nighttime] - - laterality = [right_turns / (left_turns + right_turns) for day, right_turns, left_turns, nighttime in ratios - if nighttime] - fig, ax = plt.subplots() - ax.plot(days, laterality, label='Laterality') - ax.set( - title=f"{cage} laterality index (right/right+left)\nDistance threshold: 0.25 cm\nAngle threshold: {thresh}\nRight turn is > 0.5\n{self.get_diet(cage)}", - xlabel="Days from surgery", - ylabel="Laterality index") - ax.legend() - ax.set_ylim((0, 1.0)) - ax2 = ax.twinx() - ax2.plot(days, [right + left for _, right, left, nighttime in ratios if nighttime], color='C1', - label='Number of turns') - ax2.set_ylabel('Number of turns') - ax2.legend() - plt.show() - - def get_daily_activity(self): - activity_csv = os.path.join(self.outdir,'daily_activity.csv') - if not os.path.exists(activity_csv): - print(f"Path {activity_csv} does not exist, creating dataframe") - activity_list = [] - col_list = [f'e{i:02}' for i in range(1, 12 + 1)] # electrode columns - # Iterate over minute activations - search_path = os.path.join(self.basedir, 'data', self.experiment_name, 'dvc_activation', '*.csv') - minute_activity_files = sorted( - glob.glob(search_path)) - for cage in minute_activity_files: - cage_id = os.path.split(cage)[-1].split('.')[0] - # TODO: Fix in final - assert len(cage_id) == 3, logging.error(f"{cage_id} length != 3") - # Read csv - cage_df = pd.read_csv(cage, index_col='time_stamp_start', - date_parser=lambda x: pd.datetime.strptime(x, '%Y-%m-%d %H:%M:%S:%f')) - # Make csv with columns for cage+activity+day+diet+surgery - cage_df['Activity'] = cage_df[col_list].sum(axis=1) - day = cage_df.Activity.between_time('7:00', '19:00').resample('D').sum().to_frame() - day['Cage'] = cage_id - day['Period'] = 'Daytime' - day['Surgery'] = self.get_stroke(cage_id) - day['Diet'] = self.get_diet(cage_id) - day['Group'] = self.get_group(cage_id) - day['Days'] = [int(x) for x in range(len(day.index))] - activity_list.append(day) - - night = cage_df.Activity.between_time('19:00', '7:00').resample('D').sum().to_frame() - night['Cage'] = cage_id - night['Period'] = 'Nighttime' - night['Surgery'] = self.get_stroke(cage_id) - night['Diet'] = self.get_diet(cage_id) - night['Group'] = self.get_group(cage_id) - night['Days'] = [int(x) for x in range(len(night.index))] - activity_list.append(night) - - activity = pd.concat(activity_list) - activity.to_csv(activity_csv) - else: - activity = pd.read_csv(activity_csv, - index_col='time_stamp_start', - parse_dates=['Surgery', 'time_stamp_start'], - infer_datetime_format=True) - return activity - - -def main(args): - experiment = MouseData(experiment_name='Stroke_olive_oil', - centroids_dir='/Users/justinshenk/neurodata/data/Stroke_olive_oil/dvc_tracking_position_raw/') - experiment.aggregate_files() - activity_files = experiment.get_activity_files() - - -def parse_arguments(argv=sys.argv[1:]): - parser = argparse.ArgumentParser(description='Load and analyze activity data') - # TODO: Add cage dimensions argument - args = parser.parse_args(argv) - return args - - -if __name__ == '__main__': - args = parse_arguments(sys.argv) - main() diff --git a/paper/figure.png b/paper/figure.png new file mode 100644 index 00000000..8dd9fbec Binary files /dev/null and b/paper/figure.png differ diff --git a/paper/images/autocorrelation_E1.png b/paper/images/autocorrelation_E1.png new file mode 100644 index 00000000..119171f6 Binary files /dev/null and b/paper/images/autocorrelation_E1.png differ diff --git a/paper/images/diagram.jpg b/paper/images/diagram.jpg new file mode 100644 index 00000000..d310b176 Binary files /dev/null and b/paper/images/diagram.jpg differ diff --git a/paper/images/dnns.jpg b/paper/images/dnns.jpg new file mode 100644 index 00000000..766aebe2 Binary files /dev/null and b/paper/images/dnns.jpg differ diff --git a/paper/images/generate.png b/paper/images/generate.png new file mode 100644 index 00000000..15dfc603 Binary files /dev/null and b/paper/images/generate.png differ diff --git a/paper/images/kmeans_pca-fortasyn.png b/paper/images/kmeans_pca-fortasyn.png new file mode 100644 index 00000000..73103946 Binary files /dev/null and b/paper/images/kmeans_pca-fortasyn.png differ diff --git a/paper/images/lda_fortasyn-period.png b/paper/images/lda_fortasyn-period.png new file mode 100644 index 00000000..e6fa4401 Binary files /dev/null and b/paper/images/lda_fortasyn-period.png differ diff --git a/paper/images/pca_fortasyn-period-3d.png b/paper/images/pca_fortasyn-period-3d.png new file mode 100644 index 00000000..6d669537 Binary files /dev/null and b/paper/images/pca_fortasyn-period-3d.png differ diff --git a/paper/images/pca_fortasyn-period.png b/paper/images/pca_fortasyn-period.png new file mode 100644 index 00000000..7bef04d0 Binary files /dev/null and b/paper/images/pca_fortasyn-period.png differ diff --git a/paper/images/rnn-prediction.png b/paper/images/rnn-prediction.png new file mode 100644 index 00000000..a28796c9 Binary files /dev/null and b/paper/images/rnn-prediction.png differ diff --git a/paper/images/rotate.png b/paper/images/rotate.png new file mode 100644 index 00000000..13dbd2fa Binary files /dev/null and b/paper/images/rotate.png differ diff --git a/paper/images/sample_rate.png b/paper/images/sample_rate.png new file mode 100644 index 00000000..273f8f18 Binary files /dev/null and b/paper/images/sample_rate.png differ diff --git a/paper/images/spectrum.png b/paper/images/spectrum.png new file mode 100644 index 00000000..04f905ae Binary files /dev/null and b/paper/images/spectrum.png differ diff --git a/paper/images/traja-package_diagram.pdf b/paper/images/traja-package_diagram.pdf new file mode 100644 index 00000000..9e74bb67 Binary files /dev/null and b/paper/images/traja-package_diagram.pdf differ diff --git a/paper/images/transition_matrix.png b/paper/images/transition_matrix.png new file mode 100644 index 00000000..70b0273a Binary files /dev/null and b/paper/images/transition_matrix.png differ diff --git a/paper/images/trip_grid_algo.png b/paper/images/trip_grid_algo.png new file mode 100644 index 00000000..225a82b4 Binary files /dev/null and b/paper/images/trip_grid_algo.png differ diff --git a/paper/images/tripgrid.png b/paper/images/tripgrid.png new file mode 100644 index 00000000..47e1328e Binary files /dev/null and b/paper/images/tripgrid.png differ diff --git a/paper/images/velocitylog.png b/paper/images/velocitylog.png new file mode 100644 index 00000000..a60c3713 Binary files /dev/null and b/paper/images/velocitylog.png differ diff --git a/paper/paper.bib b/paper/paper.bib new file mode 100644 index 00000000..9cf62e66 --- /dev/null +++ b/paper/paper.bib @@ -0,0 +1,2158 @@ +@article{zheng-trajectory-2015, + title = {Trajectory {Data} {Mining}: {An} {Overview}}, + url = {https://www.microsoft.com/en-us/research/publication/trajectory-data-mining-an-overview/}, + journal = {ACM Transaction on Intelligent Systems and Technology}, + author = {Zheng, Yu}, + year = {2015}, + note = {Type: Journal Article}, +} + +@ARTICLE{10.3389/fnsys.2019.00020, + AUTHOR={Arac, Ahmet and Zhao, Pingping and Dobkin, Bruce H. and Carmichael, S. Thomas and Golshani, Peyman}, + TITLE={DeepBehavior: A Deep Learning Toolbox for Automated Analysis of Animal and Human Behavior Imaging Data}, + JOURNAL={Frontiers in Systems Neuroscience}, + VOLUME={13}, + PAGES={20}, + YEAR={2019}, + URL={https://www.frontiersin.org/article/10.3389/fnsys.2019.00020}, + DOI={10.3389/fnsys.2019.00020}, + ISSN={1662-5137}, + ABSTRACT={Detailed behavioral analysis is key to understanding the brain-behavior relationship. Here, we present deep learning-based methods for analysis of behavior imaging data in mice and humans. Specifically, we use three different convolutional neural network architectures and five different behavior tasks in mice and humans and provide detailed instructions for rapid implementation of these methods for the neuroscience community. We provide examples of three dimensional (3D) kinematic analysis in the food pellet reaching task in mice, three-chamber test in mice, social interaction test in freely moving mice with simultaneous miniscope calcium imaging, and 3D kinematic analysis of two upper extremity movements in humans (reaching and alternating pronation/supination). We demonstrate that the transfer learning approach accelerates the training of the network when using images from these types of behavior video recordings. We also provide code for post-processing of the data after initial analysis with deep learning. Our methods expand the repertoire of available tools using deep learning for behavior analysis by providing detailed instructions on implementation, applications in several behavior tests, and post-processing methods and annotated code for detailed behavior analysis. Moreover, our methods in human motor behavior can be used in the clinic to assess motor function during recovery after an injury such as stroke.} +} + + +@inproceedings{pandas, + title={Data structures for statistical computing in python}, + author={McKinney, Wes and others}, + booktitle={Proceedings of the 9th Python in Science Conference}, + volume={445}, + pages={51--56}, + year={2010}, + doi ={10.25080/majora-92bf1922-00a}, + organization={Austin, TX} +} + + @Article{adehabitat, + title = {The package adehabitat for the R software: tool for the + analysis of space and habitat use by animals}, + journal = {Ecological Modelling}, + volume = {197}, + pages = {1035}, + year = {2006}, + author = {C. Calenge}, + } + + @Misc{shapely, + author = {Sean Gillies and others}, + organization = {toblerity.org}, + title = {Shapely: manipulation and analysis of geometric objects}, + year = {2007--}, + url = "https://github.com/Toblerity/Shapely" +} + +@article{kilkenny_improving_2010, + title = {Improving bioscience research reporting: {The} {ARRIVE} guidelines for reporting animal research}, + volume = {1}, + issn = {0976-500X}, + shorttitle = {Improving bioscience research reporting}, + url = {https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3043335/}, + doi = {10.4103/0976-500X.72351}, + number = {2}, + urldate = {2020-01-13}, + journal = {Journal of Pharmacology \& Pharmacotherapeutics}, + author = {Kilkenny, Carol and Browne, William J. and Cuthill, Innes C. and Emerson, Michael and Altman, Douglas G.}, + year = {2010}, + pmid = {21350617}, + pmcid = {PMC3043335}, + pages = {94--99} +} + +@article{stroke_therapy_academic_industry_roundtable_stair_recommendations_1999, + title = {Recommendations for standards regarding preclinical neuroprotective and restorative drug development}, + volume = {30}, + issn = {0039-2499}, + doi = {10.1161/01.str.30.12.2752}, + abstract = {The plethora of failed clinical trials with neuroprotective drugs for acute ischemic stroke have raised justifiable concerns about how best to proceed for the future development of such interventions. Preclinical testing of neuroprotective drugs is an important aspect of assessing their therapeutic potential, but guidelines concerning how to perform preclinical development of purported neuroprotective drugs for acute ischemic stroke are lacking. This conference of academicians and industry representatives was convened to suggest such guidelines for the preclinical evaluation of neuroprotective drugs and to recommend to potential clinical investigators the data they should review to reassure themselves that a particular neuroprotective drug has a reasonable chance to succeed in an appropriately designed clinical trial. Without rigorous, robust, and detailed preclinical evaluation, it is unlikely that novel neuroprotective drugs will prove to be effective when tested in large, time-consuming, and expensive clinical trials. Additionally, similar recommendations are provided for drugs with the potential to enhance recovery after acute ischemic stroke, a burgeoning new field with great potential but little currently available data. The suggestions contained in this document are meant to serve as overall guidelines that must be adapted to the individual characteristics related to particular drugs and their preclinical and clinical development needs.}, + language = {eng}, + number = {12}, + journal = {Stroke}, + author = {{Stroke Therapy Academic Industry Roundtable (STAIR)}}, + month = dec, + year = {1999}, + pmid = {10583007}, + keywords = {Animals, Disease Models, Animal, Drug Combinations, Drug Evaluation, Preclinical, Enzymes, Guidelines as Topic, Neuroprotective Agents, Outcome Assessment, Health Care, Primates, Rats, Remission, Spontaneous, Sex Factors, Stroke}, + pages = {2752--2758} +} + +@misc{noauthor_1_nodate, + title = {(1) {Stroke} {Therapy} {Academic} {Industry} {Roundtable} ({STAIR}) {Recommendations} {For} {Extended} {Window} {Acute} {Stroke} {Therapy} {Trials} {\textbar} {Request} {PDF}}, + url = {https://www.researchgate.net/publication/26249404_Stroke_Therapy_Academic_Industry_Roundtable_STAIR_Recommendations_For_Extended_Window_Acute_Stroke_Therapy_Trials}, + abstract = {ResearchGate is a network dedicated to science and research. Connect, collaborate and discover scientific publications, jobs and conferences. All for free.}, + language = {en}, + urldate = {2020-01-13}, + journal = {ResearchGate} +} + +@article{fisher_update_2009, + title = {Update of the {Stroke} {Therapy} {Academic} {Industry} {Roundtable} {Preclinical} {Recommendations}}, + volume = {40}, + issn = {0039-2499}, + url = {https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2888275/}, + doi = {10.1161/STROKEAHA.108.541128}, + abstract = {The initial Stroke Therapy Academic Industry Roundtable (STAIR) recommendations published in 1999 were intended to improve the quality of preclinical studies of purported acute stroke therapies. Although recognized as reasonable, they have not been closely followed nor rigorously validated. Substantial advances have occurred regarding the appropriate quality and breadth of preclinical testing for candidate acute stroke therapies for better clinical translation. The updated STAIR preclinical recommendations reinforce the previous suggestions that reproducibly defining dose response and time windows with both histological and functional outcomes in multiple animal species with appropriate physiological monitoring is appropriate. The updated STAIR recommendations include: the fundamentals of good scientific inquiry should be followed by eliminating randomization and assessment bias, a priori defining inclusion/exclusion criteria, performing appropriate power and sample size calculations, and disclosing potential conflicts of interest. After initial evaluations in young, healthy male animals, further studies should be performed in females, aged animals, and animals with comorbid conditions such as hypertension, diabetes, and hypercholesterolemia. Another consideration is the use of clinically relevant biomarkers in animal studies. Although the recommendations cannot be validated until effective therapies based on them emerge from clinical trials, it is hoped that adherence to them might enhance the chances for success.}, + number = {6}, + urldate = {2020-01-13}, + journal = {Stroke; a journal of cerebral circulation}, + author = {Fisher, Marc and Feuerstein, Giora and Howells, David W. and Hurn, Patricia D. and Kent, Thomas A. and Savitz, Sean I. and Lo, Eng H.}, + month = jun, + year = {2009}, + pmid = {19246690}, + pmcid = {PMC2888275}, + pages = {2244--2250} +} + +@article{savitzky_smoothing_1964, + title = {Smoothing and {Differentiation} of {Data} by {Simplified} {Least} {Squares} {Procedures}.}, + volume = {36}, + issn = {0003-2700}, + url = {https://doi.org/10.1021/ac60214a047}, + doi = {10.1021/ac60214a047}, + number = {8}, + urldate = {2021-02-13}, + journal = {Analytical Chemistry}, + author = {Savitzky, Abraham. and Golay, M. J. E.}, + month = jul, + year = {1964}, + note = {Publisher: American Chemical Society}, + pages = {1627--1639}, +} + +@misc{noauthor_hydroxytyrosol_nodate, + title = {Hydroxytyrosol, the {Major} {Phenolic} {Compound} of {Olive} {Oil}, as an {Acute} {Therapeutic} {Strategy} after {Ischemic} {Stroke}. - {PubMed} - {NCBI}}, + url = {https://www.ncbi.nlm.nih.gov/pubmed/31614692}, + urldate = {2020-01-13} +} + +@inproceedings{kim_trajectory_2017, + title = {Trajectory {Flow} {Map}: {Graph}-based {Approach} to {Analysing} {Temporal} {Evolution} of {Aggregated} {Traffic} {Flows} in {Large}-scale {Urban} {Networks}}, + shorttitle = {Trajectory {Flow} {Map}}, + urldate = {2019-12-02}, + author = {Kim, Jiwon and Zheng, Kai and Corcoran, Jonathan and Ahn, Sanghyung and Papamanolis, Marty}, + year = {2017} +} + +@article{abbas_computer_2019, + title = {Computer {Methods} for {Automatic} {Locomotion} and {Gesture} {Tracking} in {Mice} and {Small} {Animals} for {Neuroscience} {Applications}: {A} {Survey}}, + volume = {19}, + shorttitle = {Computer {Methods} for {Automatic} {Locomotion} and {Gesture} {Tracking} in {Mice} and {Small} {Animals} for {Neuroscience} {Applications}}, + url = {https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6696321/}, + doi = {10.3390/s19153274}, + abstract = {Neuroscience has traditionally relied on manually observing laboratory animals in controlled environments. Researchers usually record animals behaving freely or in a restrained manner and then annotate the data manually. The manual annotation is not desirable ...}, + language = {en}, + number = {15}, + urldate = {2020-01-13}, + journal = {Sensors (Basel, Switzerland)}, + author = {Abbas, Waseem and Rodo, David Masip}, + month = aug, + year = {2019}, + pmid = {31349617} +} + +@article{zinnhardt_multimodal_2015, + title = {Multimodal imaging reveals temporal and spatial microglia and matrix metalloproteinase activity after experimental stroke}, + volume = {35}, + issn = {0271-678X}, + url = {https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4635244/}, + doi = {10.1038/jcbfm.2015.149}, + abstract = {Stroke is the most common cause of death and disability from neurologic disease in humans. Activation of microglia and matrix metalloproteinases (MMPs) is involved in positively and negatively affecting stroke outcome. Novel, noninvasive, multimodal imaging methods visualizing microglial and MMP alterations were employed. The spatio-temporal dynamics of these parameters were studied in relation to blood flow changes. Micro positron emission tomography (Ī¼PET) using [18F]BR-351 showed MMP activity within the first days after transient middle cerebral artery occlusion (tMCAo), followed by increased [18F]DPA-714 uptake as a marker for microglia activation with a maximum at 14 days after tMCAo. The inflammatory response was spatially located in the infarct core and in adjacent (penumbral) tissue. For the first time, multimodal imaging based on PET, single photon emission computed tomography, and magnetic resonance imaging revealed insight into the spatio-temporal distribution of critical parameters of poststroke inflammation. This allows further evaluation of novel treatment paradigms targeting the postischemic inflammation.}, + number = {11}, + urldate = {2020-01-13}, + journal = {Journal of Cerebral Blood Flow \& Metabolism}, + author = {Zinnhardt, Bastian and Viel, Thomas and Wachsmuth, Lydia and Vrachimis, Alexis and Wagner, Stefan and Breyholz, Hans-Jƶrg and Faust, Andreas and Hermann, Sven and Kopka, Klaus and Faber, Cornelius and DollĆ©, FrĆ©dĆ©ric and Pappata, Sabina and Planas, Anna M and Tavitian, Bertrand and SchƤfers, Michael and Sorokin, Lydia M and Kuhlmann, Michael T and Jacobs, Andreas H}, + month = nov, + year = {2015}, + pmid = {26126867}, + pmcid = {PMC4635244}, + pages = {1711--1721} +} + +@article{fluri_animal_2015, + title = {Animal models of ischemic stroke and their application in clinical research}, + volume = {9}, + issn = {1177-8881}, + url = {https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4494187/}, + doi = {10.2147/DDDT.S56071}, + abstract = {This review outlines the most frequently used rodent stroke models and discusses their strengths and shortcomings. Mimicking all aspects of human stroke in one animal model is not feasible because ischemic stroke in humans is a heterogeneous disorder with a complex pathophysiology. The transient or permanent middle cerebral artery occlusion (MCAo) model is one of the models that most closely simulate human ischemic stroke. Furthermore, this model is characterized by reliable and well-reproducible infarcts. Therefore, the MCAo model has been involved in the majority of studies that address pathophysiological processes or neuroprotective agents. Another model uses thromboembolic clots and thus is more convenient for investigating thrombolytic agents and pathophysiological processes after thrombolysis. However, for many reasons, preclinical stroke research has a low translational success rate. One factor might be the choice of stroke model. Whereas the therapeutic responsiveness of permanent focal stroke in humans declines significantly within 3 hours after stroke onset, the therapeutic window in animal models with prompt reperfusion is up to 12 hours, resulting in a much longer action time of the investigated agent. Another major problem of animal stroke models is that studies are mostly conducted in young animals without any comorbidity. These models differ from human stroke, which particularly affects elderly people who have various cerebrovascular risk factors. Choosing the most appropriate stroke model and optimizing the study design of preclinical trials might increase the translational potential of animal stroke models.}, + urldate = {2020-01-13}, + journal = {Drug Design, Development and Therapy}, + author = {Fluri, Felix and Schuhmann, Michael K and Kleinschnitz, Christoph}, + month = jul, + year = {2015}, + pmid = {26170628}, + pmcid = {PMC4494187}, + pages = {3445--3454} +} + +@article{williams_identification_2017, + title = {Identification of animal movement patterns using tri-axial magnetometry}, + volume = {5}, + issn = {2051-3933}, + url = {https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5367006/}, + doi = {10.1186/s40462-017-0097-x}, + abstract = {Background +Accelerometers are powerful sensors in many bio-logging devices, and are increasingly allowing researchers to investigate the performance, behaviour, energy expenditure and even state, of free-living animals. Another sensor commonly used in animal-attached loggers is the magnetometer, which has been primarily used in dead-reckoning or inertial measurement tags, but little outside that. We examine the potential of magnetometers for helping elucidate the behaviour of animals in a manner analogous to, but very different from, accelerometers. The particular responses of magnetometers to movement means that there are instances when they can resolve behaviours that are not easily perceived using accelerometers. + +Methods +We calibrated the tri-axial magnetometer to rotations in each axis of movement and constructed 3-dimensional plots to inspect these stylised movements. Using the tri-axial data of Daily Diary tags, attached to individuals of number of animal species as they perform different behaviours, we used these 3-d plots to develop a framework with which tri-axial magnetometry data can be examined and introduce metrics that should help quantify movement and behaviour.ļ»æļ»æ + +Results +Tri-axial magnetometry data reveal patterns in movement at various scales of rotation that are not always evident in acceleration data. Some of these patterns may be obscure until visualised in 3D space as tri-axial spherical plots (m-spheres). A tag-fitted animal that rotates in heading while adopting a constant body attitude produces a ring of data around the pole of the m-sphere that we define as its Normal Operational Plane (NOP). Data that do not lie on this ring are created by postural rotations of the animal as it pitches and/or rolls. Consequently, stereotyped behaviours appear as specific trajectories on the sphere (m-prints), reflecting conserved sequences of postural changes (and/or angular velocities), which result from the precise relationship between body attitude and heading. This novel approach shows promise for helping researchers to identify and quantify behaviours in terms of animal body posture, including heading. + +Conclusion +Magnetometer-based techniques and metrics can enhance our capacity to identify and examine animal behaviour, either as a technique used alone, or one that is complementary to tri-axial accelerometry. + +Electronic supplementary material +The online version of this article (doi:10.1186/s40462-017-0097-x) contains supplementary material, which is available to authorized users.}, + urldate = {2020-01-13}, + journal = {Movement Ecology}, + author = {Williams, Hannah J. and Holton, Mark D. and Shepard, Emily L. C. and Largey, Nicola and Norman, Brad and Ryan, Peter G. and Duriez, Olivier and Scantlebury, Michael and Quintana, Flavio and Magowan, Elizabeth A. and Marks, Nikki J. and Alagaili, Abdulaziz N. and Bennett, Nigel C. and Wilson, Rory P.}, + month = mar, + year = {2017}, + pmid = {28357113}, + pmcid = {PMC5367006} +} + +@article{wiesmann_dietary_2016, + title = {A {Dietary} {Treatment} {Improves} {Cerebral} {Blood} {Flow} and {Brain} {Connectivity} in {Aging} {apoE}4 {Mice}}, + volume = {2016}, + issn = {1687-5443}, + doi = {10.1155/2016/6846721}, + abstract = {APOE Īµ4 (apoE4) polymorphism is the main genetic determinant of sporadic Alzheimer's disease (AD). A dietary approach (Fortasyn) including docosahexaenoic acid, eicosapentaenoic acid, uridine, choline, phospholipids, folic acid, vitamins B12, B6, C, and E, and selenium has been proposed for dietary management of AD. We hypothesize that the diet could inhibit AD-like pathologies in apoE4 mice, specifically cerebrovascular and connectivity impairment. Moreover, we evaluated the diet effect on cerebral blood flow (CBF), functional connectivity (FC), gray/white matter integrity, and postsynaptic density in aging apoE4 mice. At 10-12 months, apoE4 mice did not display prominent pathological differences compared to wild-type (WT) mice. However, 16-18-month-old apoE4 mice revealed reduced CBF and accelerated synaptic loss. The diet increased cortical CBF and amount of synapses and improved white matter integrity and FC in both aging apoE4 and WT mice. We demonstrated that protective mechanisms on vascular and synapse health are enhanced by Fortasyn, independent of apoE genotype. We further showed the efficacy of a multimodal translational approach, including advanced MR neuroimaging, to study dietary intervention on brain structure and function in aging.}, + language = {eng}, + journal = {Neural Plasticity}, + author = {Wiesmann, Maximilian and Zerbi, Valerio and Jansen, Diane and Haast, Roy and LĆ¼tjohann, Dieter and Broersen, Laus M. and Heerschap, Arend and Kiliaan, Amanda J.}, + year = {2016}, + pmid = {27034849}, + pmcid = {PMC4806294}, + keywords = {Aging, Alzheimer Disease, Animals, Apolipoprotein E4, Apolipoproteins E, Brain, Brain Mapping, Diet, Disks Large Homolog 4 Protein, Fatty Acids, Female, Guanylate Kinases, Magnetic Resonance Imaging, Male, Membrane Proteins, Mice, Mice, Inbred C57BL, Mice, Transgenic, Neural Pathways, Sterols}, + pages = {6846721} +} + +@article{balkaya_assessing_2013, + title = {Assessing post-stroke behavior in mouse models of focal ischemia}, + volume = {33}, + issn = {1559-7016}, + doi = {10.1038/jcbfm.2012.185}, + abstract = {Experimental treatment strategies and neuroprotective drugs that showed therapeutic promise in animal models of stroke have failed to produce beneficial effects in human stroke patients. The difficulty in translating preclinical findings to humans represents a major challenge in cerebrovascular research. The reasons behind this translational road block might be explained by a number of factors, including poor quality control in various stages of the research process, the validity of experimental stroke models, and differences in drug administration and pharmacokinetics. Another major difference between animal studies and clinical trials is the choice of end point or outcome measures. Here, we discuss the necessity of poststroke behavioral testing to bridge the gap between clinical and experimental end points. We review established sensory-motor tests for outcome determination after focal ischemia based on the published literature as well as our own personal experience. Selected tests are described in more detail and good laboratory practice standards for behavioral testing are discussed. This review is intended for stroke researchers planning to use behavioral testing in mice.}, + language = {eng}, + number = {3}, + journal = {Journal of Cerebral Blood Flow and Metabolism: Official Journal of the International Society of Cerebral Blood Flow and Metabolism}, + author = {Balkaya, Mustafa and Krƶber, Jan M. and Rex, Andre and Endres, Matthias}, + month = mar, + year = {2013}, + pmid = {23232947}, + pmcid = {PMC3587814}, + keywords = {Animals, Behavior, Animal, Brain Ischemia, Disease Models, Animal, Humans, Mice, Stroke}, + pages = {330--338} +} + +@misc{noauthor_assessing_nodate, + title = {Assessing post-stroke behavior in mouse models of focal ischemia. - {PubMed} - {NCBI}}, + url = {https://www.ncbi.nlm.nih.gov/pubmed/23232947}, + urldate = {2020-01-09} +} + +@article{zerbi_multinutrient_2014, + title = {Multinutrient diets improve cerebral perfusion and neuroprotection in a murine model of {Alzheimer}'s disease}, + volume = {35}, + issn = {0197-4580}, + url = {http://www.sciencedirect.com/science/article/pii/S0197458013004508}, + doi = {10.1016/j.neurobiolaging.2013.09.038}, + abstract = {Nutritional intervention may retard the development of Alzheimer's disease (AD). In this study we tested the effects of 2 multi-nutrient diets in an AD mouse model (APPswe/PS1dE9). One diet contained membrane precursors such as omega-3 fatty acids and uridine monophosphate (DEU), whereas another diet contained cofactors for membrane synthesis as well (Fortasyn); the diets were developed to enhance synaptic membranes synthesis, and contain components that may improve vascular health. We measured cerebral blood flow (CBF) and water diffusivity with ultra-high-field magnetic resonance imaging, as alterations in these parameters correlate with clinical symptoms of the disease. APPswe/PS1dE9 mice on control diet showed decreased CBF and changes in brain water diffusion, in accordance with findings of hypoperfusion, axonal disconnection and neuronal loss in patients with AD. Both multinutrient diets were able to increase cortical CBF in APPswe/PS1dE9 mice and Fortasyn reduced water diffusivity, particularly in the dentate gyrus and in cortical regions. We suggest that a specific diet intervention has the potential to slow AD progression, by simultaneously improving cerebrovascular health and enhancing neuroprotective mechanisms.}, + language = {en}, + number = {3}, + urldate = {2020-01-09}, + journal = {Neurobiology of Aging}, + author = {Zerbi, Valerio and Jansen, Diane and Wiesmann, Maximilian and Fang, Xiaotian and Broersen, Laus M. and Veltien, Andor and Heerschap, Arend and Kiliaan, Amanda J.}, + month = mar, + year = {2014}, + keywords = {AD mouse model, APPswe/Ps1de9, Alzheimer's disease, Cerebral blood flow, Diffusion tensor imaging, MRI, Mice, Nutrition, Omega-3 fatty acids}, + pages = {600--613} +} + +@article{huang_hidden_2018, + title = {Hidden {Markov} models for monitoring circadian rhythmicity in telemetric activity data}, + volume = {15}, + url = {https://royalsocietypublishing.org/doi/full/10.1098/rsif.2017.0885}, + doi = {10.1098/rsif.2017.0885}, + abstract = {Wearable computing devices allow collection of densely sampled real-time information on movement enabling researchers and medical experts to obtain objective and non-obtrusive records of actual activity of a subject in the real world over many days. Our interest here is motivated by the use of activity data for evaluating and monitoring the circadian rhythmicity of subjects for research in chronobiology and chronotherapeutic healthcare. In order to translate the information from such high-volume data arising we propose the use of a Markov modelling approach which (i) naturally captures the notable square wave form observed in activity data along with heterogeneous ultradian variances over the circadian cycle of human activity, (ii) thresholds activity into different states in a probabilistic way while respecting time dependence and (iii) gives rise to circadian rhythm parameter estimates, based on probabilities of transitions between rest and activity, that are interpretable and of interest to circadian research.}, + number = {139}, + urldate = {2019-12-22}, + journal = {Journal of The Royal Society Interface}, + author = {Huang, Qi and Cohen, Dwayne and Komarzynski, Sandra and Li, Xiao-Mei and Innominato, Pasquale and LĆ©vi, Francis and FinkenstƤdt, BƤrbel}, + month = feb, + year = {2018}, + pages = {20170885} +} + +@article{patterson_migration_2018, + title = {Migration dynamics of juvenile southern bluefin tuna}, + volume = {8}, + copyright = {2018 The Author(s)}, + issn = {2045-2322}, + url = {https://www.nature.com/articles/s41598-018-32949-3}, + doi = {10.1038/s41598-018-32949-3}, + abstract = {Large scale migrations are a key component of the life history of many marine species. We quantified the annual migration cycle of juvenile southern bluefin tuna (Thunnus maccoyii; SBT) and spatiotemporal variability in this cycle, based on a multi-decadal electronic tagging dataset. Behaviour-switching models allowed for the identification of cohesive areas of residency and classified the temporal sequence of movements within a migration cycle from austral summer foraging grounds in the Great Australian Bight (GAB) to winter foraging grounds in the Indian Ocean and Tasman Sea and back to the GAB. Although specific regions within the Indian Ocean were frequented, individuals did not always return to the same area in consecutive years. Outward migrations from the GAB were typically longer than return migrations back to the GAB. The timing of individual arrivals to the GAB, which may be driven by seasonality in prey availability, was more cohesive than the timing of departures from the GAB, which may be subject to the physiological condition of SBT. A valuable fishery for SBT operates in the GAB, as do a number of scientific research programs designed to monitor SBT for management purposes; thus, understanding SBT migration to and from the area is of high importance to a number of stakeholders.}, + language = {en}, + number = {1}, + urldate = {2019-12-22}, + journal = {Scientific Reports}, + author = {Patterson, Toby A. and Eveson, J. Paige and Hartog, Jason R. and Evans, Karen and Cooper, Scott and Lansdell, Matt and Hobday, Alistair J. and Davies, Campbell R.}, + month = sep, + year = {2018}, + pages = {1--10}, +} + +@article{patterson_statistical_2017, + title = {Statistical modelling of individual animal movement: an overview of key methods and a discussion of practical challenges}, + volume = {101}, + issn = {1863-818X}, + shorttitle = {Statistical modelling of individual animal movement}, + url = {https://doi.org/10.1007/s10182-017-0302-7}, + doi = {10.1007/s10182-017-0302-7}, + abstract = {With the influx of complex and detailed tracking data gathered from electronic tracking devices, the analysis of animal movement data has recently emerged as a cottage industry among biostatisticians. New approaches of ever greater complexity are continue to be added to the literature. In this paper, we review what we believe to be some of the most popular and most useful classes of statistical models used to analyse individual animal movement data. Specifically, we consider discrete-time hidden Markov models, more general state-space models and diffusion processes. We argue that these models should be core components in the toolbox for quantitative researchers working on stochastic modelling of individual animal movement. The paper concludes by offering some general observations on the direction of statistical analysis of animal movement. There is a trend in movement ecology towards what are arguably overly complex modelling approaches which are inaccessible to ecologists, unwieldy with large data sets or not based on mainstream statistical practice. Additionally, some analysis methods developed within the ecological community ignore fundamental properties of movement data, potentially leading to misleading conclusions about animal movement. Corresponding approaches, e.g. based on LĆ©vy walk-type models, continue to be popular despite having been largely discredited. We contend that there is a need for an appropriate balance between the extremes of either being overly complex or being overly simplistic, whereby the discipline relies on models of intermediate complexity that are usable by general ecologists, but grounded in well-developed statistical practice and efficient to fit to large data sets.}, + language = {en}, + number = {4}, + urldate = {2019-12-22}, + journal = {AStA Advances in Statistical Analysis}, + author = {Patterson, Toby A. and Parton, Alison and Langrock, Roland and Blackwell, Paul G. and Thomas, Len and King, Ruth}, + month = oct, + year = {2017}, + pages = {399--438} +} + +@misc{noauthor_19_nodate, + title = {(19) ({PDF}) {Hidden} {Markov} models for circular and linear-circular time series}, + url = {https://www.researchgate.net/publication/226694240_Hidden_Markov_models_for_circular_and_linear-circular_time_series}, + abstract = {ResearchGate is a network dedicated to science and research. Connect, collaborate and discover scientific publications, jobs and conferences. All for free.}, + language = {en}, + urldate = {2019-12-22}, + journal = {ResearchGate} +} + + +@inproceedings{ibrahim_-line_2008, + title = {On-line {Signature} {Verification} {Using} {Most} {Discriminating} {Features} and {Fisher} {Linear} {Discriminant} {Analysis} ({FLD})}, + doi = {10.1109/ISM.2008.115}, + abstract = {In this work, we employ a combination of strategies for partitioning and detecting abnormal fluctuations in the horizontal and vertical trajectories of an on-line generated signature profile. Alternative partitions of these spatial trajectories are generated by splitting each of the related angle, velocity and pressure profiles into two regions representing both high and low activity. The overall process can be thought of as one that exploits inter-feature dependencies by decomposing signature trajectories based upon angle, velocity and pressure - information quite characteristic to an individualpsilas signature. In the verification phase, distances of each partitioned trajectory of a test signature are calculated against a similarly partitioned template trajectory for a known signer. Finally, these distances become inputs to Fisherpsilas Linear Discriminant Analysis (FLD). Experimental results demonstrate the superiority of our approach in On-line signature verification in comparison with other techniques.}, + booktitle = {2008 {Tenth} {IEEE} {International} {Symposium} on {Multimedia}}, + author = {Ibrahim, Muhammad Talal and Kyan, Matthew and Guan, Ling}, + month = dec, + year = {2008}, + note = {ISSN: null}, + keywords = {Acceleration, Cameras, Data acquisition, FLD, Fisher linear discriminant analysis, Fluctuations, Forgery, Handwriting recognition, Histograms, Linear discriminant analysis, Shape, Testing, data acquisition, feature extraction, handwriting recognition, most discriminating features, online generated signature profile, online signature verification}, + pages = {172--177} +} + +@book{rasmussen_gaussian_2006, + address = {Cambridge, MA, USA}, + series = {Adaptive {Computation} and {Machine} {Learning}}, + title = {Gaussian {Processes} for {Machine} {Learning}}, + publisher = {Biologische Kybernetik}, + author = {Rasmussen, CE. and Williams, CKI.}, + month = jan, + year = {2006}, + note = {Backup Publisher: Max-Planck-Gesellschaft}, +} + +@inproceedings{jeong_linear_2016, + title = {Linear discriminant analysis for symmetric lifting recognition of skilled logistic experts by center of pressure trajectory}, + doi = {10.1109/EMBC.2016.7591745}, + abstract = {Goal: The main purpose of the present study was to propose a recognizing method to analyze characteristics of symmetric lifting of skilled logistic experts by center of pressure (CoP) trajectories. Although it has been known that good posture helps reduce the intradiscal loads on lumbar discs, the most significant problem was that most of logistic workers did not know whether the current posture was proper or not. Methods : The experiment of lifting was performed three times under 18 kg loads with closed eyes. Six skilled logistic experts and six unskilled beginners were participated in. The linear discriminant analysis (LDA) was designed by seven indices which were derived from measured CoP trajectories with the Wii Balance Board. The strong point of experimental system was practical, reliable, and cheap. Results : As a result, it was found that the designed LDA discriminated difference of symmetric lifting between skilled experts and unskilled beginners with the error rate of 0.005. Discussion : It was discussed that not only most of unskilled beginners had mainly characteristics of poor lifting posture, but also the proposed method showed a high possibility to self-evaluate the symmetric lifting in order to check whether the current posture of logistic worker is proper or not.}, + booktitle = {2016 38th {Annual} {International} {Conference} of the {IEEE} {Engineering} in {Medicine} and {Biology} {Society} ({EMBC})}, + author = {Jeong, Hieyong and Kido, Michiko and Ohno, Yuko}, + month = aug, + year = {2016}, + note = {ISSN: 1557-170X}, + keywords = {Biomechanical Phenomena, CoP trajectory, Discriminant Analysis, Employment, Error analysis, Hip, Humans, LDA, Lifting, Linear discriminant analysis, Logistics, Posture, Principal component analysis, Trajectory, Wii Balance Board, biomechanics, center of pressure trajectory, intradiscal loads, lifting posture, linear discriminant analysis, logistic worker, lumbar discs, mass 18 kg, mechanoception, skilled logistic experts, symmetric lifting recognition, unskilled beginners}, + pages = {4573--4576} +} + +@misc{noauthor_8_nodate, + title = {(8) ({PDF}) {Gaussian} {Process} {Regression} for {Trajectory} {Analysis} {\textbar} {George} {Kachergis} - {Academia}.edu}, + url = {https://www.academia.edu/2986743/Gaussian_Process_Regression_for_Trajectory_Analysis}, + urldate = {2019-12-01} +} + +@inproceedings{cox_gaussian_2012, + title = {Gaussian {Process} {Regression} for {Trajectory} {Analysis}}, + abstract = {Cognitive scientists have begun collecting the trajectories of hand movements as participants make decisions in experiments. These response trajectories offer a ļ¬ne-grained glimpse into ongoing cognitive processes. For example, difļ¬cult decisions show more hesitation and deļ¬‚ection from the optimal path than easy decisions. However, many summary statistics used for trajectories throw away much information, or are correlated and thus partially redundant. To alleviate these issues, we introduce Gaussian process regression for the purpose of modeling trajectory data collected in psychology experiments. Gaussian processes are a well-developed statistical model that can ļ¬nd parametric differences in trajectories and their derivatives (e.g., velocity and acceleration) rather than a summary statistic. We show how Gaussian process regression can be implemented hierarchically across conditions and subjects, and used to model the actual shape and covariance of the trajectories. Finally, we demonstrate how to construct a generative hierarchical Bayesian model of trajectories using Gaussian processes.}, + language = {en}, + author = {Cox, Gregory E and Kachergis, George and Shiffrin, Richard M}, + year = {2012}, + pages = {6}, +} + + +@article{kareiva_analyzing_1983, + title = {Analyzing insect movement as a correlated random walk}, + volume = {56}, + issn = {1432-1939}, + doi = {10.1007/BF00379695}, + abstract = {This paper develops a procedure for quantifying movement sequences in terms of move length and turning angle probability distributions. By assuming that movement is a correlated random walk, we derive a formula that relates expected square displacements to the number of consecutive moves. We show this displacement formula can be used to highlight the consequences of different searching behaviors (i.e. different probability distributions of turning angles or move lengths). Observations of Pieris rapae (cabbage white butterfly) flight and Battus philenor (pipe-vine swallowtail) crawling are analyzed as a correlated random walk. The formula that we derive aptly predicts that net displacements of ovipositing cabbage white butterflies. In other circumstances, however, net displacements are not well-described by our correlated random walk formula; in these examples movement must represent a more complicated process than a simple correlated random walk. We suggest that progress might be made by analyzing these more complicated cases in terms of higher order markov processes.}, + language = {eng}, + number = {2-3}, + journal = {Oecologia}, + author = {Kareiva, P. M. and Shigesada, N.}, + month = feb, + year = {1983}, + pmid = {28310199}, + pages = {234--238} +} + + +@misc{noauthor_assessing_nodate-1, + title = {Assessing post-stroke behavior in mouse models of focal ischemia. - {PubMed} - {NCBI}}, + url = {https://www.ncbi.nlm.nih.gov/pubmed/23232947}, + urldate = {2019-11-25} +} + +@misc{noauthor_functional_nodate, + title = {Functional subdivisions of the rat somatic sensorimotor cortex - {Google} {Search}}, + url = {https://www.google.com/search?q=Functional+subdivisions+of+the+rat+somatic+sensorimotor+cortex&oq=Functional+subdivisions+of+the+rat+somatic+sensorimotor+cortex&aqs=chrome..69i57.281j0j7&sourceid=chrome&ie=UTF-8}, + urldate = {2019-11-25} +} + +@misc{noauthor_17_nodate, + title = {(17) ({PDF}) {Characterizing} {Visual} {Performance} in {Mice}: {An} {Objective} and {Automated} {System} {Based} on the {Optokinetic} {Reflex}}, + shorttitle = {(17) ({PDF}) {Characterizing} {Visual} {Performance} in {Mice}}, + url = {https://www.researchgate.net/publication/255984748_Characterizing_Visual_Performance_in_Mice_An_Objective_and_Automated_System_Based_on_the_Optokinetic_Reflex}, + abstract = {ResearchGate is a network dedicated to science and research. Connect, collaborate and discover scientific publications, jobs and conferences. All for free.}, + language = {en}, + urldate = {2019-11-25}, + journal = {ResearchGate} +} + +@misc{noauthor_17_nodate-1, + title = {(17) ({PDF}) {Behavioural} and endocrinological responses of mature male goldfish to the sex pheromone 17alpha,20beta-dihydroxy-4-pregnen-3-one in the water}, + url = {https://www.researchgate.net/publication/13904826_Behavioural_and_endocrinological_responses_of_mature_male_goldfish_to_the_sex_pheromone_17alpha20beta-dihydroxy-4-pregnen-3-one_in_the_water}, + abstract = {ResearchGate is a network dedicated to science and research. Connect, collaborate and discover scientific publications, jobs and conferences. All for free.}, + language = {en}, + urldate = {2019-11-25}, + journal = {ResearchGate} +} + +@misc{noauthor_use_nodate, + title = {Use of the {Open} {Field} {Maze} to measure locomotor and anxiety-like behavior in mice. - {PubMed} - {NCBI}}, + url = {https://www.ncbi.nlm.nih.gov/pubmed/25742564}, + urldate = {2019-11-25} +} + +@article{wang_modeling_2017, + title = {Modeling {Trajectory} as {Image}: {Convolutional} {Neural} {Networks} for {Multi}-scale {Taxi} {Trajectory} {Prediction}}, + shorttitle = {Modeling {Trajectory} as {Image}}, + url = {https://www.academia.edu/34767293/Modeling_Trajectory_as_Image_Convolutional_Neural_Networks_for_Multi-scale_Taxi_Trajectory_Prediction}, + abstract = {Precise destination prediction of Taxi trajectories can benefit both efficient schedule of taxies and accurate advertisement for customers.In this paper, we propose T-CONV, a novel trajectory prediction algorithm, which models trajectories as}, + language = {en}, + urldate = {2019-11-23}, + author = {Wang, Xintong}, + year = {2017}, +} + +@article{meng_overview_2019, + title = {An overview on trajectory outlier detection}, + volume = {52}, + issn = {1573-7462}, + url = {https://doi.org/10.1007/s10462-018-9619-1}, + doi = {10.1007/s10462-018-9619-1}, + abstract = {The task of trajectory outlier detection is to discover trajectories or their segments which differ substantially from or are inconsistent with the remaining set. In this paper, we make an overview on trajectory outlier detection algorithms from three aspects. Firstly, algorithms considering multi-attribute. In this kind of algorithms, as many key attributes as possible, such as speed, direction, position, time, are explored to represent the original trajectory and to compare with the others. Secondly, suitable distance metric. Many researches try to find or develop suitable distance metric which can measure the divergence between trajectories effectively and reliably. Thirdly, other studies attempt to improve existing algorithms to find outliers with less time and space complexity, and even more reliable. In this paper, we survey and summarize some classic trajectory outlier detection algorithms. In order to provide an overview, we analyze their features from the three dimensions above and discuss their benefits and shortcomings. It is hope that this review will serve as the steppingstone for those interested in advancing moving object outlier detection.}, + language = {en}, + number = {4}, + urldate = {2019-11-22}, + journal = {Artificial Intelligence Review}, + author = {Meng, Fanrong and Yuan, Guan and Lv, Shaoqian and Wang, Zhixiao and Xia, Shixiong}, + month = dec, + year = {2019}, + keywords = {Moving object data mining, Outlier detection, Spatial-temporal data, Trajectory}, + pages = {2437--2456} +} + +@article{graser_movingpandas_2019, + title = {{MovingPandas}: {Efficient} {Structures} for {Movement} {Data} in {Python}}, + volume = {Volume 7,}, + copyright = {Ɩsterreichische Akademie der Wissenschaften}, + issn = {2308-1708}, + shorttitle = {{MovingPandas}}, + url = {https://www.austriaca.at?arp=0x003aba2b}, + doi = {10.1553/giscience2019_01_s54}, + abstract = {Movement data analysis is a high-interest topic in many scientific domains. Even though Python is the scripting language of choice in the GIS world, currently there is no Python library that would enable researchers and practitioners to interact with and analyse movement data efficiently. To close this gap, we present MovingPandas, a new Python library for dealing with movement data. Its development is based on an analysis of state-of-the-art conceptual frameworks and existing implementations (in PostGIS, Hermes, and the R package trajectories). We describe how MovingPandas avoids limitations of Simple Feature-based movement data models commonly used to handle trajectories in the GIS world. Finally, we present the current state of the MovingPandas implementation and demonstrate its use in stand-alone Python scripts, as well as within the context of the desktop GIS application QGIS. This work represents the first step towards a general-purpose Python library that enables researchers and practitioners in the GIS field and beyond to handle and analyse movement data more efficiently}, + language = {de}, + urldate = {2021-02-02}, + journal = {GI\_Forum 2019,}, + author = {Graser, Anita}, + month = jun, + year = {2019}, + note = {Publisher: Verlag der Ɩsterreichischen Akademie der Wissenschaften}, + pages = {54--68}, +} + +@misc{word2vec, + title={Distributed Representations of Words and Phrases and their Compositionality}, + author={Tomas Mikolov and Ilya Sutskever and Kai Chen and Greg Corrado and Jeffrey Dean}, + year={2013}, + eprint={1310.4546}, + archivePrefix={arXiv}, + primaryClass={cs.CL} +} + +@article{huber_robust_1964, + title = {Robust {Estimation} of a {Location} {Parameter}}, + volume = {35}, + issn = {0003-4851, 2168-8990}, + url = {https://projecteuclid.org/euclid.aoms/1177703732}, + doi = {10.1214/aoms/1177703732}, + abstract = {This paper contains a new approach toward a theory of robust estimation; it treats in detail the asymptotic theory of estimating a location parameter for contaminated normal distributions, and exhibits estimators--intermediaries between sample mean and sample median--that are asymptotically most robust (in a sense to be specified) among all translation invariant estimators. For the general background, see Tukey (1960) (p. 448 ff.) Let x1,ā‹Æ,xnx1,ā‹Æ,xnx\_1, {\textbackslash}cdots, x\_n be independent random variables with common distribution function F(tāˆ’Ī¾)F(tāˆ’Ī¾)F(t - {\textbackslash}xi). The problem is to estimate the location parameter Ī¾Ī¾{\textbackslash}xi, but with the complication that the prototype distribution F(t)F(t)F(t) is only approximately known. I shall primarily be concerned with the model of indeterminacy F=(1āˆ’Ļµ)Ī¦+ĻµHF=(1āˆ’Ļµ)Ī¦+ĻµHF = (1 - {\textbackslash}epsilon){\textbackslash}Phi + {\textbackslash}epsilon H, where 0ā‰¦Ļµ{\textless}10ā‰¦Ļµ{\textless}10 {\textbackslash}leqq {\textbackslash}epsilon {\textless} 1 is a known number, Ī¦(t)=(2Ļ€)āˆ’12āˆ«tāˆ’āˆžexp(āˆ’12s2)dsĪ¦(t)=(2Ļ€)āˆ’12āˆ«āˆ’āˆžtexpā”(āˆ’12s2)ds{\textbackslash}Phi(t) = (2{\textbackslash}pi){\textasciicircum}\{-{\textbackslash}frac\{1\}\{2\}\} {\textbackslash}int{\textasciicircum}t\_\{-{\textbackslash}infty\} {\textbackslash}exp(-{\textbackslash}frac\{1\}\{2\}s{\textasciicircum}2) ds is the standard normal cumulative and HHH is an unknown contaminating distribution. This model arises for instance if the observations are assumed to be normal with variance 1, but a fraction ĻµĻµ{\textbackslash}epsilon of them is affected by gross errors. Later on, I shall also consider other models of indeterminacy, e.g., supt{\textbar}F(t)āˆ’Ī¦(t){\textbar}ā‰¦Ļµsupt{\textbar}F(t)āˆ’Ī¦(t){\textbar}ā‰¦Ļµ{\textbackslash}sup\_t {\textbar}F(t) - {\textbackslash}Phi(t){\textbar} {\textbackslash}leqq {\textbackslash}epsilon. Some inconvenience is caused by the fact that location and scale parameters are not uniquely determined: in general, for fixed ĻµĻµ{\textbackslash}epsilon, there will be several values of Ī¾Ī¾{\textbackslash}xi and ĻƒĻƒ{\textbackslash}sigma such that supt{\textbar}F(t)āˆ’Ī¦((tāˆ’Ī¾)/Ļƒ){\textbar}ā‰¦Ļµsupt{\textbar}F(t)āˆ’Ī¦((tāˆ’Ī¾)/Ļƒ){\textbar}ā‰¦Ļµ{\textbackslash}sup\_t{\textbar}F(t) - {\textbackslash}Phi((t - {\textbackslash}xi)/{\textbackslash}sigma){\textbar} {\textbackslash}leqq {\textbackslash}epsilon, and similarly for the contaminated case. Although this inherent and unavoidable indeterminacy is small if ĻµĻµ{\textbackslash}epsilon is small and is rather irrelevant for practical purposes, it poses awkward problems for the theory, especially for optimality questions. To remove this difficulty, one may either (i) restrict attention to symmetric distributions, and estimate the location of the center of symmetry (this works for Ī¾Ī¾{\textbackslash}xi but not for ĻƒĻƒ{\textbackslash}sigma); or (ii) one may define the parameter to be estimated in terms of the estimator itself, namely by its asymptotic value for sample size nā†’āˆžnā†’āˆžn {\textbackslash}rightarrow {\textbackslash}infty; or (iii) one may define the parameters by arbitrarily chosen functionals of the distribution (e.g., by the expectation, or the median of FFF). All three possibilities have unsatisfactory aspects, and I shall usually choose the variant which is mathematically most convenient. It is interesting to look back to the very origin of the theory of estimation, namely to Gauss and his theory of least squares. Gauss was fully aware that his main reason for assuming an underlying normal distribution and a quadratic loss function was mathematical, i.e., computational, convenience. In later times, this was often forgotten, partly because of the central limit theorem. However, if one wants to be honest, the central limit theorem can at most explain why many distributions occurring in practice are approximately normal. The stress is on the word "approximately." This raises a question which could have been asked already by Gauss, but which was, as far as I know, only raised a few years ago (notably by Tukey): What happens if the true distribution deviates slightly from the assumed normal one? As is now well known, the sample mean then may have a catastrophically bad performance: seemingly quite mild deviations may already explode its variance. Tukey and others proposed several more robust substitutes--trimmed means, Winsorized means, etc.--and explored their performance for a few typical violations of normality. A general theory of robust estimation is still lacking; it is hoped that the present paper will furnish the first few steps toward such a theory. At the core of the method of least squares lies the idea to minimize the sum of the squared "errors," that is, to adjust the unknown parameters such that the sum of the squares of the differences between observed and computed values is minimized. In the simplest case, with which we are concerned here, namely the estimation of a location parameter, one has to minimize the expression āˆ‘i(xiāˆ’T)2āˆ‘i(xiāˆ’T)2{\textbackslash}sum\_i (x\_i - T){\textasciicircum}2; this is of course achieved by the sample mean T=āˆ‘ixi/nT=āˆ‘ixi/nT = {\textbackslash}sum\_i x\_i/n. I should like to emphasize that no loss function is involved here; I am only describing how the least squares estimator is defined, and neither the underlying family of distributions nor the true value of the parameter to be estimated enters so far. It is quite natural to ask whether one can obtain more robustness by minimizing another function of the errors than the sum of their squares. We shall therefore concentrate our attention to estimators that can be defined by a minimum principle of the form (for a location parameter): T=Tn(x1,ā‹Æ,xn)minimizesāˆ‘iĻ(xiāˆ’T),T=Tn(x1,ā‹Æ,xn)minimizesāˆ‘iĻ(xiāˆ’T),T = T\_n(x\_1, {\textbackslash}cdots, x\_n) minimizes {\textbackslash}sum\_i {\textbackslash}rho(x\_i - T), whereĻisanonāˆ’constantfunction.(M)(M)whereĻisanonāˆ’constantfunction.{\textbackslash}begin\{equation*\} {\textbackslash}tag\{M\} where {\textbackslash}rho is a non-constant function. {\textbackslash}end\{equation*\} Of course, this definition generalizes at once to more general least squares type problems, where several parameters have to be determined. This class of estimators contains in particular (i) the sample mean (Ļ(t)=t2)(Ļ(t)=t2)({\textbackslash}rho(t) = t{\textasciicircum}2), (ii) the sample median (Ļ(t)={\textbar}t{\textbar})(Ļ(t)={\textbar}t{\textbar})({\textbackslash}rho(t) = {\textbar}t{\textbar}), and more generally, (iii) all maximum likelihood estimators (Ļ(t)=āˆ’logf(t)(Ļ(t)=āˆ’logā”f(t)({\textbackslash}rho(t) = -{\textbackslash}log f(t), where fff is the assumed density of the untranslated distribution). These (MMM)-estimators, as I shall call them for short, have rather pleasant asymptotic properties; sufficient conditions for asymptotic normality and an explicit expression for their asymptotic variance will be given. How should one judge the robustness of an estimator Tn(x)=Tn(x1,ā‹Æ,xn)Tn(x)=Tn(x1,ā‹Æ,xn)T\_n(x) = T\_n(x\_1, {\textbackslash}cdots, x\_n)? Since ill effects from contamination are mainly felt for large sample sizes, it seems that one should primarily optimize large sample robustness properties. Therefore, a convenient measure of robustness for asymptotically normal estimators seems to be the supremum of the asymptotic variance (nā†’āˆž)(nā†’āˆž)(n {\textbackslash}rightarrow {\textbackslash}infty) when FFF ranges over some suitable set of underlying distributions, in particular over the set of all F=(1āˆ’Ļµ)Ī¦+ĻµHF=(1āˆ’Ļµ)Ī¦+ĻµHF = (1 - {\textbackslash}epsilon){\textbackslash}Phi + {\textbackslash}epsilon H for fixed ĻµĻµ{\textbackslash}epsilon and symmetric HHH. On second thought, it turns out that the asymptotic variance is not only easier to handle, but that even for moderate values of nnn it is a better measure of performance than the actual variance, because (i) the actual variance of an estimator depends very much on the behavior of the tails of HHH, and the supremum of the actual variance is infinite for any estimator whose value is always contained in the convex hull of the observations. (ii) If an estimator is asymptotically normal, then the important central part of its distribution and confidence intervals for moderate confidence levels can better be approximated in terms of the asymptotic variance than in terms of the actual variance. If we adopt this measure of robustness, and if we restrict attention to (MMM)-estimators, then it will be shown that the most robust estimator is uniquely determined and corresponds to the following Ļ:Ļ(t)=12t2Ļ:Ļ(t)=12t2{\textbackslash}rho:{\textbackslash}rho(t) = {\textbackslash}frac\{1\}\{2\}t{\textasciicircum}2 for {\textbar}t{\textbar}{\textless}k,Ļ(t)=k{\textbar}t{\textbar}āˆ’12k2{\textbar}t{\textbar}{\textless}k,Ļ(t)=k{\textbar}t{\textbar}āˆ’12k2{\textbar}t{\textbar} {\textless} k, {\textbackslash}rho(t) = k{\textbar}t{\textbar} - {\textbackslash}frac\{1\}\{2\}k{\textasciicircum}2 for {\textbar}t{\textbar}ā‰§k{\textbar}t{\textbar}ā‰§k{\textbar}t{\textbar} {\textbackslash}geqq k, with kkk depending on ĻµĻµ{\textbackslash}epsilon. This estimator is most robust even among all translation invariant estimators. Sample mean (k=āˆž)(k=āˆž)(k = {\textbackslash}infty) and sample median (k=0)(k=0)(k = 0) are limiting cases corresponding to Ļµ=0Ļµ=0{\textbackslash}epsilon = 0 and Ļµ=1Ļµ=1{\textbackslash}epsilon = 1, respectively, and the estimator is closely related and asymptotically equivalent to Winsorizing. I recall the definition of Winsorizing: assume that the observations have been ordered, x1ā‰¦x2ā‰¦ā‹Æā‰¦xnx1ā‰¦x2ā‰¦ā‹Æā‰¦xnx\_1 {\textbackslash}leqq x\_2 {\textbackslash}leqq {\textbackslash}cdots {\textbackslash}leqq x\_n, then the statistic T=nāˆ’1(gxg+1+xg+1+xg+2+ā‹Æ+xnāˆ’h+hxnāˆ’h)T=nāˆ’1(gxg+1+xg+1+xg+2+ā‹Æ+xnāˆ’h+hxnāˆ’h)T = n{\textasciicircum}\{-1\}(gx\_\{g + 1\} + x\_\{g + 1\} + x\_\{g + 2\} + {\textbackslash}cdots + x\_\{n - h\} + hx\_\{n - h\}) is called the Winsorized mean, obtained by Winsorizing the ggg leftmost and the hhh rightmost observations. The above most robust (MMM)-estimators can be described by the same formula, except that in the first and in the last summand, the factors xg+1xg+1x\_\{g + 1\} and xnāˆ’hxnāˆ’hx\_\{n - h\} have to be replaced by some numbers u,vu,vu, v satisfying xgā‰¦uā‰¦xg+1xgā‰¦uā‰¦xg+1x\_g {\textbackslash}leqq u {\textbackslash}leqq x\_\{g + 1\} and xnāˆ’hā‰¦vā‰¦xnāˆ’h+1xnāˆ’hā‰¦vā‰¦xnāˆ’h+1x\_\{n - h\} {\textbackslash}leqq v {\textbackslash}leqq x\_\{n - h + 1\}, respectively; g,h,ug,h,ug, h, u and vvv depend on the sample. In fact, this (MMM)-estimator is the maximum likelihood estimator corresponding to a unique least favorable distribution F0F0F\_0 with density f0(t)=(1āˆ’Ļµ)(2Ļ€)āˆ’12eāˆ’Ļ(t)f0(t)=(1āˆ’Ļµ)(2Ļ€)āˆ’12eāˆ’Ļ(t)f\_0(t) = (1 - {\textbackslash}epsilon)(2{\textbackslash}pi){\textasciicircum}\{-{\textbackslash}frac\{1\}\{2\}\}e{\textasciicircum}\{-{\textbackslash}rho(t)\}. This f0f0f\_0 behaves like a normal density for small ttt, like an exponential density for large ttt. At least for me, this was rather surprising--I would have expected an f0f0f\_0 with much heavier tails. This result is a particular case of a more general one that can be stated roughly as follows: Assume that FFF belongs to some convex set CCC of distribution functions. Then the most robust (MMM)-estimator for the set CCC coincides with the maximum likelihood estimator for the unique F0ĪµCF0ĪµCF\_0 {\textbackslash}varepsilon C which has the smallest Fisher information number I(F)=āˆ«(fā€²/f)2fdtI(F)=āˆ«(fā€²/f)2fdtI(F) = {\textbackslash}int (f'/f){\textasciicircum}2f dt among all FĪµCFĪµCF {\textbackslash}varepsilon C. Miscellaneous related problems will also be treated: the case of non-symmetric contaminating distributions; the most robust estimator for the model of indeterminacy supt{\textbar}F(t)āˆ’Ī¦(t){\textbar}ā‰¦Ļµsupt{\textbar}F(t)āˆ’Ī¦(t){\textbar}ā‰¦Ļµ{\textbackslash}sup\_t{\textbar}F(t) - {\textbackslash}Phi(t){\textbar} {\textbackslash}leqq {\textbackslash}epsilon; robust estimation of a scale parameter; how to estimate location, if scale and ĻµĻµ{\textbackslash}epsilon are unknown; numerical computation of the estimators; more general estimators, e.g., minimizing āˆ‘i{\textless}jĻ(xiāˆ’T,xjāˆ’T)āˆ‘i{\textless}jĻ(xiāˆ’T,xjāˆ’T){\textbackslash}sum\_\{i {\textless} j\} {\textbackslash}rho(x\_i - T, x\_j - T), where ĻĻ{\textbackslash}rho is a function of two arguments. Questions of small sample size theory will not be touched in this paper.}, + language = {EN}, + number = {1}, + urldate = {2021-02-03}, + journal = {Annals of Mathematical Statistics}, + author = {Huber, Peter J.}, + month = mar, + year = {1964}, + mrnumber = {MR161415}, + zmnumber = {0136.39805}, + note = {Publisher: Institute of Mathematical Statistics}, + pages = {73--101}, +} + +@article{franke_analysis_2004, + title = {Analysis of movements and behavior of caribou ({Rangifer} tarandus) using hidden {Markov} models}, + volume = {173}, + issn = {0304-3800}, + url = {http://www.sciencedirect.com/science/article/pii/S0304380003003983}, + doi = {10.1016/j.ecolmodel.2003.06.004}, + abstract = {We explore how doubly stochastic, multiple-observation hidden Markov models (HMMs) may infer meaningful descriptions of woodland caribou (Rangifer tarandus) movement and behavior. Parameterized models allowed us to predict behavioral states (bedding, feeding and relocating), relative bout length and transitions, as well as most likely behavioral state sequences. Identification of state transitions and bout lengths appear specific to individuals and may identify dissimilar strategies of resource selection, behavior-specific habitats that are more important than is simply suggested by time spent there (pattern) and transitions between the same or different states that may be evidence for decision-making (process). Using only estimated model parameters, multiple-observation HMMs permitted us to successfully simulate movement and behavior representative of individual caribou through space and time.}, + language = {en}, + number = {2}, + urldate = {2019-12-22}, + journal = {Ecological Modelling}, + author = {Franke, Alastair and Caelli, Terry and Hudson, Robert J}, + month = apr, + year = {2004}, + keywords = {Activity, Animal behavior, Animal movement, Hidden Markov model, Resource selection}, + pages = {259--270}, +} + +@book{hastie01statisticallearning, + added-at = {2008-05-16T16:17:42.000+0200}, + address = {New York, NY, USA}, + author = {Hastie, Trevor and Tibshirani, Robert and Friedman, Jerome}, + biburl = {https://www.bibsonomy.org/bibtex/2f58afc5c9793fcc8ad8389824e57984c/sb3000}, + interhash = {d585aea274f2b9b228fc1629bc273644}, + intrahash = {f58afc5c9793fcc8ad8389824e57984c}, + keywords = {ml statistics}, + publisher = {Springer New York Inc.}, + series = {Springer Series in Statistics}, + timestamp = {2008-05-16T16:17:43.000+0200}, + title = {The Elements of Statistical Learning}, + year = 2001 +} + +@article{holzmann_hidden_2006, + title = {Hidden {Markov} models for circular and linear-circular time series}, + volume = {13}, + issn = {1352-8505, 1573-3009}, + url = {http://link.springer.com/10.1007/s10651-006-0015-7}, + doi = {10.1007/s10651-006-0015-7}, + number = {3}, + journal = {Environmental and Ecological Statistics}, + author = {Holzmann, Hajo and Munk, Axel and Suster, Max and Zucchini, Walter}, + year = {2006}, + note = {Type: Journal Article}, + pages = {325--347}, +} + + +@article{richardson_power_2015, + title = {The power of automated behavioural homecage technologies in characterizing disease progression in laboratory mice: {A} review}, + volume = {163}, + issn = {0168-1591}, + shorttitle = {The power of automated behavioural homecage technologies in characterizing disease progression in laboratory mice}, + url = {http://www.sciencedirect.com/science/article/pii/S0168159114003050}, + doi = {10.1016/j.applanim.2014.11.018}, + abstract = {Behavioural changes that occur as animals become sick have been characterized in a number of species and include the less frequent occurrence of ā€˜luxury behavioursā€™ such as playing, grooming and socialization. ā€˜Sickness behavioursā€™ or behavioural changes following exposure to infectious agents, have been particularly well described; animals are typically less active, sleep more, exhibit postural changes and consume less food/water. Disease is frequently induced in laboratory mice to model pathophysiological processes and investigate potential therapies but despite what is known about behavioural changes as animals become sick, behavioural phenotyping of mice involved in disease studies is relatively rare. A detailed understanding of how behaviour changes as mice get sick could be applied to improve welfare of laboratory mice and support the underlying biomedical research. Specifically, characterizing behavioural changes in ill health could help those working with laboratory mice to recognize when refinements should be introduced, when severity limits are being approached and when humane endpoints should be implemented. Understanding how behaviour changes with illness may also help to identify compounds that have a clinical effect as well as when these agents act. There are an increasing number of automated systems to monitor the behaviour of laboratory mice in their homecages incorporating technologies such as the quantification of cage movement, automated video analysis and radiofrequency identification transponders/readers. Mouse models of neurodegenerative diseases particularly Huntington's disease have been well characterized using these systems and behavioural biomarkers of pathology, including changes in the animalsā€™ use of environmental enrichment, changes in food/water consumption and alterations in circadian rhythms, are now monitored by laboratories worldwide and used to refine studies and develop therapies. In contrast, automated behavioural technologies have not been used to characterize the behaviour of mice with systemic diseases such as cancer and liver disease. In this review, common behavioural changes that occur in animals with declining health will be discussed with an emphasis on progressive disease studies involving mice. Automated homecage behaviour recording technologies will then be summarized, studies in which these systems have been used to characterize the behaviour of mice with progressive diseases will be reviewed and the potential to apply automated technologies to refine disease studies involving mice will be discussed.}, + language = {en}, + urldate = {2019-11-21}, + journal = {Applied Animal Behaviour Science}, + author = {Richardson, Claire A.}, + month = feb, + year = {2015}, + keywords = {Animal welfare, Automated behavioural analysis, Disease, Humane endpoints, Mice, Replacement, reduction, refinement (3Rs)}, + pages = {19--27} +} + +@software{sgoldenlab_2021_4521178, + author = {sgoldenlab and + Jia Jie Choong and + Simon Nilsson and + Aasiya Islam and + sophihwang26}, + title = {sgoldenlab/simba: SimBA: release v1.3}, + month = feb, + year = 2021, + publisher = {Zenodo}, + version = {v1.3}, + doi = {10.5281/zenodo.4521178}, + url = {https://doi.org/10.5281/zenodo.4521178} +} + +@article {Hsu770271, + author = {Hsu, Alexander I. and Yttri, Eric A.}, + title = {B-SOiD: An Open Source Unsupervised Algorithm for Discovery of Spontaneous Behaviors}, + elocation-id = {770271}, + year = {2020}, + doi = {10.1101/770271}, + publisher = {Cold Spring Harbor Laboratory}, + abstract = {Capturing the performance of naturalistic behaviors remains a prohibitively difficult objective. Recent machine learning applications have enabled localization of limb position; however, position alone does not yield behavior. To provide a bridge from positions to actions and their kinematics, we developed Behavioral Segmentation of Open-field in DeepLabCut (B-SOiD). This unsupervised learning algorithm discovers natural patterns in position and extracts their inherent statistics. The cluster statistics are then used to train a machine learning algorithm to classify behaviors with greater speed and accuracy due to improved ability to generalize from subject to subject. Through the application of a novel fram-eshift paradigm, B-SOiD provides the fast temporal resolution required for comparison with neural activity. B-SOiD also provides high-resolution behavioral measures such as stride and grooming kinematics, that are difficult but critical to obtain, particularly in the study of pain, compulsion, and other neurological disorders. This open-source platform surpasses the current state of the field in its improved analytical accessibility, objectivity, and ease of use.}, + URL = {https://www.biorxiv.org/content/early/2020/03/07/770271}, + eprint = {https://www.biorxiv.org/content/early/2020/03/07/770271.full.pdf}, + journal = {bioRxiv} +} + +@software{vivek_hari_sridhar_2017_1134016, + author = {Vivek Hari Sridhar}, + title = {vivekhsridhar/tracktor: Tracktor}, + month = dec, + year = 2017, + publisher = {Zenodo}, + version = {tracktor}, + doi = {10.5281/zenodo.1134016}, + url = {https://doi.org/10.5281/zenodo.1134016} +} + + +@article{wijeyakulasuriya_machine_2020, + title = {Machine learning for modeling animal movement}, + volume = {15}, + url = {https://doi.org/10.1371/journal.pone.0235750}, + doi = {10.1371/journal.pone.0235750}, + abstract = {Animal movement drives important ecological processes such as migration and the spread of infectious disease. Current approaches to modeling animal tracking data focus on parametric models used to understand environmental effects on movement behavior and to fill in missing tracking data. Machine Learning and Deep learning algorithms are powerful and flexible predictive modeling tools but have rarely been applied to animal movement data. In this study we present a general framework for predicting animal movement that is a combination of two steps: first predicting movement behavioral states and second predicting the animalā€™s velocity. We specify this framework at the individual level as well as for collective movement. We use Random Forests, Neural and Recurrent Neural Networks to compare performance predicting one step ahead as well as long range simulations. We compare results against a custom constructed Stochastic Differential Equation (SDE) model. We apply this approach to high resolution ant movement data. We found that the individual level Machine Learning and Deep Learning methods outperformed the SDE model for one step ahead prediction. The SDE model did comparatively better at simulating long range movement behaviour. Of the Machine Learning and Deep Learning models the Long Short Term Memory (LSTM) individual level model did best at long range simulations. We also applied the Random Forest and LSTM individual level models to model gull migratory movement to demonstrate the generalizability of this framework. Machine Learning and deep learning models are easier to specify compared to traditional parametric movement models which can have restrictive assumptions. However, machine learning and deep learning models are less interpretable than parametric movement models. The type of model used should be determined by the goal of the study, if the goal is prediction, our study provides evidence that machine learning and deep learning models could be useful tools.}, + number = {7}, + journal = {PLOS ONE}, + author = {Wijeyakulasuriya, Dhanushi A. and Eisenhauer, Elizabeth W. and Shaby, Benjamin A. and Hanks, Ephraim M.}, + year = {2020}, + note = {Publisher: Public Library of Science}, + pages = {1--30}, +} + +@article{Mathisetal2018, + title={DeepLabCut: markerless pose estimation of user-defined body parts with deep learning}, + author = {Alexander Mathis and Pranav Mamidanna and Kevin M. Cury and Taiga Abe and Venkatesh N. Murthy and Mackenzie W. Mathis and Matthias Bethge}, + journal={Nature Neuroscience}, + year={2018}, + doi={10.1038/s41593-018-0209-y}, + url={https://www.nature.com/articles/s41593-018-0209-y} +} + + +@incollection{pytorch, +title = {PyTorch: An Imperative Style, High-Performance Deep Learning Library}, +author = {Paszke, Adam and Gross, Sam and Massa, Francisco and Lerer, Adam and Bradbury, James and Chanan, Gregory and Killeen, Trevor and Lin, Zeming and Gimelshein, Natalia and Antiga, Luca and Desmaison, Alban and Kopf, Andreas and Yang, Edward and DeVito, Zachary and Raison, Martin and Tejani, Alykhan and Chilamkurthy, Sasank and Steiner, Benoit and Fang, Lu and Bai, Junjie and Chintala, Soumith}, +booktitle = {Advances in Neural Information Processing Systems 32}, +editor = {H. Wallach and H. Larochelle and A. Beygelzimer and F. d\textquotesingle Alch\'{e}-Buc and E. Fox and R. Garnett}, +pages = {8024--8035}, +year = {2019}, +publisher = {Curran Associates, Inc.}, +url = {http://papers.neurips.cc/paper/9015-pytorch-an-imperative-style-high-performance-deep-learning-library.pdf} +} + +@inproceedings{zhou_micro_2018, + title = {Micro {Behaviors}: {A} {New} {Perspective} in {E}-commerce {Recommender} {Systems}}, + shorttitle = {Micro {Behaviors}}, + doi = {10.1145/3159652.3159671}, + abstract = {The explosive popularity of e-commerce sites has reshaped usersĀ» shopping habits and an increasing number of users prefer to spend more time shopping online. This evolution allows e-commerce sites to observe rich data about users. The majority of traditional recommender systems have focused on the macro interactions between users and items, i.e., the purchase history of a customer. However, within each macro interaction between a user and an item, the user actually performs a sequence of micro behaviors, which indicate how the user locates the item, what activities the user conducts on the item (e.g., reading the comments, carting, and ordering) and how long the user stays with the item. Such micro behaviors offer fine-grained and deep understandings about users and provide tremendous opportunities to advance recommender systems in e-commerce. However, exploiting micro behaviors for recommendations is rather limited, which motivates us to investigate e-commerce recommendations from a micro-behavior perspective in this paper. Particularly, we uncover the effects of micro behaviors on recommendations and propose an interpretable Recommendation framework RIB, which models inherently the sequence of mIcro Behaviors and their effects. Experimental results on datasets from a real e-commence site demonstrate the effectiveness of the proposed framework and the importance of micro behaviors for recommendations.}, + booktitle = {{WSDM}}, + author = {Zhou, Meizi and Ding, Zhuoye and Tang, Jiliang and Yin, Dawei}, + year = {2018}, + keywords = {E-commerce, E-commerce payment system, IBM Notes, Interaction, Online shopping, Recommender system} +} + +@article{pedregosa_scikit-learn:_2011, + title = {Scikit-learn: {Machine} {Learning} in {Python}}, + volume = {12}, + issn = {ISSN 1533-7928}, + shorttitle = {Scikit-learn}, + url = {http://www.jmlr.org/papers/v12/pedregosa11a.html}, + number = {Oct}, + urldate = {2019-11-06}, + journal = {Journal of Machine Learning Research}, + author = {Pedregosa, Fabian and Varoquaux, GaĆ«l and Gramfort, Alexandre and Michel, Vincent and Thirion, Bertrand and Grisel, Olivier and Blondel, Mathieu and Prettenhofer, Peter and Weiss, Ron and Dubourg, Vincent and Vanderplas, Jake and Passos, Alexandre and Cournapeau, David and Brucher, Matthieu and Perrot, Matthieu and Duchesnay, Ɖdouard}, + year = {2011}, + pages = {2825--2830} +} + +@article{singh_low-cost_2019, + title = {Low-cost solution for rodent home-cage behaviour monitoring}, + volume = {14}, + issn = {1932-6203}, + url = {https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0220751}, + doi = {10.1371/journal.pone.0220751}, + abstract = {In the current research on measuring complex behaviours/phenotyping in rodents, most of the experimental design requires the experimenter to remove the animal from its home-cage environment and place it in an unfamiliar apparatus (novel environment). This interaction may influence behaviour, general well-being, and the metabolism of the animal, affecting the phenotypic outcome even if the data collection method is automated. Most of the commercially available solutions for home-cage monitoring are expensive and usually lack the flexibility to be incorporated with existing home-cages. Here we present a low-cost solution for monitoring home-cage behaviour of rodents that can be easily incorporated to practically any available rodent home-cage. To demonstrate the use of our system, we reliably predict the sleep/wake state of mice in their home-cage using only video. We validate these results using hippocampal local field potential (LFP) and electromyography (EMG) data. Our approach provides a low-cost flexible methodology for high-throughput studies of sleep, circadian rhythm and rodent behaviour with minimal experimenter interference.}, + language = {en}, + number = {8}, + urldate = {2019-11-06}, + journal = {PLOS ONE}, + author = {Singh, Surjeet and Bermudez-Contreras, Edgar and Nazari, Mojtaba and Sutherland, Robert J. and Mohajerani, Majid H.}, + month = aug, + year = {2019}, + keywords = {Algorithms, Animal behavior, Cameras, Electromyography, Mice, Rodents, Sleep, Web-based applications}, + pages = {e0220751} +} + +@misc{noauthor_m-track:_nodate, + title = {M-{Track}: {A} {New} {Software} for {Automated} {Detection} of {Grooming} {Trajectories} in {Mice}}, + url = {https://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1005115}, + urldate = {2019-11-06}, + doi = {10.1371/journal.pcbi.1005115}, +} + +@article{jiang_trajectorynet:_2017, + title = {{TrajectoryNet}: {An} {Embedded} {GPS} {Trajectory} {Representation} for {Point}-based {Classification} {Using} {Recurrent} {Neural} {Networks}}, + shorttitle = {{TrajectoryNet}}, + url = {http://arxiv.org/abs/1705.02636}, + abstract = {Understanding and discovering knowledge from GPS (Global Positioning System) traces of human activities is an essential topic in mobility-based urban computing. We propose TrajectoryNet-a neural network architecture for point-based trajectory classification to infer real world human transportation modes from GPS traces. To overcome the challenge of capturing the underlying latent factors in the low-dimensional and heterogeneous feature space imposed by GPS data, we develop a novel representation that embeds the original feature space into another space that can be understood as a form of basis expansion. We also enrich the feature space via segment-based information and use Maxout activations to improve the predictive power of Recurrent Neural Networks (RNNs). We achieve over 98\% classification accuracy when detecting four types of transportation modes, outperforming existing models without additional sensory data or location-based prior knowledge.}, + urldate = {2019-11-06}, + journal = {arXiv:1705.02636 [cs]}, + author = {Jiang, Xiang and de Souza, Erico N. and Pesaranghader, Ahmad and Hu, Baifan and Silver, Daniel L. and Matwin, Stan}, + month = aug, + year = {2017}, + note = {arXiv: 1705.02636}, + keywords = {Computer Science - Artificial Intelligence, Computer Science - Computer Vision and Pattern Recognition, Computer Science - Machine Learning, H.2.8, I.2.1, I.2.6} +} +@article{zheng_trajectory_2015, + title = {Trajectory {Data} {Mining}: {An} {Overview}}, + shorttitle = {Trajectory {Data} {Mining}}, + url = {https://www.microsoft.com/en-us/research/publication/trajectory-data-mining-an-overview/}, + abstract = {The advances in location-acquisition and mobile computing techniques have generated massive spatial trajectory data, which represent the mobility of a diversity of moving objects, such as people, vehicles and animals. Many techniques have been proposed for processing, managing and mining trajectory data in the past decade, fostering a broad range of applications. In this article, ā€¦}, + language = {en-US}, + urldate = {2019-11-06}, + journal = {ACM Transaction on Intelligent Systems and Technology}, + author = {Zheng, Yu}, + month = sep, + year = {2015} +} + +@article{zheng_trajectory_2015-1, + title = {Trajectory {Data} {Mining}: {An} {Overview}}, + volume = {6}, + issn = {21576904}, + shorttitle = {Trajectory {Data} {Mining}}, + url = {http://dl.acm.org/citation.cfm?doid=2764959.2743025}, + doi = {10.1145/2743025}, + language = {en}, + number = {3}, + urldate = {2019-11-06}, + journal = {ACM Transactions on Intelligent Systems and Technology}, + author = {Zheng, Yu}, + month = may, + year = {2015}, + pages = {1--41} +} + +@article{calahorra_hydroxytyrosol_2019, + title = {Hydroxytyrosol, the {Major} {Phenolic} {Compound} of {Olive} {Oil}, as an {Acute} {Therapeutic} {Strategy} after {Ischemic} {Stroke}}, + volume = {11}, + copyright = {http://creativecommons.org/licenses/by/3.0/}, + url = {https://www.mdpi.com/2072-6643/11/10/2430}, + doi = {10.3390/nu11102430}, + abstract = {Stroke is one of the leading causes of adult disability worldwide. After ischemic stroke, damaged tissue surrounding the irreversibly damaged core of the infarct, the penumbra, is still salvageable and is therefore a target for acute therapeutic strategies. The Mediterranean diet (MD) has been shown to lower stroke risk. MD is characterized by increased intake of extra-virgin olive oil, of which hydroxytyrosol (HT) is the foremost phenolic component. This study investigates the effect of an HT-enriched diet directly after stroke on regaining motor and cognitive functioning, MRI parameters, neuroinflammation, and neurogenesis. Stroke mice on an HT diet showed increased strength in the forepaws, as well as improved short-term recognition memory probably due to improvement in functional connectivity (FC). Moreover, mice on an HT diet showed increased cerebral blood flow (CBF) and also heightened expression of brain derived neurotrophic factor (Bdnf), indicating a novel neurogenic potential of HT. This result was additionally accompanied by an enhanced transcription of the postsynaptic marker postsynaptic density protein 95 (Psd-95) and by a decreased ionized calcium-binding adapter molecule 1 (IBA-1) level indicative of lower neuroinflammation. These results suggest that an HT-enriched diet could serve as a beneficial therapeutic approach to attenuate ischemic stroke-associated damage.}, + language = {en}, + number = {10}, + urldate = {2019-11-05}, + journal = {Nutrients}, + author = {Calahorra, JesĆŗs and Shenk, Justin and Wielenga, Vera H. and Verweij, Vivienne and Geenen, Bram and Dederen, Pieter J. and Peinado, M. Ɓngeles and Siles, Eva and Wiesmann, Maximilian and Kiliaan, Amanda J.}, + month = oct, + year = {2019}, + keywords = {MRI, animal model, cerebral blood flow, cerebral connectivity, dietary treatment, hydroxytyrosol, neuroinflammation, stroke}, + pages = {2430} +} + +@article{iannello_non-intrusive_2019, + title = {Non-intrusive high throughput automated data collection from the home cage}, + volume = {5}, + issn = {2405-8440}, + doi = {10.1016/j.heliyon.2019.e01454}, + abstract = {Automated home cage monitoring represents a key technology to collect animal activity information directly from the home cage. The availability of 24/7 cage data enables extensive and quantitative assessment of mouse behavior and activity over long periods of time than possible otherwise. When home cage monitoring is performed directly at the home cage rack, it is possible to leverage additional advantages, including, e.g., partial (or total) reduction of animal handling, no need for setting up external data collection system as well as not requiring dedicated labs and personnel to perform tests. In this work we introduce a home cage-home rack monitoring system that is capable of continuously detecting spontaneous animal activity occurring in the home cage directly from the home cage rack. The proposed system is based on an electrical capacitance sensing technology that enables non-intrusive and continuous home cage monitoring. We then present a few animal activity metrics that are validated via comparison against a video camera-based tracking system. The results show that the proposed home-cage monitoring system can provide animal activity metrics that are comparable to the ones derived via a conventional video tracking system, with the advantage of system scalability, limited amount of both data generated and computational capabilities required to derive metrics.}, + language = {eng}, + number = {4}, + journal = {Heliyon}, + author = {Iannello, Fabio}, + month = apr, + year = {2019}, + pmid = {30997429}, + pmcid = {PMC6451168}, + keywords = {Bioengineering, Bioinformatics, Cancer research, Genetics, Neuroscience, Physiology, Toxicology}, + pages = {e01454} +} + +@article{pernold_towards_2019, + title = {Towards large scale automated cage monitoring ā€“ {Diurnal} rhythm and impact of interventions on in-cage activity of {C}57BL/6J mice recorded 24/7 with a non-disrupting capacitive-based technique}, + volume = {14}, + issn = {1932-6203}, + url = {https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6361443/}, + doi = {10.1371/journal.pone.0211063}, + abstract = {Background and aims +Automated recording of laboratory animalā€™s home cage behavior is receiving increasing attention since such non-intruding surveillance will aid in the unbiased understanding of animal cage behavior potentially improving animal experimental reproducibility. + +Material and methods +Here we investigate activity of group held female C57BL/6J mice (mus musculus) housed in standard Individually Ventilated Cages across three test-sites: Consiglio Nazionale delle Ricerche (CNR, Rome, Italy), The Jackson Laboratory (JAX, Bar Harbor, USA) and Karolinska Insititutet (KI, Stockholm, Sweden). Additionally, comparison of female and male C57BL/6J mice was done at KI. Activity was recorded using a capacitive-based sensor placed non-intrusively on the cage rack under the home cage collecting activity data every 250 msec, 24/7. The data collection was analyzed using non-parametric analysis of variance for longitudinal data comparing sites, weekdays and sex. + +Results +The system detected an increase in activity preceding and peaking around lights-on followed by a decrease to a rest pattern. At lights off, activity increased substantially displaying a distinct temporal variation across this period. We also documented impact on mouse activity that standard animal handling procedures have, e.g. cage-changes, and show that such procedures are stressors impacting in-cage activity., These key observations replicated across the three test-sites, however, it is also clear that, apparently minor local environmental differences generate significant behavioral variances between the sites and within sites across weeks. Comparison of gender revealed differences in activity in the response to cage-change lasting for days in male but not female mice; and apparently also impacting the response to other events such as lights-on in males. Females but not males showed a larger tendency for week-to-week variance in activity possibly reflecting estrous cycling. + +Conclusions +These data demonstrate that home cage monitoring is scalable and run in real time, providing complementary information for animal welfare measures, experimental design and phenotype characterization.}, + number = {2}, + urldate = {2019-11-05}, + journal = {PLoS ONE}, + author = {Pernold, Karin and Iannello, F. and Low, B. E. and Rigamonti, M. and Rosati, G. and Scavizzi, F. and Wang, J. and Raspa, M. and Wiles, M. V. and Ulfhake, B.}, + month = feb, + year = {2019}, + pmid = {30716111}, + pmcid = {PMC6361443} +} + +@article{liang_peeking_2019, + title = {Peeking into the {Future}: {Predicting} {Future} {Person} {Activities} and {Locations} in {Videos}}, + shorttitle = {Peeking into the {Future}}, + url = {http://arxiv.org/abs/1902.03748}, + abstract = {Deciphering human behaviors to predict their future paths/trajectories and what they would do from videos is important in many applications. Motivated by this idea, this paper studies predicting a pedestrian's future path jointly with future activities. We propose an end-to-end, multi-task learning system utilizing rich visual features about human behavioral information and interaction with their surroundings. To facilitate the training, the network is learned with an auxiliary task of predicting future location in which the activity will happen. Experimental results demonstrate our state-of-the-art performance over two public benchmarks on future trajectory prediction. Moreover, our method is able to produce meaningful future activity prediction in addition to the path. The result provides the first empirical evidence that joint modeling of paths and activities benefits future path prediction.}, + urldate = {2019-11-01}, + journal = {arXiv:1902.03748 [cs]}, + author = {Liang, Junwei and Jiang, Lu and Niebles, Juan Carlos and Hauptmann, Alexander and Fei-Fei, Li}, + month = may, + year = {2019}, + note = {arXiv: 1902.03748}, + doi = {10.1109/cvprw.2019.00358}, + keywords = {Computer Science - Computer Vision and Pattern Recognition} +} + +@article{amirian_social_2019, + title = {Social {Ways}: {Learning} {Multi}-{Modal} {Distributions} of {Pedestrian} {Trajectories} with {GANs}}, + shorttitle = {Social {Ways}}, + url = {http://arxiv.org/abs/1904.09507}, + abstract = {This paper proposes a novel approach for predicting the motion of pedestrians interacting with others. It uses a Generative Adversarial Network (GAN) to sample plausible predictions for any agent in the scene. As GANs are very susceptible to mode collapsing and dropping, we show that the recently proposed Info-GAN allows dramatic improvements in multi-modal pedestrian trajectory prediction to avoid these issues. We also left out L2-loss in training the generator, unlike some previous works, because it causes serious mode collapsing though faster convergence. We show through experiments on real and synthetic data that the proposed method leads to generate more diverse samples and to preserve the modes of the predictive distribution. In particular, to prove this claim, we have designed a toy example dataset of trajectories that can be used to assess the performance of different methods in preserving the predictive distribution modes.}, + urldate = {2019-11-01}, + journal = {arXiv:1904.09507 [cs]}, + author = {Amirian, Javad and Hayet, Jean-Bernard and Pettre, Julien}, + month = apr, + year = {2019}, + note = {arXiv: 1904.09507}, + doi = {10.1109/cvprw.2019.00359}, + keywords = {Computer Science - Computer Vision and Pattern Recognition} +} + +@article{chesler_identification_2002, + title = {Identification and ranking of genetic and laboratory environment factors influencing a behavioral trait, thermal nociception, via computational analysis of a large data archive}, + volume = {26}, + issn = {0149-7634}, + url = {http://www.sciencedirect.com/science/article/pii/S0149763402001033}, + doi = {10.1016/S0149-7634(02)00103-3}, + abstract = {Laboratory conditions in biobehavioral experiments are commonly assumed to be ā€˜controlledā€™, having little impact on the outcome. However, recent studies have illustrated that the laboratory environment has a robust effect on behavioral traits. Given that environmental factors can interact with trait-relevant genes, some have questioned the reliability and generalizability of behavior genetic research designed to identify those genes. This problem might be alleviated by the identification of the most relevant environmental factors, but the task is hindered by the large number of factors that typically vary between and within laboratories. We used a computational approach to retrospectively identify and rank sources of variability in nociceptive responses as they occurred in a typical research laboratory over several years. A machine-learning algorithm was applied to an archival data set of 8034 independent observations of baseline thermal nociceptive sensitivity. This analysis revealed that a factor even more important than mouse genotype was the experimenter performing the test, and that nociception can be affected by many additional laboratory factors including season/humidity, cage density, time of day, sex and within-cage order of testing. The results were confirmed by linear modeling in a subset of the data, and in confirmatory experiments, in which we were able to partition the variance of this complex trait among genetic (27\%), environmental (42\%) and geneticƗenvironmental (18\%) sources.}, + language = {en}, + number = {8}, + urldate = {2019-11-01}, + journal = {Neuroscience \& Biobehavioral Reviews}, + author = {Chesler, Elissa J and Wilson, Sonya G and Lariviere, William R and Rodriguez-Zas, Sandra L and Mogil, Jeffrey S}, + month = dec, + year = {2002}, + keywords = {CART, Data mining, Environment, Genetic, Mice, Nociception, Pain}, + pages = {907--923} +} + +@article{valletta_applications_2017, + title = {Applications of machine learning in animal behaviour studies}, + volume = {124}, + issn = {0003-3472}, + url = {http://www.sciencedirect.com/science/article/pii/S0003347216303360}, + doi = {10.1016/j.anbehav.2016.12.005}, + abstract = {In many areas of animal behaviour research, improvements in our ability to collect large and detailed data sets are outstripping our ability to analyse them. These diverse, complex and often high-dimensional data sets exhibit nonlinear dependencies and unknown interactions across multiple variables, and may fail to conform to the assumptions of many classical statistical methods. The field of machine learning provides methodologies that are ideally suited to the task of extracting knowledge from these data. In this review, we aim to introduce animal behaviourists unfamiliar with machine learning (ML) to the promise of these techniques for the analysis of complex behavioural data. We start by describing the rationale behind ML and review a number of animal behaviour studies where ML has been successfully deployed. The ML framework is then introduced by presenting several unsupervised and supervised learning methods. Following this overview, we illustrate key ML approaches by developing data analytical pipelines for three different case studies that exemplify the types of behavioural and ecological questions ML can address. The first uses a large number of spectral and morphological characteristics that describe the appearance of pheasant, Phasianus colchicus, eggs to assign them to putative clutches. The second takes a continuous data stream of feeder visits from PIT (passive integrated transponder)-tagged jackdaws, Corvus monedula, and extracts foraging events from it, which permits the construction of social networks. Our final example uses aerial images to train a classifier that detects the presence of wildebeest, Connochaetes taurinus, to count individuals in a population. With the advent of cheaper sensing and tracking technologies an unprecedented amount of data on animal behaviour is becoming available. We believe that ML will play a central role in translating these data into scientific knowledge and become a useful addition to the animal behaviourist's analytical toolkit.}, + language = {en}, + urldate = {2019-11-01}, + journal = {Animal Behaviour}, + author = {Valletta, John Joseph and Torney, Colin and Kings, Michael and Thornton, Alex and Madden, Joah}, + month = feb, + year = {2017}, + keywords = {animal behaviour data, classification, clustering, dimensionality reduction, machine learning, predictive modelling, random forests, social networks, supervised learning, unsupervised learning}, + pages = {203--220} +} + + +@article{kerster_spatial_2016, + title = {Spatial memory in foraging games}, + volume = {148}, + issn = {1873-7838}, + doi = {10.1016/j.cognition.2015.12.015}, + abstract = {Foraging and foraging-like processes are found in spatial navigation, memory, visual search, and many other search functions in human cognition and behavior. Foraging is commonly theorized using either random or correlated movements based on LĆ©vy walks, or a series of decisions to remain or leave proximal areas known as "patches". Neither class of model makes use of spatial memory, but search performance may be enhanced when information about searched and unsearched locations is encoded. A video game was developed to test the role of human spatial memory in a canonical foraging task. Analyses of search trajectories from over 2000 human players yielded evidence that foraging movements were inherently clustered, and that clustering was facilitated by spatial memory cues and influenced by memory for spatial locations of targets found. A simple foraging model is presented in which spatial memory is used to integrate aspects of LĆ©vy-based and patch-based foraging theories to perform a kind of area-restricted search, and thereby enhance performance as search unfolds. Using only two free parameters, the model accounts for a variety of findings that individually support competing theories, but together they argue for the integration of spatial memory into theories of foraging.}, + language = {eng}, + journal = {Cognition}, + author = {Kerster, Bryan E. and Rhodes, Theo and Kello, Christopher T.}, + month = mar, + year = {2016}, + pmid = {26752603}, + keywords = {Area-restricted search, Cognition, Feeding Behavior, Foraging, Humans, Search model, Spatial Behavior, Spatial memory, Spatial Memory, Spatial Navigation, Video Games}, + pages = {85--96}, +} + + +@article{ross_influence_2016, + title = {Influence of musical groove on postural sway}, + volume = {42}, + issn = {1939-1277(Electronic),0096-1523(Print)}, + doi = {10.1037/xhp0000198}, + abstract = {Timescales of postural fluctuation reflect underlying neuromuscular processes in balance control that are influenced by sensory information and the performance of concurrent cognitive and motor tasks. An open question is how postural fluctuations entrain to complex environmental rhythms, such as in music, which also vary on multiple timescales. Musical groove describes the property of music that encourages auditory-motor synchronization and is used to study voluntary motor entrainment to rhythmic sounds. The influence of groove on balance control mechanisms remains unexplored. We recorded fluctuations in center of pressure (CoP) of standing participants (N = 40) listening to low and high groove music and during quiet stance. We found an effect of musical groove on radial sway variability, with the least amount of variability in the high groove condition. In addition, we observed that groove influenced postural sway entrainment at various temporal scales. For example, with increasing levels of groove, we observed more entrainment to shorter, local timescale rhythmic musical occurrences. In contrast, we observed more entrainment to longer, global timescale features of the music, such as periodicity, with decreasing levels of groove. Finally, musical experience influenced the amount of postural variability and entrainment at local and global timescales. We conclude that groove in music and musical experience can influence the neural mechanisms that govern balance control, and discuss implications of our findings in terms of multiscale sensorimotor coupling. (PsycINFO Database Record (c) 2016 APA, all rights reserved)}, + number = {3}, + journal = {Journal of Experimental Psychology: Human Perception and Performance}, + author = {Ross, Jessica M. and Warlaumont, Anne S. and Abney, Drew H. and Rigoli, Lillian M. and Balasubramaniam, Ramesh}, + year = {2016}, + note = {Place: US +Publisher: American Psychological Association}, + keywords = {Auditory Stimulation, Motor Processes, Music, Posture, Rhythm}, + pages = {308--319}, + file = {Snapshot:/Users/justinshenk/Zotero/storage/DNH9UD9R/2015-58954-001.html:text/html}, +} + +@article{ayers, +author = {Ayers, Carolyn and Armsworth, Paul and Brosi, Berry}, +year = {2015}, +month = {08}, +pages = {}, +title = {Determinism as a statistical metric for ecologically important recurrent behaviors with trapline foraging as a case study}, +volume = {69}, +journal = {Behavioral Ecology and Sociobiology}, +doi = {10.1007/s00265-015-1948-3} +} + +@article{morato_jaguar_2018, + title = {Jaguar movement database: a {GPS}-based movement dataset of an apex predator in the {Neotropics}}, + volume = {99}, + copyright = {Ā© 2018 The Authors. Ecology Ā© 2018 The Ecological Society of America.}, + issn = {1939-9170}, + shorttitle = {Jaguar movement database}, + url = {https://esajournals.onlinelibrary.wiley.com/doi/abs/10.1002/ecy.2379}, + doi = {10.1002/ecy.2379}, + abstract = {The field of movement ecology has rapidly grown during the last decade, with important advancements in tracking devices and analytical tools that have provided unprecedented insights into where, when, and why species move across a landscape. Although there has been an increasing emphasis on making animal movement data publicly available, there has also been a conspicuous dearth in the availability of such data on large carnivores. Globally, large predators are of conservation concern. However, due to their secretive behavior and low densities, obtaining movement data on apex predators is expensive and logistically challenging. Consequently, the relatively small sample sizes typical of large carnivore movement studies may limit insights into the ecology and behavior of these elusive predators. The aim of this initiative is to make available to the conservation-scientific community a dataset of 134,690 locations of jaguars (Panthera onca) collected from 117 individuals (54 males and 63 females) tracked by GPS technology. Individual jaguars were monitored in five different range countries representing a large portion of the speciesā€™ distribution. This dataset may be used to answer a variety of ecological questions including but not limited to: improved models of connectivity from local to continental scales; the use of natural or human-modified landscapes by jaguars; movement behavior of jaguars in regions not represented in this dataset; intraspecific interactions; and predator-prey interactions. In making our dataset publicly available, we hope to motivate other research groups to do the same in the near future. Specifically, we aim to help inform a better understanding of jaguar movement ecology with applications towards effective decision making and maximizing long-term conservation efforts for this ecologically important species. There are no costs, copyright, or proprietary restrictions associated with this data set. When using this data set, please cite this article to recognize the effort involved in gathering and collating the data and the willingness of the authors to make it publicly available.}, + language = {en}, + number = {7}, + urldate = {2021-06-04}, + journal = {Ecology}, + author = {Morato, Ronaldo G. and Thompson, Jeffrey J. and Paviolo, Agustin and Torre, Jesus A. de La and Lima, Fernando and McBride, Roy T. and Paula, Rogerio C. and Cullen, Laury and Silveira, Leandro and Kantek, Daniel L. Z. and Ramalho, Emiliano E. and MaranhĆ£o, Louise and Haberfeld, Mario and Sana, Denis A. and Medellin, Rodrigo A. and Carrillo, Eduardo and Montalvo, Victor and Monroy-Vilchis, Octavio and Cruz, Paula and Jacomo, Anah T. and Torres, Natalia M. and Alves, Giselle B. and Cassaigne, Ivonne and Thompson, Ron and Saens-Bolanos, Carolina and Cruz, Juan Carlos and Alfaro, Luiz D. and Hagnauer, Isabel and Silva, Xavier Marina da and Vogliotti, Alexandre and Moraes, Marcela F. D. and Miyazaki, Selma S. and Pereira, Thadeu D. C. and Araujo, Gediendson R. and Silva, Leanes Cruz da and Leuzinger, Lucas and Carvalho, Marina M. and Rampin, Lilian and Sartorello, Leonardo and Quigley, Howard and Tortato, Fernando and Hoogesteijn, Rafael and Crawshaw, Peter G. and Devlin, Allison L. and May, Joares A. and Azevedo, Fernando C. C. de and Concone, Henrique V. B. and Quiroga, Veronica A. and Costa, Sebastian A. and Arrabal, Juan P. and Vanderhoeven, Ezequiel and Blanco, Yamil E. Di and Lopes, Alexandre M. C. and Widmer, Cynthia E. and Ribeiro, Milton Cezar}, + year = {2018}, + note = {\_eprint: https://esajournals.onlinelibrary.wiley.com/doi/pdf/10.1002/ecy.2379}, + keywords = {behavior, conservation, GPS radio-collars, habitat use, landscape, movement ecology, Panthera onca}, + pages = {1691--1691}, + file = {Full Text PDF:/Users/justinshenk/Zotero/storage/FG8IDDP7/Morato et al. - 2018 - Jaguar movement database a GPS-based movement dat.pdf:application/pdf;Snapshot:/Users/justinshenk/Zotero/storage/FJT5T8D9/ecy.html:text/html}, +} + +@article{neves_recurrence_2017, + title = {Recurrence analysis of ant activity patterns}, + volume = {12}, + url = {https://doi.org/10.1371/journal.pone.0185968}, + doi = {10.1371/journal.pone.0185968}, + abstract = {In this study, we used recurrence quantification analysis (RQA) and recurrence plots (RPs) to compare the movement activity of individual workers of three ant species, as well as a gregarious beetle species. RQA and RPs quantify the number and duration of recurrences of a dynamical system, including a detailed quantification of signals that could be stochastic, deterministic, or both. First, we found substantial differences between the activity dynamics of beetles and ants, with the results suggesting that the beetles have quasi-periodic dynamics and the ants do not. Second, workers from different ant species varied with respect to their dynamics, presenting degrees of predictability as well as stochastic signals. Finally, differences were found among minor and major caste of the same (dimorphic) ant species. Our results underscore the potential of RQA and RPs in the analysis of complex behavioral patterns, as well as in general inferences on animal behavior and other biological phenomena.}, + number = {10}, + journal = {PLOS ONE}, + author = {Neves, Felipe Marcel and Viana, Ricardo Luiz and Pie, Marcio Roberto}, + year = {2017}, + note = {Publisher: Public Library of Science}, + pages = {1--15}, +} + +@article{shockley, +author = {Shockley, Kevin and Santana, Marie-Vee and Fowler, Carol}, +year = {2003}, +month = {05}, +pages = {326-32}, +title = {Mutual Interpersonal Postural Constraints are Involved in Cooperative Conversation}, +volume = {29}, +journal = {Journal of experimental psychology. Human perception and performance}, +doi = {10.1037/0096-1523.29.2.326} +} + +@article{huette_drawing_2013, + title = {Drawing from {Memory}: {Hand}-{Eye} {Coordination} at {Multiple} {Scales}}, + volume = {8}, + shorttitle = {Drawing from {Memory}}, + doi = {10.1371/journal.pone.0058464}, + abstract = {Eyes move to gather visual information for the purpose of guiding behavior. This guidance takes the form of perceptual-motor interactions on short timescales for behaviors like locomotion and hand-eye coordination. More complex behaviors require perceptual-motor interactions on longer timescales mediated by memory, such as navigation, or designing and building artifacts. In the present study, the task of sketching images of natural scenes from memory was used to examine and compare perceptual-motor interactions on shorter and longer timescales. Eye and pen trajectories were found to be coordinated in time on shorter timescales during drawing, and also on longer timescales spanning study and drawing periods. The latter type of coordination was found by developing a purely spatial analysis that yielded measures of similarity between images, eye trajectories, and pen trajectories. These results challenge the notion that coordination only unfolds on short timescales. Rather, the task of drawing from memory evokes perceptual-motor encodings of visual images that preserve coarse-grained spatial information over relatively long timescales as well.}, + journal = {PloS one}, + author = {Huette, Stephanie and Kello, Christopher and Rhodes, Theo and Spivey, Michael}, + month = mar, + year = {2013}, + pages = {e58464}, + file = {Full Text PDF:/Users/justinshenk/Zotero/storage/JZ4JJ7T7/Huette et al. - 2013 - Drawing from Memory Hand-Eye Coordination at Mult.pdf:application/pdf}, +} + + +@article{clustering_mice, +author = {Bak, Peter and Mansmann, Florian and Janetzko, Halldor and Keim, Daniel}, +year = {2009}, +month = {11}, +pages = {913-20}, +title = {Spatiotemporal Analysis of Sensor Logs using Growth Ring Maps}, +volume = {15}, +journal = {IEEE transactions on visualization and computer graphics}, +doi = {10.1109/TVCG.2009.182} +} + +@article{huang_mapping_2020, + title = {Mapping {Mouse} {Behavior} with an {Unsupervised} {Spatio}-temporal {Sequence} {Decomposition} {Framework}}, + url = {https://www.biorxiv.org/content/early/2020/09/14/2020.09.14.295808}, + doi = {10.1101/2020.09.14.295808}, + abstract = {Objective quantification of animal behavior is crucial to understanding the relationship between brain activity and behavior. For rodents, this has remained a challenge due to the high-dimensionality and large temporal variability of their behavioral features. Inspired by the natural structure of animal behavior, the present study uses a parallel, multi-stage approach to decompose motion features and generate an objective metric for mapping rodent behavior into the animalā€™s feature space. Incorporating a three-dimensional (3D) motion-capture system and unsupervised clustering into this approach, we developed a framework that can automatically identify animal behavioral phenotypes from experimental monitoring. We demonstrate the efficacy of our framework by generating an ā€œautistic-like behavior spaceā€ that can robustly characterize a transgenic mouse disease model based on motor activity without human supervision. Our results suggest that our framework features a broad range of applications, including animal disease model phenotyping and the modeling of relationships between neural circuits and behavior.Competing Interest StatementThe authors have declared no competing interest.}, + journal = {bioRxiv}, + author = {Huang, Kang and Han, Yaning and Chen, Ke and Pan, Hongli and Yi, Wenling and Li, Xiaoxi and Liu, Siyuan and Wei, Pengfei and Wang, Liping}, + year = {2020}, + note = {Publisher: Cold Spring Harbor Laboratory +\_eprint: https://www.biorxiv.org/content/early/2020/09/14/2020.09.14.295808.full.pdf}, +} + + +@article{mclean_trajr:_2018, + title = {trajr: {An} {R} package for characterisation of animal trajectories}, + volume = {124}, + copyright = {Ā© 2018 The Authors. Ethology Published by Blackwell Verlag GmbH}, + issn = {1439-0310}, + shorttitle = {trajr}, + url = {https://onlinelibrary.wiley.com/doi/abs/10.1111/eth.12739}, + doi = {10.1111/eth.12739}, + abstract = {Quantitative characterisation of the trajectories of moving animals is an important component of many behavioural and ecological studies, however methods are complicated and varied, and sometimes require well-developed programming skills to implement. Here, we introduce trajr, an R package that serves to analyse animal paths, from unicellular organisms, through insects to whales. It makes a variety of statistical characterisations of trajectories, such as tortuosity, speed and changes in direction, available to biologists who may not have a background in programming. We discuss a range of indices that have been used by researchers, describe the package in detail, then use movement observations of whales and clearwing moths to demonstrate some of the capabilities of trajr. As an open-source R package, trajr encourages open and reproducible research. It supports the implementation of additional methods by providing access to trajectory analysis ā€œbuilding blocks,ā€ allows the full suite of R statistical analysis tools to be applied to trajectory analysis, and the source code can be independently validated.}, + language = {en}, + number = {6}, + urldate = {2019-07-30}, + journal = {Ethology}, + author = {McLean, Donald James and Volponi, Marta A. Skowron}, + year = {2018}, + keywords = {behaviour, locomotor mimicry, navigation, speed, tortuosity, whales}, + pages = {440--448} +} + +@article{mullner_modern_2011, + title = {Modern hierarchical, agglomerative clustering algorithms}, + url = {http://arxiv.org/abs/1109.2378}, + abstract = {This paper presents algorithms for hierarchical, agglomerative clustering which perform most efficiently in the general-purpose setup that is given in modern standard software. Requirements are: (1) the input data is given by pairwise dissimilarities between data points, but extensions to vector data are also discussed (2) the output is a "stepwise dendrogram", a data structure which is shared by all implementations in current standard software. We present algorithms (old and new) which perform clustering in this setting efficiently, both in an asymptotic worst-case analysis and from a practical point of view. The main contributions of this paper are: (1) We present a new algorithm which is suitable for any distance update scheme and performs significantly better than the existing algorithms. (2) We prove the correctness of two algorithms by Rohlf and Murtagh, which is necessary in each case for different reasons. (3) We give well-founded recommendations for the best current algorithms for the various agglomerative clustering schemes.}, + urldate = {2019-07-29}, + journal = {arXiv:1109.2378 [cs, stat]}, + author = {MĆ¼llner, Daniel}, + month = sep, + year = {2011}, + note = {arXiv: 1109.2378}, + keywords = {62H30, Computer Science - Data Structures and Algorithms, I.5.3, Statistics - Machine Learning} +} + +@article{chaumont_live_2018, + title = {Live {Mouse} {Tracker}: real-time behavioral analysis of groups of mice}, + copyright = {Ā© 2018, Posted by Cold Spring Harbor Laboratory. This pre-print is available under a Creative Commons License (Attribution 4.0 International), CC BY 4.0, as described at http://creativecommons.org/licenses/by/4.0/}, + shorttitle = {Live {Mouse} {Tracker}}, + url = {https://www.biorxiv.org/content/10.1101/345132v2}, + doi = {10.1101/345132}, + abstract = {{\textless}p{\textgreater}Preclinical studies of psychiatric disorders require the use of animal models to investigate the impact of environmental factors or genetic mutations on complex traits such as decision-making and social interactions. Here, we present a real-time method for behavior analysis of mice housed in groups that couples computer vision, machine learning and Triggered-RFID identification to track and monitor animals over several days in enriched environments. The system extracts a thorough list of individual and collective behavioral traits and provides a unique phenotypic profile for each animal. On mouse models, we study the impact of mutations of genes Shank2 and Shank3 involved in autism. Characterization and integration of data from behavioral profiles of mutated female mice reveals distinctive activity levels and involvement in complex social configuration.{\textless}/p{\textgreater}}, + language = {en}, + urldate = {2019-07-28}, + journal = {bioRxiv}, + author = {Chaumont, Fabrice de and Ey, Elodie and Torquet, Nicolas and Lagache, Thibault and Dallongeville, StĆ©phane and Imbert, Albane and Legou, Thierry and Sourd, Anne-Marie Le and Faure, Philippe and Bourgeron, Thomas and Olivo-Marin, Jean-Christophe}, + month = jun, + year = {2018}, + pages = {345132} +} + +@article{hetze_gait_2012, + title = {Gait analysis as a method for assessing neurological outcome in a mouse model of stroke}, + volume = {206}, + issn = {1872-678X}, + doi = {10.1016/j.jneumeth.2012.02.001}, + abstract = {Ameliorating stroke induced neurological deficits is one of the most important goals of stroke therapy. In order to improve stroke outcome, novel treatment approaches as well as animal stroke models predictive for the clinical setting are of urgent need. One of the main obstacles in experimental stroke research is measuring long-term outcome, in particular in mouse models of stroke. On the other hand, assessing functional deficits in animal models of stroke is critical to improve the prediction of preclinical findings. Automated gait analysis provides a sensitive tool to examine locomotion and limb coordination in small rodents. Comparing mice before and 10 days after experimental stroke (60 min MCAo) we observed a significant decrease in maximum contact area, stride length and swing speed in the hind limbs, especially the contralateral one. Mice showed a disturbed interlimb coordination represented by changes in regularity index and phase dispersion. To assess whether gait analysis is applicable to assess improvements by neuroprotective compounds, we applied a model calculation and approached common statistical problems. In conclusion, gait analysis is a promising tool to assess mid- to long-term outcome in experimental stroke research.}, + language = {eng}, + number = {1}, + journal = {Journal of Neuroscience Methods}, + author = {Hetze, Susann and Rƶmer, Christine and Teufelhart, Carena and Meisel, Andreas and Engel, Odilo}, + month = apr, + year = {2012}, + pmid = {22343052}, + keywords = {Animals, Disease Models, Animal, Gait, Male, Mice, Mice, Inbred C57BL, Neurologic Examination, Predictive Value of Tests, Stroke, Treatment Outcome}, + pages = {7--14} +} + +@article{encarnacion_long-term_2011, + title = {Long-term behavioral assessment of function in an experimental model for ischemic stroke}, + volume = {196}, + issn = {01650270}, + url = {https://linkinghub.elsevier.com/retrieve/pii/S0165027011000367}, + doi = {10.1016/j.jneumeth.2011.01.010}, + abstract = {Middle cerebral artery occlusion (MCAO) in rats is a well-studied experimental model for ischemic stroke leading to brain infarction and functional deficits. Many preclinical studies have focused on a small time window after the ischemic episode to evaluate functional outcome for screening therapeutic candidates. Short evaluation periods following injury have led to significant setbacks due to lack of information on the delayed effects of treatments, as well as short-lived and reversible neuroprotection, so called false-positive results. In this report, we evaluated long-term functional deficit for 90 days after MCAO in two rat strains with two durations of ischemic insult, in order to identify the best experimental paradigm to assess injury and subsequent recovery. Behavioral outcomes were measured pre-MCAO followed by weekly assessment post-stroke. Behavioral tests included the 18-point composite neurological score, 28-point neuroscore, rearing test, vibrissae-evoked forelimb placing test, foot fault test and the CatWalk. Brain lesions were assessed to correlate injury to behavior outcomes at the end of study. Our results indicate that infarction volume in Sprague-Dawley rats was dependent on occlusion duration. In contrast, the infarction volume in Wistar rats did not correlate with the duration of ischemic episode. Functional outcomes were not dependent on occlusion time in either strain; however, measureable deficits were detectable long-term in limb asymmetry, 18- and 28-point neuroscores, forelimb placing, paw swing speed, and gait coordination. In conclusion, these behavioral assays, in combination with an extended long-term assessment period, can be used for evaluating therapeutic candidates in preclinical models of ischemic stroke.}, + language = {en}, + number = {2}, + urldate = {2019-07-28}, + journal = {Journal of Neuroscience Methods}, + author = {Encarnacion, Angelo and Horie, Nobutaka and Keren-Gill, Hadar and Bliss, Tonya M. and Steinberg, Gary K. and Shamloo, Mehrdad}, + month = mar, + year = {2011}, + pages = {247--257} +} + +@article{park_method_2014, + title = {A {Method} for {Generate} a {Mouse} {Model} of {Stroke}: {Evaluation} of {Parameters} for {Blood} {Flow}, {Behavior}, and {Survival}}, + volume = {23}, + issn = {1226-2560}, + shorttitle = {A {Method} for {Generate} a {Mouse} {Model} of {Stroke}}, + url = {https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3984953/}, + doi = {10.5607/en.2014.23.1.104}, + abstract = {Stroke is one of the common causes of death and disability. Despite extensive efforts in stroke research, therapeutic options for improving the functional recovery remain limited in clinical practice. Experimental stroke models using genetically modified mice could aid in unraveling the complex pathophysiology triggered by ischemic brain injury. Here, we optimized the procedure for generating mouse stroke model using an intraluminal suture in the middle cerebral artery and verified the blockage of blood flow using indocyanine green coupled with near infra-red radiation. The first week after the ischemic injury was critical for survivability. The survival rate of 11\% in mice without any treatment but increased to 60\% on administering prophylactic antibiotics. During this period, mice showed severe functional impairment but recovered spontaneously starting from the second week onward. Among the various behavioral tests, the pole tests and neurological severity score tests remained reliable up to 4 weeks after ischemia, whereas the rotarod and corner tests became less sensitive for assessing the severity of ischemic injury with time. Further, loss of body weight was also observed for up 4 weeks after ischemia induction. In conclusion, we have developed an improved approach which allows us to investigate the role of the cell death-related genes in the disease progression using genetically modified mice and to evaluate the modes of action of candidate drugs.}, + number = {1}, + urldate = {2019-07-28}, + journal = {Experimental Neurobiology}, + author = {Park, Sin-Young and Marasini, Subash and Kim, Geu-Hee and Ku, Taeyun and Choi, Chulhee and Park, Min-Young and Kim, Eun-Hee and Lee, Young-Don and Suh-Kim, Haeyoung and Kim, Sung-Soo}, + month = mar, + year = {2014}, + pmid = {24737945}, + pmcid = {PMC3984953}, + pages = {104--114} +} + +@misc{noauthor_f1000workspace_nodate, + title = {F1000Workspace}, + url = {https://f1000.com/work/#/items/553731}, + urldate = {2019-07-28} +} + +@article{bailoo_precision_2010, + title = {The precision of video and photocell tracking systems and the elimination of tracking errors with infrared backlighting}, + volume = {188}, + issn = {1872-678X}, + doi = {10.1016/j.jneumeth.2010.01.035}, + abstract = {Automated tracking offers a number of advantages over both manual and photocell tracking methodologies, including increased reliability, validity, and flexibility of application. Despite the advantages that video offers, our experience has been that video systems cannot track a mouse consistently when its coat color is in low contrast with the background. Furthermore, the local lab lighting can influence how well results are quantified. To test the effect of lighting, we built devices that provide a known path length for any given trial duration, at a velocity close to the average speed of a mouse in the open-field and the circular water maze. We found that the validity of results from two commercial video tracking systems (ANY-maze and EthoVision XT) depends greatly on the level of contrast and the quality of the lighting. A photocell detection system was immune to lighting problems but yielded a path length that deviated from the true length. Excellent precision was achieved consistently, however, with video tracking using infrared backlighting in both the open field and water maze. A high correlation (r=0.98) between the two software systems was observed when infrared backlighting was used with live mice.}, + language = {eng}, + number = {1}, + journal = {Journal of Neuroscience Methods}, + author = {Bailoo, Jeremy D. and Bohlen, Martin O. and Wahlsten, Douglas}, + month = apr, + year = {2010}, + pmid = {20138914}, + pmcid = {PMC2847046}, + keywords = {Animals, Behavior, Animal, Electronic Data Processing, Exploratory Behavior, Image Enhancement, Image Processing, Computer-Assisted, Mice, Motor Activity, Movement, Pattern Recognition, Automated, Signal Processing, Computer-Assisted, Spatial Behavior, User-Computer Interface, Video Recording}, + pages = {45--52} +} + +@article{spink_ethovision_2001, + series = {Molecular {Behavior} {Genetics} of the {Mouse}}, + title = {The {EthoVision} video tracking systemā€”{A} tool for behavioral phenotyping of transgenic mice}, + volume = {73}, + issn = {0031-9384}, + url = {http://www.sciencedirect.com/science/article/pii/S0031938401005303}, + doi = {10.1016/S0031-9384(01)00530-3}, + abstract = {Video tracking systems enable behavior to be studied in a reliable and consistent way, and over longer time periods than if they are manually recorded. The system takes an analog video signal, digitizes each frame, and analyses the resultant pixels to determine the location of the tracked animals (as well as other data). Calculations are performed on a series of frames to derive a set of quantitative descriptors of the animal's movement. EthoVision (from Noldus Information Technology) is a specific example of such a system, and its functionality that is particularly relevant to transgenic mice studies is described. Key practical aspects of using the EthoVision system are also outlined, including tips about lighting, marking animals, the arena size, and sample rate. Four case studies are presented, illustrating various aspects of the system: (1) The effects of disabling the Munc 18-1 gene were clearly shown using the straightforward measure of how long the mice took to enter a zone in an open field. (2) Differences in exploratory behavior between short and long attack latency mice strains were quantified by measuring the time spent in inner and outer zones of an open field. (3) Mice with hypomorphic CREB alleles were shown to perform less well in a water maze, but this was only clear when a range of different variables were calculated from their tracks. (4) Mice with the trkB receptor knocked out in the forebrain also performed poorly in a water maze, and it was immediately apparent from examining plots of the tracks that this was due to thigmotaxis. Some of the latest technological developments and possible future directions for video tracking systems are briefly discussed.}, + number = {5}, + urldate = {2019-07-28}, + journal = {Physiology \& Behavior}, + author = {Spink, A. J and Tegelenbosch, R. A. J and Buma, M. O. S and Noldus, L. P. J. J}, + month = aug, + year = {2001}, + keywords = {Automated observation, Rodent, Video tracking, Water maze}, + pages = {731--744} +} + +@article{dunne_development_2007, + title = {Development of a home cage locomotor tracking system capable of detecting the stimulant and sedative properties of drugs in rats}, + volume = {31}, + issn = {0278-5846}, + url = {http://www.sciencedirect.com/science/article/pii/S0278584607002163}, + doi = {10.1016/j.pnpbp.2007.06.023}, + abstract = {The advent of automated locomotor activity methodologies has been extremely useful in removing the subjectivity and bias out of measuring this parameter in rodents. However, many of these behavioural studies are still conducted in novel environments, rather than in ones that the animals are familiar with, such as their home cage. The purpose of the present series of experiments was to develop an automated home cage tracking (HCT) profile using EthoVisionĀ® software and assessing the acute effects of stimulant (amphetamine and methamphetamine, 0ā€“5 mg/kg, sc) and sedative (diazepam, 0ā€“20 mg/kg, sc and chlordiazepoxide, 0ā€“50 mg/kg sc) drugs in this apparatus. Young adult male Spragueā€“Dawley rats were used, and the home cage locomotor activity was recorded for 11ā€“60 min following administration (n=4 per group). For amphetamine and methamphetamine, a dose-dependent increase in home cage activity was evident for both drugs, with a plateau, followed by reduction at higher doses. Methamphetamine was more potent, whereas amphetamine produced greater maximal responses. Both diazepam and chlordiazepoxide dose-dependently reduced locomotor activity, with diazepam exhibiting a greater potency and having stronger sedative effects than chlordiazepoxide. Three doses of each drug were selected at the 31ā€“40 min time period following administration, and compared to open field responses. Diazepam, chlordiazepoxide and amphetamine did not produce significant changes in the open field, whilst methamphetamine produced a significant increase in the 2.5 mg/kg group. In conclusion, these studies have successfully developed a sensitive HCT methodology that has been validated using drugs with stimulant and sedative properties in the same test conditions, with relatively small numbers of animals required to produce statistically significant results. It has proven superior to the open field investigations in allowing dose-response effects to be observed over a relatively short observation period (i.e. 10 min) for both stimulants and sedatives. In addition, the HCT system can determine differences in potency and efficacy between drugs of a similar chemical class.}, + number = {7}, + urldate = {2019-07-28}, + journal = {Progress in Neuro-Psychopharmacology and Biological Psychiatry}, + author = {Dunne, Fergal and O'Halloran, Ambrose and Kelly, John P.}, + month = oct, + year = {2007}, + keywords = {Home cage, Locomotor activity, Rats, Sedatives, Stimulants}, + pages = {1456--1463} +} + +@article{young_combined_2000, + title = {A combined system for measuring animal motion activities}, + volume = {95}, + issn = {0165-0270}, + url = {http://www.sciencedirect.com/science/article/pii/S0165027099001569}, + doi = {10.1016/S0165-0270(99)00156-9}, + abstract = {In this study, we have developed a combined animal motion activity measurement system that combines an infrared light matrix subsystem with an ultrasonic phase shift subsystem for animal activity measurement. Accordingly, in conjunction with an IBM PC/AT compatible personal computer, the combined system has the advantages of both infrared and ultrasonic subsystems. That is, it can at once measure and directly analyze detailed changes in animal activity ranging from locomotion to tremor. The main advantages of this combined system are that it features real time data acquisition with the option of animated real time or recorded display/playback of the animalā€™s motion. Additionally, under the multi-task operating condition of IBM PC, it can acquire and process behavior using both IR and ultrasound systems simultaneously. Traditional systems have had to make separate runs for gross and fine movement recording. This combined system can be profitably employed for normative behavioral activity studies and for neurological and pharmacological research.}, + number = {1}, + urldate = {2019-07-28}, + journal = {Journal of Neuroscience Methods}, + author = {Young, M. S. and Young, C. W. and Li, Y. C.}, + month = jan, + year = {2000}, + keywords = {Animal activity, Infrared Light, Measurement, Real time, Single-chip microcomputer, Ultrasound}, + pages = {55--63} +} + +@article{aragao_automatic_2011, + title = {Automatic system for analysis of locomotor activity in rodentsā€”{A} reproducibility study}, + volume = {195}, + issn = {0165-0270}, + url = {http://www.sciencedirect.com/science/article/pii/S0165027010007041}, + doi = {10.1016/j.jneumeth.2010.12.016}, + abstract = {Automatic analysis of locomotion in studies of behavior and development is of great importance because it eliminates the subjective influence of evaluators on the study. This study aimed to develop and test the reproducibility of a system for automated analysis of locomotor activity in rats. For this study, 15 male Wistar were evaluated at P8, P14, P17, P21, P30 and P60. A monitoring system was developed that consisted of an open field of 1m in diameter with a black surface, an infrared digital camera and a video capture card. The animals were filmed for 2min as they moved freely in the field. The images were sent to a computer connected to the camera. Afterwards, the videos were analyzed using software developed using MATLABĀ® (mathematical software). The software was able to recognize the pixels constituting the image and extract the following parameters: distance traveled, average speed, average potency, time immobile, number of stops, time spent in different areas of the field and time immobile/number of stops. All data were exported for further analysis. The system was able to effectively extract the desired parameters. Thus, it was possible to observe developmental changes in the patterns of movement of the animals. We also discuss similarities and differences between this system and previously described systems.}, + number = {2}, + urldate = {2019-07-28}, + journal = {Journal of Neuroscience Methods}, + author = {AragĆ£o, Raquel da Silva and Rodrigues, Marco AurĆ©lio Benedetti and de Barros, Karla MĆ“nica Ferraz Teixeira and Silva, SebastiĆ£o RogĆ©rio Freitas and Toscano, Ana Elisa and de Souza, Ricardo Emmanuel and ManhĆ£es-de-Castro, Raul}, + month = feb, + year = {2011}, + keywords = {Automated analysis, Behavioral analysis, Biomechanical analysis, Locomotor activity, Open field}, + pages = {216--221} +} + +@article{benjamini_ten_2010, + title = {Ten ways to improve the quality of descriptions of whole-animal movement}, + volume = {34}, + issn = {0149-7634}, + url = {http://www.sciencedirect.com/science/article/pii/S0149763410000886}, + doi = {10.1016/j.neubiorev.2010.04.004}, + abstract = {The demand for replicability of behavioral results across laboratories is viewed as a burden in behavior genetics. We demonstrate how it can become an asset offering a quantitative criterion that guides the design of better ways to describe behavior. Passing the high benchmark dictated by the replicability demand requires less stressful and less restraining experimental setups, less noisy data, individually customized cutoff points between the building blocks of movement, and less variable yet discriminative dynamic representations that would capture more faithfully the nature of the behavior, unmasking similarities and differences and revealing novel animal-centered measures. Here we review ten tools that enhance replicability without compromising discrimination. While we demonstrate the usefulness of these tools in the context of inbred mouse exploratory behavior they can readily be used in any study involving a high-resolution analysis of spatial behavior. Viewing replicability as a design concept and using the ten methodological improvements may prove useful in many fields not necessarily related to spatial behavior.}, + number = {8}, + urldate = {2019-07-28}, + journal = {Neuroscience \& Biobehavioral Reviews}, + author = {Benjamini, Yoav and Lipkind, Dina and Horev, Guy and Fonio, Ehud and Kafkafi, Neri and Golani, Ilan}, + month = jul, + year = {2010}, + keywords = {Compression of kinematic data, Description of behavior, Discriminability between strains and preparations, Exploratory behavior, Genotype-laboratory interaction, Mixed-Model Anova, Open field behavior, Phenotyping mouse behavior, Replicability of results, Segmentation of behavior, Smoothing kinematic data}, + pages = {1351--1365} +} + +@article{Arpteg2018SoftwareEC, + title={Software Engineering Challenges of Deep Learning}, + author={A. Arpteg and B. Brinne and Luka Crnkovic-Friis and J. Bosch}, + journal={2018 44th Euromicro Conference on Software Engineering and Advanced Applications (SEAA)}, + year={2018}, + pages={50-59}, + doi={10.1109/seaa.2018.00018}, +} + +@InProceedings{ mckinney-proc-scipy-2010, + author = { {W}es {M}c{K}inney }, + title = { {D}ata {S}tructures for {S}tatistical {C}omputing in {P}ython }, + booktitle = { {P}roceedings of the 9th {P}ython in {S}cience {C}onference }, + pages = { 56 - 61 }, + year = { 2010 }, + editor = { {S}t\'efan van der {W}alt and {J}arrod {M}illman }, + doi = { 10.25080/Majora-92bf1922-00a } +} + +@article{van_galen_effects_1990, + title = {Effects of motor programming on the power spectral density function of finger and wrist movements}, + volume = {16}, + issn = {1939-1277(Electronic),0096-1523(Print)}, + doi = {10.1037/0096-1523.16.4.755}, + abstract = {Power spectral density analysis was applied to the frequency content of the acceleration signal of pen movements in line drawing using 10 right-handed college students. The relative power in frequency bands between 1 and 32 Hz was measured as a function of motoric and anatomic task demands. Results showed a decrease of power at the lower frequencies (1ā€“4 Hz) of the spectrum and an increase in the middle (9ā€“22 Hz) with increasing motor demands. These findings evidence the inhibition of visual control and the disinhibition of physiological tremor under conditions of increased programming demands. Adductive movements displayed less power than abductive movements in the lower end of the spectrum, with a simultaneous increase at the higher frequencies. The relevance of the method for the measurement of neuromotor noise as a possible origin of delays in motor behavior is discussed. (PsycINFO Database Record (c) 2016 APA, all rights reserved)}, + number = {4}, + journal = {Journal of Experimental Psychology: Human Perception and Performance}, + author = {Van Galen, Gerard P. and Van Doorn, Robert R. and Schomaker, Lambert R.}, + year = {1990}, + note = {Place: US +Publisher: American Psychological Association}, + keywords = {Fingers (Anatomy), Motion Perception, Task Complexity, Wrist}, + pages = {755--765}, +} + +@software{reback2020pandas, + author = {The pandas development team}, + title = {pandas-dev/pandas: Pandas}, + month = feb, + year = 2020, + publisher = {Zenodo}, + version = {latest}, + doi = {10.5281/zenodo.3509134}, + url = {https://doi.org/10.5281/zenodo.3509134} +} + +@article{noonan_scale-insensitive_2019, + title = {Scale-insensitive estimation of speed and distance traveled from animal tracking data}, + volume = {7}, + issn = {2051-3933}, + url = {https://doi.org/10.1186/s40462-019-0177-1}, + doi = {10.1186/s40462-019-0177-1}, + abstract = {Speed and distance traveled provide quantifiable links between behavior and energetics, and are among the metrics most routinely estimated from animal tracking data. Researchers typically sum over the straight-line displacements (SLDs) between sampled locations to quantify distance traveled, while speed is estimated by dividing these displacements by time. Problematically, this approach is highly sensitive to the measurement scale, with biases subject to the sampling frequency, the tortuosity of the animalā€™s movement, and the amount of measurement error. Compounding the issue of scale-sensitivity, SLD estimates do not come equipped with confidence intervals to quantify their uncertainty.}, + number = {1}, + urldate = {2021-02-13}, + journal = {Movement Ecology}, + author = {Noonan, Michael J. and Fleming, Christen H. and Akre, Thomas S. and Drescher-Lehman, Jonathan and Gurarie, Eliezer and Harrison, Autumn-Lynn and Kays, Roland and Calabrese, Justin M.}, + month = nov, + year = {2019}, + keywords = {Continuous-time, GPS, correlated velocity, ctmm, movement models, step length, telemetry, travel distance}, + pages = {35}, +} + + +@misc{noauthor_f1000workspace_nodate-1, + title = {F1000Workspace}, + url = {https://f1000.com/work/#/items/6352976}, + urldate = {2019-07-28} +} + +@article{kilkenny_improving_2010, + title = {Improving {Bioscience} {Research} {Reporting}: {The} {ARRIVE} {Guidelines} for {Reporting} {Animal} {Research}}, + volume = {8}, + issn = {1545-7885}, + shorttitle = {Improving {Bioscience} {Research} {Reporting}}, + url = {https://journals.plos.org/plosbiology/article?id=10.1371/journal.pbio.1000412}, + doi = {10.1371/journal.pbio.1000412}, + language = {en}, + number = {6}, + urldate = {2019-07-28}, + journal = {PLOS Biology}, + author = {Kilkenny, Carol and Browne, William J. and Cuthill, Innes C. and Emerson, Michael and Altman, Douglas G.}, + month = jun, + year = {2010}, + keywords = {Laboratory animals, Peer review, Research design, Research laboratories, Research reporting guidelines, Routes of administration, Statistical data, Statistical methods}, + pages = {e1000412} +} + +@article{fisher_update_2009, + title = {Update of the {Stroke} {Therapy} {Academic} {Industry} {Roundtable} {Preclinical} {Recommendations}}, + volume = {40}, + issn = {0039-2499}, + url = {https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2888275/}, + doi = {10.1161/STROKEAHA.108.541128}, + abstract = {The initial Stroke Therapy Academic Industry Roundtable (STAIR) recommendations published in 1999 were intended to improve the quality of preclinical studies of purported acute stroke therapies. Although recognized as reasonable, they have not been closely followed nor rigorously validated. Substantial advances have occurred regarding the appropriate quality and breadth of preclinical testing for candidate acute stroke therapies for better clinical translation. The updated STAIR preclinical recommendations reinforce the previous suggestions that reproducibly defining dose response and time windows with both histological and functional outcomes in multiple animal species with appropriate physiological monitoring is appropriate. The updated STAIR recommendations include: the fundamentals of good scientific inquiry should be followed by eliminating randomization and assessment bias, a priori defining inclusion/exclusion criteria, performing appropriate power and sample size calculations, and disclosing potential conflicts of interest. After initial evaluations in young, healthy male animals, further studies should be performed in females, aged animals, and animals with comorbid conditions such as hypertension, diabetes, and hypercholesterolemia. Another consideration is the use of clinically relevant biomarkers in animal studies. Although the recommendations cannot be validated until effective therapies based on them emerge from clinical trials, it is hoped that adherence to them might enhance the chances for success.}, + number = {6}, + urldate = {2019-07-28}, + journal = {Stroke; a journal of cerebral circulation}, + author = {Fisher, Marc and Feuerstein, Giora and Howells, David W. and Hurn, Patricia D. and Kent, Thomas A. and Savitz, Sean I. and Lo, Eng H.}, + month = jun, + year = {2009}, + pmid = {19246690}, + pmcid = {PMC2888275}, + pages = {2244--2250} +} + +@article{engel_modeling_2011, + title = {Modeling stroke in mice - middle cerebral artery occlusion with the filament model}, + issn = {1940-087X}, + doi = {10.3791/2423}, + abstract = {Stroke is among the most frequent causes of death and adult disability, especially in highly developed countries. However, treatment options to date are very limited. To meet the need for novel therapeutic approaches, experimental stroke research frequently employs rodent models of focal cerebral ischaemia. Most researchers use permanent or transient occlusion of the middle cerebral artery (MCA) in mice or rats. Proximal occlusion of the middle cerebral artery (MCA) via the intraluminal suture technique (so called filament or suture model) is probably the most frequently used model in experimental stroke research. The intraluminal MCAO model offers the advantage of inducing reproducible transient or permanent ischaemia of the MCA territory in a relatively non-invasive manner. Intraluminal approaches interrupt the blood flow of the entire territory of this artery. Filament occlusion thus arrests flow proximal to the lenticulo-striate arteries, which supply the basal ganglia. Filament occlusion of the MCA results in reproducible lesions in the cortex and striatum and can be either permanent or transient. In contrast, models inducing distal (to the branching of the lenticulo-striate arteries) MCA occlusion typically spare the striatum and primarily involve the neocortex. In addition these models do require craniectomy. In the model demonstrated in this article, a silicon coated filament is introduced into the common carotid artery and advanced along the internal carotid artery into the Circle of Willis, where it blocks the origin of the middle cerebral artery. In patients, occlusions of the middle cerebral artery are among the most common causes of ischaemic stroke. Since varying ischemic intervals can be chosen freely in this model depending on the time point of reperfusion, ischaemic lesions with varying degrees of severity can be produced. Reperfusion by removal of the occluding filament at least partially models the restoration of blood flow after spontaneous or therapeutic (tPA) lysis of a thromboembolic clot in humans. In this video we will present the basic technique as well as the major pitfalls and confounders which may limit the predictive value of this model.}, + language = {eng}, + number = {47}, + journal = {Journal of Visualized Experiments: JoVE}, + author = {Engel, Odilo and Kolodziej, Sabine and Dirnagl, Ulrich and Prinz, Vincent}, + month = jan, + year = {2011}, + pmid = {21248698}, + pmcid = {PMC3182649}, + keywords = {Animals, Brain Ischemia, Disease Models, Animal, Infarction, Middle Cerebral Artery, Mice, Middle Cerebral Artery, Silicon} +} + +@article{endres_ischemia_2002, + title = {Ischemia and stroke}, + volume = {513}, + issn = {0065-2598}, + doi = {10.1007/978-1-4615-0123-7_17}, + abstract = {Cell death following cerebral ischemia is mediated by a complex pathophysiologic interaction of different mechanisms. In this Chapter we will outline the basic principles as well as introduce in vitro and in vivo models of cerebral ischemia. Mechanistically, excitotoxicity, peri-infarct depolarization, inflammation and apoptosis seem to be the most relevant mediators of damage and are promising targets for neuroprotective strategies.}, + language = {eng}, + journal = {Advances in Experimental Medicine and Biology}, + author = {Endres, Matthias and Dirnagl, Ulrich}, + year = {2002}, + pmid = {12575832}, + keywords = {Acidosis, Animals, Apoptosis, Brain, Brain Ischemia, Caspase Inhibitors, Caspases, Disease Models, Animal, Humans, Inflammation, Necrosis, Receptors, Glutamate, Stroke, Temperature}, + pages = {455--473} +} + +@article{crone_mice_2009, + title = {In {Mice} {Lacking} {V}2a {Interneurons}, {Gait} {Depends} on {Speed} of {Locomotion}}, + volume = {29}, + copyright = {Copyright Ā© 2009 Society for Neuroscience 0270-6474/09/297098-12\$15.00/0}, + issn = {0270-6474, 1529-2401}, + url = {https://www.jneurosci.org/content/29/21/7098}, + doi = {10.1523/JNEUROSCI.1206-09.2009}, + abstract = {Many animals are capable of changing gait with speed of locomotion. The neural basis of gait control and its dependence on speed are not fully understood. Mice normally use a single ā€œtrottingā€ gait while running at all speeds, either over ground or on a treadmill. Transgenic mouse mutants in which the trotting is replaced by hopping also lack a speed-dependent change in gait. Here we describe a transgenic mouse model in which the V2a interneurons have been ablated by targeted expression of diphtheria toxin A chain (DTA) under the control of the Chx10 gene promoter (Chx10::DTA mice). Chx10::DTA mice show normal trotting gait at slow speeds but transition to a galloping gait as speed increases. Although leftā€“right limb coordination is altered in Chx10::DTA mice at fast speed, alternation of forelegs and hindlegs and the relative duration of swing and stance phases for individual limbs is unchanged compared with wild-type mice. The speed-dependent loss of leftā€“right alternation is recapitulated during drug-induced fictive locomotion in spinal cords isolated from neonatal Chx10::DTA mice, and high-speed fictive locomotion evoked by caudal spinal cord stimulation also shows synchronous leftā€“right bursting. These results show that spinal V2a interneurons are required for maintaining leftā€“right alternation at high speeds. Whether animals that generate galloping or hopping gaits, characterized by synchronous movement of left and right forelegs and hindlegs, have lost or modified the function of V2a interneurons is an intriguing question.}, + language = {en}, + number = {21}, + urldate = {2019-07-28}, + journal = {Journal of Neuroscience}, + author = {Crone, Steven A. and Zhong, Guisheng and Harris-Warrick, Ronald and Sharma, Kamal}, + month = may, + year = {2009}, + pmid = {19474336}, + pages = {7098--7109} +} + +@article{solla_eliminating_1999, + title = {Eliminating autocorrelation reduces biological relevance of home range estimates}, + volume = {68}, + issn = {1365-2656}, + url = {https://besjournals.onlinelibrary.wiley.com/doi/abs/10.1046/j.1365-2656.1999.00279.x}, + doi = {10.1046/j.1365-2656.1999.00279.x}, + abstract = {1. Destructive subsampling or restrictive sampling are often standard procedures to obtain independence of spatial observations in home range analyses. We examined whether home range estimators based upon kernel densities require serial independence of observations, by using a Monte Carlo simulation, antler flies and snapping turtles as models. 2. Home range size, time partitioning and total straight line distances travelled were tested to determine if subsampling improved kernel performance and estimation of home range parameters. 3. The accuracy and precision of home range estimates from the simulated data set improved at shorter time intervals despite the increase in autocorrelation among the observations. 4. Subsampling did not reduce autocorrelation among locational observations of snapping turtles or antler flies, and home range size, time partitioning and total distance travelled were better represented by autocorrelated observations. 5. We found that kernel densities do not require serial independence of observations when estimating home range, and we recommend that researchers maximize the number of observations using constant time intervals to increase the accuracy and precision of their estimates.}, + language = {en}, + number = {2}, + urldate = {2021-02-13}, + journal = {Journal of Animal Ecology}, + author = {Solla, Shane R. DE and Bonduriansky, Russell and Brooks, Ronald J.}, + year = {1999}, + note = {\_eprint: https://besjournals.onlinelibrary.wiley.com/doi/pdf/10.1046/j.1365-2656.1999.00279.x}, + keywords = {Chelydra serpentina, Monte Carlo, Protopiophila litigata, kernel density estimation, statistical independence}, + pages = {221--234}, +} + +@article{bothe_genetic_2004, + title = {Genetic and behavioral differences among five inbred mouse strains commonly used in the production of transgenic and knockout mice}, + volume = {3}, + issn = {1601-183X}, + url = {https://onlinelibrary.wiley.com/doi/abs/10.1111/j.1601-183x.2004.00064.x}, + doi = {10.1111/j.1601-183x.2004.00064.x}, + abstract = {Five strains of mice commonly used in transgenic and knockout production were compared with regard to genetic background and behavior. These strains were: C57BL/6J, C57BL/6NTac, 129P3/J (formerly 129/J), 129S6/SvEvTac (formerly 129/SvEvTac) and FVB/NTac. Genotypes for 342 microsatellite markers and performance in three behavioral tests (rotorod, open field activity and habituation, and contextual and cued fear conditioning) were determined. C57BL/6J and C57BL/6NTac were found to be true substrains; there were only 12 microsatellite differences between them. Given the data on the genetic background, one might predict that the two C57BL/6 substrains should be very similar behaviorally. Indeed, there were no significant behavioral differences between C57BL/6J and C57BL/6NTac. Contrary to literature reports on other 129 strains, 129S6/SvEvTac often performed similarly to C57BL/6 strains, except that it was less active. FVB/NTac showed impaired rotorod learning and cued fear conditioning. Therefore, both 129S6/SvEvTac and C57BL/6 are recommended as background strains for targeted mutations when researchers want to evaluate their mice in any of these three behavior tests. However, any transgene on the FVB/NTac background should be transferred to B6. Habituation to the open field was analyzed using the parameters: total distance, center distance, velocity and vertical activity. Contrary to earlier studies, we found that all strains habituated to the open field in at least two of these parameters (center distance and velocity).}, + language = {en}, + number = {3}, + urldate = {2019-07-28}, + journal = {Genes, Brain and Behavior}, + author = {Bothe, G. W. M. and Bolivar, V. J. and Vedder, M. J. and Geistfeld, J. G.}, + year = {2004}, + keywords = {Behavior, center avoidance, contextual and cued fear conditioning, genetics, habituation, inbred strain, leaning, microsatellite, motor coordination, mouse, open-field activity, rearing, rotorod}, + pages = {149--157} +} + +@article{masocha_assessment_2009, + title = {Assessment of weight bearing changes and pharmacological antinociception in mice with {LPS}-induced monoarthritis using the {Catwalk} gait analysis system}, + volume = {85}, + issn = {1879-0631}, + doi = {10.1016/j.lfs.2009.07.015}, + abstract = {AIMS: We evaluated the possibility of using the video-based Catwalk gait analysis method to measure weight bearing changes and for testing pharmacological antinociception in freely moving mice with lipopolysaccharide (LPS)-induced monoarthritis. +MAIN METHODS: LPS or its solvent (PBS) was injected intra-articularly into the right hind (RH) limb ankle joint through the Achilles tendon of C57BL/6 mice. The Catwalk system was used to assess behavioral changes in freely moving mice. The effects of indomethacin on changes in LPS-inoculated mice were examined. +KEY FINDINGS: Mice inoculated with LPS into the RH limb showed reduced paw pressure (measured as light intensity) and print area on the RH limb, whereas they exerted more pressure with the left hind (LH) and front limbs, showing a transfer of weight bearing from RH to LH and front limbs, which was significant at 2 days post-LPS inoculation. There were no differences between the front limbs. No changes were observed in the PBS injected controls. There were no changes in interlimb coordination (regularity index) in both PBS- and LPS-injected mice. Treatment with indomethacin (10 and 100mg/kg) restored the weight bearing (measured as the ratio of the pressure exerted by the paws) and the print area ratios of LPS-inoculated mice similar to that observed in control mice. +SIGNIFICANCE: This study shows that the Catwalk gait analysis system can be used to objectively quantify LPS-induced monoarthritis weight bearing changes in all four limbs and evaluate pharmacological antinociception in freely moving mice.}, + language = {eng}, + number = {11-12}, + journal = {Life Sciences}, + author = {Masocha, Willias and Parvathy, Subramanian S. and Pavarthy, Subramanian S.}, + month = sep, + year = {2009}, + pmid = {19683012}, + keywords = {Achilles Tendon, Analgesics, Animals, Anti-Inflammatory Agents, Non-Steroidal, Arthritis, Experimental, Foot, Functional Laterality, Gait, Hindlimb, Indomethacin, Injections, Intra-Articular, Joints, Lighting, Lipopolysaccharides, Mice, Mice, Inbred C57BL, Weight-Bearing}, + pages = {462--469} +} + +@article{hampton_gait_2004, + title = {Gait dynamics in trisomic mice: quantitative neurological traits of {Down} syndrome}, + volume = {82}, + issn = {0031-9384}, + shorttitle = {Gait dynamics in trisomic mice}, + doi = {10.1016/j.physbeh.2004.04.006}, + abstract = {The segmentally trisomic mouse Ts65Dn is a model of Down syndrome (DS). Gait abnormalities are almost universal in persons with DS. We applied a noninvasive imaging method to quantitatively compare the gait dynamics of Ts65Dn mice (n=10) to their euploid littermates (controls) (n=10). The braking duration of the hind limbs in Ts65Dn mice was prolonged compared to that in control mice (60+/-3 ms vs. 49+/-2 ms, P{\textless}.05) at a slow walking speed (18 cm/s). Stride length and stride frequency of forelimbs and hind limbs were comparable between Ts65Dn mice and control mice. Stride dynamics were significantly different in Ts65Dn mice at a faster walking speed (36 cm/s). Stride length was shorter in Ts65Dn mice (5.9+/-0.1 vs. 6.3+/-0.3 cm, P{\textless}.05), and stride frequency was higher in Ts65Dn compared to control mice (5.9+/-0.1 vs. 5.3+/-0.1 strides/s, P{\textless}.05). Hind limb swing duration was prolonged in Ts65Dn mice compared to control mice (93+/-3 vs. 76+/-3 ms, P{\textless}.05). Propulsion of the forelimbs contributed to a significantly larger percentage of stride duration in Ts65Dn mice than in control mice at the faster walking speed. Indices of gait dynamics in Ts65Dn mice correspond to previously reported findings in children with DS. The methods used in the present study provide quantitative markers for genotype and phenotype relationship studies in DS. This technique may provide opportunities for testing the efficacy of therapies for motor dysfunction in persons with DS.}, + language = {eng}, + number = {2-3}, + journal = {Physiology \& Behavior}, + author = {Hampton, Thomas G. and Stasko, Melissa R. and Kale, Ajit and Amende, Ivo and Costa, Alberto C. S.}, + month = sep, + year = {2004}, + pmid = {15276802}, + keywords = {Animals, Disease Models, Animal, Down Syndrome, Gait, Male, Mice, Mice, Neurologic Mutants, Motor Activity, Phenotype, Reference Values}, + pages = {381--389} +} + +@article{parker_gait_1980, + title = {Gait of children with {Down} syndrome}, + volume = {61}, + issn = {0003-9993}, + language = {eng}, + number = {8}, + journal = {Archives of Physical Medicine and Rehabilitation}, + author = {Parker, A. W. and Bronks, R.}, + month = aug, + year = {1980}, + pmid = {6447490}, + keywords = {Child, Child Development, Down Syndrome, Female, Gait, Humans, Joints, Male, Muscle Contraction}, + pages = {345--351} +} + +@article{amende_gait_2005, + title = {Gait dynamics in mouse models of {Parkinson}'s disease and {Huntington}'s disease}, + volume = {2}, + issn = {1743-0003}, + doi = {10.1186/1743-0003-2-20}, + abstract = {BACKGROUND: Gait is impaired in patients with Parkinson's disease (PD) and Huntington's disease (HD), but gait dynamics in mouse models of PD and HD have not been described. Here we quantified temporal and spatial indices of gait dynamics in a mouse model of PD and a mouse model of HD. +METHODS: Gait indices were obtained in C57BL/6J mice treated with the dopaminergic neurotoxin 1-methyl-4-phenyl-1,2,3,6-tetrahydropyridine (MPTP, 30 mg/kg/day for 3 days) for PD, the mitochondrial toxin 3-nitropropionic acid (3NP, 75 mg/kg cumulative dose) for HD, or saline. We applied ventral plane videography to generate digital paw prints from which indices of gait and gait variability were determined. Mice walked on a transparent treadmill belt at a speed of 34 cm/s after treatments. +RESULTS: Stride length was significantly shorter in MPTP-treated mice (6.6 +/- 0.1 cm vs. 7.1 +/- 0.1 cm, P {\textless} 0.05) and stride frequency was significantly increased (5.4 +/- 0.1 Hz vs. 5.0 +/- 0.1 Hz, P {\textless} 0.05) after 3 administrations of MPTP, compared to saline-treated mice. The inability of some mice treated with 3NP to exhibit coordinated gait was due to hind limb failure while forelimb gait dynamics remained intact. Stride-to-stride variability was significantly increased in MPTP-treated and 3NP-treated mice compared to saline-treated mice. To determine if gait disturbances due to MPTP and 3NP, drugs affecting the basal ganglia, were comparable to gait disturbances associated with motor neuron diseases, we also studied gait dynamics in a mouse model of amyotrophic lateral sclerosis (ALS). Gait variability was not increased in the SOD1 G93A transgenic model of ALS compared to wild-type control mice. +CONCLUSION: The distinct characteristics of gait and gait variability in the MPTP model of Parkinson's disease and the 3NP model of Huntington's disease may reflect impairment of specific neural pathways involved.}, + language = {eng}, + journal = {Journal of Neuroengineering and Rehabilitation}, + author = {Amende, Ivo and Kale, Ajit and McCue, Scott and Glazier, Scott and Morgan, James P. and Hampton, Thomas G.}, + month = jul, + year = {2005}, + pmid = {16042805}, + pmcid = {PMC1201165}, + pages = {20} +} + +@incollection{jeung_mining_2007, + address = {Berlin, Heidelberg}, + title = {Mining {Trajectory} {Patterns} {Using} {Hidden} {Markov} {Models}}, + volume = {4654}, + isbn = {978-3-540-74552-5 978-3-540-74553-2}, + url = {http://link.springer.com/10.1007/978-3-540-74553-2_44 https://espace.library.uq.edu.au/view/UQ:164937/MIC12UQ164937.pdf}, + booktitle = {Data {Warehousing} and {Knowledge} {Discovery}}, + publisher = {Springer Berlin Heidelberg}, + author = {Jeung, Hoyoung and Shen, Heng Tao and Zhou, Xiaofang}, + editor = {Song, Il Yeal and Eder, Johann and Nguyen, Tho Manh}, + year = {2007}, + note = {Type: Book Section}, + doi ={10.1007/978-3-540-74553-2_44}, + pages = {470--480}, +} + +@Article{ harris2020array, + title = {Array programming with {NumPy}}, + author = {Charles R. Harris and K. Jarrod Millman and St{'{e}}fan J. + van der Walt and Ralf Gommers and Pauli Virtanen and David + Cournapeau and Eric Wieser and Julian Taylor and Sebastian + Berg and Nathaniel J. Smith and Robert Kern and Matti Picus + and Stephan Hoyer and Marten H. van Kerkwijk and Matthew + Brett and Allan Haldane and Jaime Fern{'{a}}ndez del + R{'{\i}}o and Mark Wiebe and Pearu Peterson and Pierre + G{'{e}}rard-Marchant and Kevin Sheppard and Tyler Reddy and + Warren Weckesser and Hameer Abbasi and Christoph Gohlke and + Travis E. Oliphant}, + year = {2020}, + month = sep, + journal = {Nature}, + volume = {585}, + number = {7825}, + pages = {357--362}, + doi = {10.1038/s41586-020-2649-2}, + publisher = {Springer Science and Business Media {LLC}}, + url = {https://doi.org/10.1038/s41586-020-2649-2} +} + +@article{Waskom2021, + doi = {10.21105/joss.03021}, + url = {https://doi.org/10.21105/joss.03021}, + year = {2021}, + publisher = {The Open Journal}, + volume = {6}, + number = {60}, + pages = {3021}, + author = {Michael L. Waskom}, + title = {seaborn: statistical data visualization}, + journal = {Journal of Open Source Software} +} + +@Article{Hunter:2007, + Author = {Hunter, J. D.}, + Title = {Matplotlib: A 2D graphics environment}, + Journal = {Computing in Science \& Engineering}, + Volume = {9}, + Number = {3}, + Pages = {90--95}, + abstract = {Matplotlib is a 2D graphics package used for Python for + application development, interactive scripting, and publication-quality + image generation across user interfaces and operating systems.}, + publisher = {IEEE COMPUTER SOC}, + doi = {10.1109/MCSE.2007.55}, + year = 2007 +} + +@article{rowcliffe_bias_2012, + title = {Bias in estimating animal travel distance: the effect of sampling frequency}, + volume = {3}, + copyright = {Ā© 2012 The Authors. Methods in Ecology and Evolution Ā© 2012 British Ecological Society}, + issn = {2041-210X}, + shorttitle = {Bias in estimating animal travel distance}, + url = {https://besjournals.onlinelibrary.wiley.com/doi/abs/10.1111/j.2041-210X.2012.00197.x}, + doi = {10.1111/j.2041-210X.2012.00197.x}, + abstract = {1. The distance travelled by animals is an important ecological variable that links behaviour, energetics and demography. It is usually measured by summing straight-line distances between intermittently sampled locations along continuous animal movement paths. The extent to which this approach underestimates travel distance remains a rarely addressed and unsolved problem, largely because true movement paths are rarely, if ever, available for comparison. Here, we use simulated movement paths parameterized with empirical movement data to study how estimates of distance travelled are affected by sampling frequency. 2. We used a novel method to obtain fine-scale characteristics of animal movement from camera trap videos for a set of tropical forest mammals and used these characteristics to generate detailed movement paths. We then sampled these paths at different frequencies, simulating telemetry studies, and quantified the accuracy of sampled travel distance estimation. 3. For our focal species, typical telemetry studies would underestimate distances travelled by 67ā€“93\%, and extremely high sampling frequencies (several fixes per minute) would be required to get tolerably accurate estimates. The form of the relationship between tortuosity, sample frequency, and distance travelled was such that absolute distance cannot accurately be estimated by the infrequent samples used in typical tracking studies. 4. We conclude that the underestimation of distance travelled is a serious but underappreciated problem. Currently, there is no reliable, widely applicable method to obtain approximately unbiased estimates of distance travelled by animals. Further research on this problem is needed.}, + language = {en}, + number = {4}, + urldate = {2021-02-14}, + journal = {Methods in Ecology and Evolution}, + author = {Rowcliffe, J. Marcus and Carbone, Chris and Kays, Roland and Kranstauber, Bart and Jansen, Patrick A.}, + year = {2012}, + note = {\_eprint: https://besjournals.onlinelibrary.wiley.com/doi/pdf/10.1111/j.2041-210X.2012.00197.x}, + keywords = {Barro Colorado Island, camera traps, daily distance, day range, movement models, radiotracking, random walk, telemetry, travel distance, tropical forest}, + pages = {653--662}, +} + +@article{patterson_statistical_2017, + title = {Statistical modelling of individual animal movement: an overview of key methods and a discussion of practical challenges}, + volume = {101}, + issn = {1863-818X}, + url = {https://doi.org/10.1007/s10182-017-0302-7}, + doi = {10.1007/s10182-017-0302-7}, + number = {4}, + journal = {AStA Advances in Statistical Analysis}, + author = {Patterson, Toby A. and Parton, Alison and Langrock, Roland and Blackwell, Paul G. and Thomas, Len and King, Ruth}, + year = {2017}, + note = {Type: Journal Article}, + pages = {399--438}, +} + +@article{morris_stride_1996, + title = {Stride length regulation in {Parkinson}'s disease. {Normalization} strategies and underlying mechanisms}, + volume = {119 ( Pt 2)}, + issn = {0006-8950}, + doi = {10.1093/brain/119.2.551}, + abstract = {Results of our previous studies have shown that the slow, shuffling gait of Parkinson's disease patients is due to an inability to generate appropriate stride length and that cadence control is intact and is used as a compensatory mechanism. The reason for the reduced stride length is unclear, although deficient internal cue production or inadequate contribution to cortical motor set by the basal ganglia are two possible explanations. In this study we have examined the latter possibility by comparing the long-lasting effects of visual cues in improving stride length with that of attentional strategies. Computerized stride analysis was used to measure the spatial (distance) and temporal (timing) parameters of the walking pattern in a total of 54 subjects in three separate studies. In each study Parkinson's disease subjects were trained for 20 min by repeated 10 m walks set at control stride length (determined from control subjects matched for age, sex and height), using either visual floor markers or a mental picture of the appropriate stride size. Following training, the gait patterns were monitored (i) every 15 min for 2 h; (ii) whilst interspersing secondary tasks of increasing levels of complexity; (iii) covertly, when subjects were unaware that measurement was taking place. The results demonstrated that training with both visual cues and attentional strategies could maintain normal gait for the maximum recording time of 2 h. Secondary tasks reduced stride length towards baseline values as did covert monitoring. The findings confirm that the ability to generate a normal stepping pattern is not lost in Parkinson's disease and that gait hypokinesia reflects a difficulty in activating the motor control system. Normal stride length can be elicited in Parkinson's disease using attentional strategies and visual cues. Both strategies appear to share the same mechanism of focusing attention on the stride length. The effect of attention appears to require constant vigilance to prevent reverting to more automatic control mechanisms.}, + language = {eng}, + journal = {Brain: A Journal of Neurology}, + author = {Morris, M. E. and Iansek, R. and Matyas, T. A. and Summers, J. J.}, + month = apr, + year = {1996}, + pmid = {8800948}, + keywords = {Aged, Aged, 80 and over, Attention, Cues, Female, Gait, Humans, Male, Middle Aged, Parkinson Disease, Time Factors}, + pages = {551--568} +} + +@article{miller_locomotion_1975, + title = {Locomotion in the cat: basic programmes of movement}, + volume = {91}, + issn = {0006-8993}, + shorttitle = {Locomotion in the cat}, + doi = {10.1016/0006-8993(75)90545-4}, + abstract = {Observations in cats of flexion and extension movements of the 4 limbs have led to the conclusion that the different forms of alternative locomotion (e.g. walking, trotting, swimming) and in-phase locomotion (galloping, jumping) result from the interaction of 'programmes' for the coordination of (1) the homologous limbs (pair of hindlimbs or pair of forelimbs) and (2) the homolateral limbs (hind- and forelimb of the same side of the body). The movements of the homologous pairs of limbs are coupled out of phase in alternate locomotion and approximately in phase in the phase form of locomotion. The movements of the homolateral pairs of limbs occur approximately out of phase in the trotting type of coupling and approximately in phase in the pacing type of coupling. Transitions between the different forms of coupling occur abruptly over 1 or 2 steps. Therefore, for each type of coupling (homologous or homolateral) there are two distinct forms or 'programmes' of movement. The hypothesis is advanced that (a) all the characteristic patterns of locomotion in the cat result from different combinations of these 'programmes' of homologous and homolateral limb coupling; (b) the 'programmes' are mutually self reinforcing in the gaits in which the coordination of the movements of the 4 limbs is bilaterally symmetrical; (c) the 'programmes' act in competition in certain gaits which are not bilaterally symmetrical giving rise at times to a changing gait pattern, and (d) the temporary dominance of one 'programme' or another can determine the gait of the particular step.}, + language = {eng}, + number = {2}, + journal = {Brain Research}, + author = {Miller, S. and Van Der Burg, J. and Van Der MechĆ©, F.}, + month = jun, + year = {1975}, + pmid = {1080684}, + keywords = {5-Hydroxytryptophan, Animals, Cats, Clonidine, Decerebrate State, Forelimb, Gait, Hindlimb, Levodopa, Movement, Spinal Cord, Swimming}, + pages = {239--253} +} + +@article{morris_gait_2001, + title = {Gait disorders and gait rehabilitation in {Parkinson}'s disease}, + volume = {87}, + issn = {0091-3952}, + language = {eng}, + journal = {Advances in Neurology}, + author = {Morris, M. E. and Huxham, F. E. and McGinley, J. and Iansek, R.}, + year = {2001}, + pmid = {11347239}, + keywords = {Biomechanical Phenomena, Gait, Gait Disorders, Neurologic, Humans, Parkinson Disease}, + pages = {347--361} +} + +@article{barriere_prominent_2008, + title = {Prominent role of the spinal central pattern generator in the recovery of locomotion after partial spinal cord injuries}, + volume = {28}, + issn = {1529-2401}, + doi = {10.1523/JNEUROSCI.5692-07.2008}, + abstract = {The re-expression of hindlimb locomotion after complete spinal cord injuries (SCIs) is caused by the presence of a spinal central pattern generator (CPG) for locomotion. After partial SCI, however, the role of this spinal CPG in the recovery of hindlimb locomotion in the cat remains mostly unknown. In the present work, we devised a dual-lesion paradigm to determine its possible contribution after partial SCI. After a partial section of the left thoracic segment T10 or T11, cats gradually recovered voluntary quadrupedal locomotion. Then, a complete transection was performed two to three segments more caudally (T13-L1) several weeks after the first partial lesion. Cats that received intensive treadmill training after the partial lesion expressed bilateral hindlimb locomotion within hours of the complete lesion. Untrained cats however showed asymmetrical hindlimb locomotion with the limb on the side of the partial lesion walking well before the other hindlimb. Thus, the complete spinalization revealed that the spinal CPG underwent plastic changes after the partial lesions, which were shaped by locomotor training. Over time, with further treadmill training, the asymmetry disappeared and a bilateral locomotion was reinstated. Therefore, although remnant intact descending pathways must contribute to voluntary goal-oriented locomotion after partial SCI, the recovery and re-expression of the hindlimb locomotor pattern mostly results from intrinsic changes below the lesion in the CPG and afferent inputs.}, + language = {eng}, + number = {15}, + journal = {The Journal of Neuroscience: The Official Journal of the Society for Neuroscience}, + author = {BarriĆØre, GrĆ©gory and Leblond, Hugues and Provencher, Janyne and Rossignol, Serge}, + month = apr, + year = {2008}, + pmid = {18400897}, + keywords = {Animals, Cats, Extremities, Female, Lumbar Vertebrae, Male, Motor Activity, Neuronal Plasticity, Physical Conditioning, Animal, Recovery of Function, Spinal Cord, Spinal Cord Injuries, Thoracic Vertebrae}, + pages = {3976--3987} +} + +@article{cascallares_role_2018, + title = {Role of the circadian clock in the statistics of locomotor activity in {Drosophila}.}, + volume = {13}, + url = {http://dx.doi.org/10.1371/journal.pone.0202505}, + doi = {10.1371/journal.pone.0202505}, + abstract = {In many animals the circadian rhythm of locomotor activity is controlled by an endogenous circadian clock. Using custom made housing and video tracking software in order to obtain high spatial and temporal resolution, we studied the statistical properties of the locomotor activity of wild type and two clock mutants of Drosophila melanogaster. We show here that the distributions of activity and quiescence bouts for the clock mutants in light-dark conditions (LD) are very different from the distributions obtained when there are no external cues from the environment (DD). In the wild type these distributions are very similar, showing that the clock controls this aspect of behavior in both regimes (LD and DD). Furthermore, the distributions are very similar to those reported for Wistar rats. For the timing of events we also observe important differences, quantified by how the event rate distributions scale for increasing time windows. We find that for the wild type these distributions can be rescaled by the same function in DD as in LD. Interestingly, the same function has been shown to rescale the rate distributions in Wistar rats. On the other hand, for the clock mutants it is not possible to rescale the rate distributions, which might indicate that the extent of circadian control depends on the statistical properties of activity and quiescence.}, + number = {8}, + urldate = {2019-07-12}, + journal = {Plos One}, + author = {Cascallares, Guadalupe and Riva, Sabrina and Franco, D Lorena and Risau-Gusman, Sebastian and Gleiser, Pablo M}, + month = aug, + year = {2018}, + pmid = {30138403}, + pmcid = {PMC6107170}, + pages = {e0202505} +} + +@book{batschelet_circular_1981, + address = {London}, + title = {Circular {Statistics} {In} {Biology} (mathematics {In} {Biology})}, + isbn = {0-12-081050-6}, + urldate = {2019-07-12}, + publisher = {Academic Press}, + author = {Batschelet, Edward}, + year = {1981} +} + +@article{wiesmann_specific_2017, + title = {A specific dietary intervention to restore brain structure and function after ischemic stroke.}, + volume = {7}, + url = {http://dx.doi.org/10.7150/thno.17559}, + doi = {10.7150/thno.17559}, + abstract = {Occlusion of the middle cerebral artery (MCAo) is among the most common causes of ischemic stroke in humans. Cerebral ischemia leads to brain lesions existing of an irreversibly injured core and an ischemic boundary zone, the penumbra, containing damaged but potentially salvageable tissue. Using a transient occlusion (30 min) of the middle cerebral artery (tMCAo) mouse model in this cross-institutional study we investigated the neurorestorative efficacy of a dietary approach (Fortasyn) comprising docosahexaenoic acid, eicosapentaenoic acid, uridine, choline, phospholipids, folic acid, vitamins B12, B6, C, and E, and selenium as therapeutic approach to counteract neuroinflammation and impairments of cerebral (structural+functional) connectivity, cerebral blood flow (CBF), and motor function. Male adult C57BL/6j mice were subjected to right tMCAo using the intraluminal filament model. Following tMCAo, animals were either maintained on Control diet or switched to the multicomponent Fortasyn diet. At several time points after tMCAo, behavioral tests, and MRI and PET scanning were conducted to identify the impact of the multicomponent diet on the elicited neuroinflammatory response, loss of cerebral connectivity, and the resulting impairment of motor function after experimental stroke. Mice on the multicomponent diet showed decreased neuroinflammation, improved functional and structural connectivity, beneficial effect on CBF, and also improved motor function after tMCAo. Our present data show that this specific dietary intervention may have beneficial effects on structural and functional recovery and therefore therapeutic potential after ischemic stroke.}, + number = {2}, + urldate = {2019-03-14}, + journal = {Theranostics}, + author = {Wiesmann, Maximilian and Zinnhardt, Bastian and Reinhardt, Dirk and Eligehausen, Sarah and Wachsmuth, Lydia and Hermann, Sven and Dederen, Pieter J and Hellwich, Marloes and Kuhlmann, Michael T and Broersen, Laus M and Heerschap, Arend and Jacobs, Andreas H and Kiliaan, Amanda J}, + month = jan, + year = {2017}, + pmid = {28255345}, + pmcid = {PMC5327363}, + pages = {493--512} +} + +@article{benjamini_ten_2010, + title = {Ten ways to improve the quality of descriptions of whole-animal movement.}, + volume = {34}, + url = {http://dx.doi.org/10.1016/j.neubiorev.2010.04.004}, + doi = {10.1016/j.neubiorev.2010.04.004}, + abstract = {The demand for replicability of behavioral results across laboratories is viewed as a burden in behavior genetics. We demonstrate how it can become an asset offering a quantitative criterion that guides the design of better ways to describe behavior. Passing the high benchmark dictated by the replicability demand requires less stressful and less restraining experimental setups, less noisy data, individually customized cutoff points between the building blocks of movement, and less variable yet discriminative dynamic representations that would capture more faithfully the nature of the behavior, unmasking similarities and differences and revealing novel animal-centered measures. Here we review ten tools that enhance replicability without compromising discrimination. While we demonstrate the usefulness of these tools in the context of inbred mouse exploratory behavior they can readily be used in any study involving a high-resolution analysis of spatial behavior. Viewing replicability as a design concept and using the ten methodological improvements may prove useful in many fields not necessarily related to spatial behavior.}, + number = {8}, + urldate = {2019-03-11}, + journal = {Neuroscience and Biobehavioral Reviews}, + author = {Benjamini, Yoav and Lipkind, Dina and Horev, Guy and Fonio, Ehud and Kafkafi, Neri and Golani, Ilan}, + month = jul, + year = {2010}, + pmid = {20399806}, + pages = {1351--1365} +} + +@article{maier_big_2017, + title = {Big data in large-scale systemic mouse phenotyping}, + volume = {4}, + issn = {24523100}, + url = {https://linkinghub.elsevier.com/retrieve/pii/S2452310017300525}, + doi = {10.1016/j.coisb.2017.07.012}, + abstract = {Systemic phenotyping of mutant mice has been established at large scale in the last decade as a new tool to uncover the relations between genotype, phenotype and environment. Recent advances in that field led to the generation of a valuable open access data resource that can be used to better understanding the underlying causes for human diseases. From an ethical perspective, systemic phenotyping significantly contributes to the reduction of experimental animals and the refinement of animal experiments by enforcing standardisation efforts. There are particular logistical, experimental and analytical challenges of systemic large-scale mouse phenotyping. On all levels, IT solutions are critical to implement and efficiently support breeding, phenotyping and data analysis processes that lead to the generation of high-quality systemic phenotyping data accessible for the scientific community.}, + urldate = {2019-01-13}, + journal = {Current Opinion in Systems Biology}, + author = {Maier, Holger and Leuchtenberger, Stefanie and Fuchs, Helmut and Gailus-Durner, Valerie and Hrabe de Angelis, Martin}, + month = aug, + year = {2017}, + pages = {97--104} +} + +@article{wiesmann_effect_2018, + title = {Effect of a multinutrient intervention after ischemic stroke in female {C}57Bl/6 mice.}, + volume = {144}, + url = {http://dx.doi.org/10.1111/jnc.14213}, + doi = {10.1111/jnc.14213}, + abstract = {Stroke can affect females very differently from males, and therefore preclinical research on underlying mechanisms and the effects of interventions should not be restricted to male subjects, and treatment strategies for stroke should be tailored to benefit both sexes. Previously, we demonstrated that a multinutrient intervention (Fortasyn) improved impairments after ischemic stroke induction in male C57Bl/6 mice, but the therapeutic potential of this dietary treatment remained to be investigated in females. We now induced a transient middle cerebral artery occlusion (tMCAo) in C57Bl/6 female mice and immediately after surgery switched to either Fortasyn or an isocaloric Control diet. The stroke females performed several behavioral and motor tasks before and after tMCAo and were scanned in an 11.7 Tesla magnetic resonance imaging (MRI) scanner to assess brain perfusion, integrity, and functional connectivity. To assess brain plasticity, inflammation, and vascular integrity, immunohistochemistry was performed after killing of the mice. We found that the multinutrient intervention had diverse effects on the stroke-induced impairments in females. Similar to previous observations in male stroke mice, brain integrity, sensorimotor integration and neurogenesis benefitted from Fortasyn, but impairments in activity and motor skills were not improved in female stroke mice. Overall, Fortasyn effects in the female stroke mice seem more modest in comparison to previously investigated male stroke mice. We suggest that with further optimization of treatment protocols more information on the efficacy of specific interventions in stroked females can be gathered. This in turn will help with the development of (gender-specific) treatment regimens for cerebrovascular diseases such as stroke. This article is part of the Special Issue "Vascular Dementia". {\textbackslash}copyright 2017 International Society for Neurochemistry.}, + number = {5}, + urldate = {2019-01-13}, + journal = {Journal of Neurochemistry}, + author = {Wiesmann, Maximilian and Timmer, Nienke M and Zinnhardt, Bastian and Reinhard, Dirk and Eligehausen, Sarah and Kƶnigs, Anja and Ben Jeddi, Hasnae and Dederen, Pieter J and Jacobs, Andreas H and Kiliaan, Amanda J}, + month = mar, + year = {2018}, + pmid = {28888042}, + pages = {549--564} +} + +@article{zheng_trajectory_2015, + title = {Trajectory {Data} {Mining}}, + volume = {6}, + issn = {21576904}, + url = {http://dl.acm.org/citation.cfm?doid=2764959.2743025}, + doi = {10.1145/2743025}, + abstract = {The advances in location-acquisition and mobile computing techniques have generated massive spatial trajectory data, which represent the mobility of a diversity of moving objects, such as people, vehicles, and animals. Many techniques have been proposed for processing, managing, and mining trajectory data in the past decade, fostering a broad range of applications. In this article, we conduct a systematic survey on the major research into trajectory data mining , providing a panorama of the field as well as the scope of its research topics. Following a road map from the derivation of trajectory data, to trajectory data preprocessing, to trajectory data management, and to a variety of mining tasks (such as trajectory pattern mining, outlier detection, and trajectory classification), the survey explores the connections, correlations, and differences among these existing techniques. This survey also introduces the methods that transform trajectories into other data formats, such as graphs, matrices, and tensors, to which more data mining and machine learning techniques can be applied. Finally, some public trajectory datasets are presented. This survey can help shape the field of trajectory data mining , providing a quick understanding of this field to the community.}, + number = {3}, + urldate = {2019-03-23}, + journal = {ACM transactions on intelligent systems and technology}, + author = {Zheng, Yu}, + month = may, + year = {2015}, + pages = {1--41} +} + +@article{valletta_applications_2017, + title = {Applications of machine learning in animal behaviour studies}, + volume = {124}, + issn = {00033472}, + url = {http://linkinghub.elsevier.com/retrieve/pii/S0003347216303360}, + doi = {10.1016/j.anbehav.2016.12.005}, + abstract = {Highlightsā€¢Machine learning (ML) offers a hypothesis-free approach to modelling complex data.ā€¢We present a review of ML techniques pertinent to the study of animal behaviour.ā€¢Key ML approaches are illustrated using three different case studies.ā€¢ML offers a useful addition to the animal behaviourist's analytical toolbox. In many areas of animal behaviour research, improvements in our ability to collect large and detailed data sets are outstripping our ability to analyse them. These diverse, complex and often high-dimensional data sets exhibit nonlinear dependencies and unknown interactions across multiple variables, and may fail to conform to the assumptions of many classical statistical methods. The field of machine learning provides methodologies that are ideally suited to the task of extracting knowledge from these data. In this review, we aim to introduce animal behaviourists unfamiliar with machine learning (ML) to the promise of these techniques for the analysis of complex behavioural data. We start by describing the rationale behind ML and review a number of animal behaviour studies where ML has been successfully deployed. The ML framework is then introduced by presenting several unsupervised and supervised learning methods. Following this overview, we illustrate key ML approaches by developing data analytical pipelines for three different case studies that exemplify the types of behavioural and ecological questions ML can address. The first uses a large number of spectral and morphological characteristics that describe the appearance of pheasant, Phasianus colchicus, eggs to assign them to putative clutches. The second takes a continuous data stream of feeder visits from PIT (passive integrated transponder)-tagged jackdaws, Corvus monedula, and extracts foraging events from it, which permits the construction of social networks. Our final example uses aerial images to train a classifier that detects the presence of wildebeest, Connochaetes taurinus, to count individuals in a population. With the advent of cheaper sensing and tracking technologies an unprecedented amount of data on animal behaviour is becoming available. We believe that ML will play a central role in translating these data into scientific knowledge and become a useful addition to the animal behaviourist's analytical toolkit.}, + urldate = {2019-07-12}, + journal = {Animal Behaviour}, + author = {Valletta, John Joseph and Torney, Colin and Kings, Michael and Thornton, Alex and Madden, Joah}, + month = feb, + year = {2017}, + pages = {203--220} +} + +@article{brown_compass:_2016, + title = {{COMPA}{\textbackslash}{SS}: continuous open mouse phenotyping of activity and sleep status.}, + volume = {1}, + url = {http://dx.doi.org/10.12688/wellcomeopenres.9892.2}, + doi = {10.12688/wellcomeopenres.9892.2}, + abstract = {Background Disruption of rhythms in activity and rest occur in many diseases, and provide an important indicator of healthy physiology and behaviour. However, outside the field of sleep and circadian rhythm research, these rhythmic processes are rarely measured due to the requirement for specialised resources and expertise. Until recently, the primary approach to measuring activity in laboratory rodents has been based on voluntary running wheel activity. By contrast, measuring sleep requires the use of electroencephalography (EEG), which involves invasive surgical procedures and time-consuming data analysis. Methods Here we describe a simple, non-invasive system to measure home cage activity in mice based upon passive infrared (PIR) motion sensors. Careful calibration of this system will allow users to simultaneously assess sleep status in mice. The use of open-source tools and simple sensors keeps the cost and the size of data-files down, in order to increase ease of use and uptake. Results In addition to providing accurate data on circadian activity parameters, here we show that extended immobility of {\textbackslash}textgreater40 seconds provides a reliable indicator of sleep, correlating well with EEG-defined sleep (Pearson's r {\textbackslash}textgreater0.95, 4 mice). Conclusions Whilst any detailed analysis of sleep patterns in mice will require EEG, behaviourally-defined sleep provides a valuable non-invasive means of simultaneously phenotyping both circadian rhythms and sleep. Whilst previous approaches have relied upon analysis of video data, here we show that simple motion sensors provide a cheap and effective alternative, enabling real-time analysis and longitudinal studies extending over weeks or even months. The data files produced are small, enabling easy deposition and sharing. We have named this system COMPA{\textbackslash}SS - Continuous Open Mouse Phenotyping of Activity and Sleep Status. This simple approach is of particular value in phenotyping screens as well as providing an ideal tool to assess activity and rest cycles for non-specialists.}, + urldate = {2019-03-14}, + journal = {Wellcome Open Research}, + author = {Brown, Laurence A and Hasan, Sibah and Foster, Russell G and Peirson, Stuart N}, + month = nov, + year = {2016}, + pmid = {27976750}, + pmcid = {PMC5140024}, + pages = {2} +} + +@article{dickinson_high-throughput_2016, + title = {High-throughput discovery of novel developmental phenotypes.}, + volume = {537}, + url = {http://dx.doi.org/10.1038/nature19356}, + doi = {10.1038/nature19356}, + abstract = {Approximately one-third of all mammalian genes are essential for life. Phenotypes resulting from knockouts of these genes in mice have provided tremendous insight into gene function and congenital disorders. As part of the International Mouse Phenotyping Consortium effort to generate and phenotypically characterize 5,000 knockout mouse lines, here we identify 410 lethal genes during the production of the first 1,751 unique gene knockouts. Using a standardized phenotyping platform that incorporates high-resolution 3D imaging, we identify phenotypes at multiple time points for previously uncharacterized genes and additional phenotypes for genes with previously reported mutant phenotypes. Unexpectedly, our analysis reveals that incomplete penetrance and variable expressivity are common even on a defined genetic background. In addition, we show that human disease genes are enriched for essential genes, thus providing a dataset that facilitates the prioritization and validation of mutations identified in clinical sequencing efforts.}, + number = {7621}, + urldate = {2018-02-07}, + journal = {Nature}, + author = {Dickinson, Mary E and Flenniken, Ann M and Ji, Xiao and Teboul, Lydia and Wong, Michael D and White, Jacqueline K and Meehan, Terrence F and Weninger, Wolfgang J and Westerberg, Henrik and Adissu, Hibret and Baker, Candice N and Bower, Lynette and Brown, James M and Caddle, L Brianna and Chiani, Francesco and Clary, Dave and Cleak, James and Daly, Mark J and Denegre, James M and Doe, Brendan and Dolan, Mary E and Edie, Sarah M and Fuchs, Helmut and Gailus-Durner, Valerie and Galli, Antonella and Gambadoro, Alessia and Gallegos, Juan and Guo, Shiying and Horner, Neil R and Hsu, Chih-Wei and Johnson, Sara J and Kalaga, Sowmya and Keith, Lance C and Lanoue, Louise and Lawson, Thomas N and Lek, Monkol and Mark, Manuel and Marschall, Susan and Mason, Jeremy and McElwee, Melissa L and Newbigging, Susan and Nutter, Lauryl M J and Peterson, Kevin A and Ramirez-Solis, Ramiro and Rowland, Douglas J and Ryder, Edward and Samocha, Kaitlin E and Seavitt, John R and Selloum, Mohammed and Szoke-Kovacs, Zsombor and Tamura, Masaru and Trainor, Amanda G and Tudose, Ilinca and Wakana, Shigeharu and Warren, Jonathan and Wendling, Olivia and West, David B and Wong, Leeyean and Yoshiki, Atsushi and Consortium, International Mouse Phenotyping and Laboratory, Jackson and Infrastructure Nationale PHENOMIN, Institut Clinique de la Souris (ICS) and Laboratories, Charles River and Harwell, M. R. C. and Phenogenomics, Toronto Centre for and Institute, Wellcome Trust Sanger and Center, RIKEN BioResource and MacArthur, Daniel G and Tocchini-Valentini, Glauco P and Gao, Xiang and Flicek, Paul and Bradley, Allan and Skarnes, William C and Justice, Monica J and Parkinson, Helen E and Moore, Mark and Wells, Sara and Braun, Robert E and Svenson, Karen L and de Angelis, Martin Hrabe and Herault, Yann and Mohun, Tim and Mallon, Ann-Marie and Henkelman, R Mark and Brown, Steve D M and Adams, David J and Lloyd, K C Kent and McKerlie, Colin and Beaudet, Arthur L and Bućan, Maja and Murray, Stephen A}, + month = sep, + year = {2016}, + pmid = {27626380}, + pmcid = {PMC5295821}, + pages = {508--514} +} + +@article{pack_novel_2007, + title = {Novel method for high-throughput phenotyping of sleep in mice.}, + volume = {28}, + url = {http://dx.doi.org/10.1152/physiolgenomics.00139.2006}, + doi = {10.1152/physiolgenomics.00139.2006}, + abstract = {Assessment of sleep in mice currently requires initial implantation of chronic electrodes for assessment of electroencephalogram (EEG) and electromyogram (EMG) followed by time to recover from surgery. Hence, it is not ideal for high-throughput screening. To address this deficiency, a method of assessment of sleep and wakefulness in mice has been developed based on assessment of activity/inactivity either by digital video analysis or by breaking infrared beams in the mouse cage. It is based on the algorithm that any episode of continuous inactivity of {\textbackslash}textgreater or =40 s is predicted to be sleep. The method gives excellent agreement in C57BL/6J male mice with simultaneous assessment of sleep by EEG/EMG recording. The average agreement over 8,640 10-s epochs in 24 h is 92\% (n = 7 mice) with agreement in individual mice being 88-94\%. Average EEG/EMG determined sleep per 2-h interval across the day was 59.4 min. The estimated mean difference (bias) per 2-h interval between inactivity-defined sleep and EEG/EMG-defined sleep was only 1.0 min (95\% confidence interval for mean bias -0.06 to +2.6 min). The standard deviation of differences (precision) was 7.5 min per 2-h interval with 95\% limits of agreement ranging from -13.7 to +15.7 min. Although bias significantly varied by time of day (P = 0.0007), the magnitude of time-of-day differences was not large (average bias during lights on and lights off was +5.0 and -3.0 min per 2-h interval, respectively). This method has applications in chemical mutagenesis and for studies of molecular changes in brain with sleep/wakefulness.}, + number = {2}, + urldate = {2019-03-14}, + journal = {Physiological Genomics}, + author = {Pack, Allan I and Galante, Raymond J and Maislin, Greg and Cater, Jacqueline and Metaxas, Dimitris and Lu, Shan and Zhang, Lin and Von Smith, Randy and Kay, Timothy and Lian, Jie and Svenson, Karen and Peters, Luanne L}, + month = jan, + year = {2007}, + pmid = {16985007}, + pages = {232--238} +} + +@article{eckel-mahan_phenotyping_2015, + title = {Phenotyping circadian rhythms in mice.}, + volume = {5}, + url = {http://dx.doi.org/10.1002/9780470942390.mo140229}, + doi = {10.1002/9780470942390.mo140229}, + abstract = {Circadian rhythms take place with a periodicity of 24 hr, temporally following the rotation of the earth around its axis. Examples of circadian rhythms are the sleep/wake cycle, feeding, and hormone secretion. Light powerfully entrains the mammalian clock and assists in keeping animals synchronized to the 24-hour cycle of the earth by activating specific neurons in the "central pacemaker" of the brain, the suprachiasmatic nucleus. Absolute periodicity of an animal can deviate slightly from 24 hr as manifest when an animal is placed into constant dark or "free-running" conditions. Simple measurements of an organism's activity in free-running conditions reveal its intrinsic circadian period. Mice are a particularly useful model for studying circadian rhythmicity due to the ease of genetic manipulation, thus identifying molecular contributors to rhythmicity. Furthermore, their small size allows for monitoring locomotion or activity in their homecage environment with relative ease. Several tasks commonly used to analyze circadian periodicity and plasticity in mice are presented here including the process of entrainment, determination of tau (period length) in free-running conditions, determination of circadian periodicity in response to light disruption (e.g., jet lag studies), and evaluation of clock plasticity in non-24-hour conditions (T-cycles). Studying the properties of circadian periods such as their phase, amplitude, and length in response to photic perturbation, can be particularly useful in understanding how humans respond to jet lag, night shifts, rotating shifts, or other transient or chronic disruption of environmental surroundings. Copyright {\textbackslash}copyright 2015 John Wiley \& Sons, Inc.}, + number = {3}, + urldate = {2019-03-15}, + journal = {Current protocols in mouse biology}, + author = {Eckel-Mahan, Kristin and Sassone-Corsi, Paolo}, + month = sep, + year = {2015}, + pmid = {26331760}, + pmcid = {PMC4732881}, + pages = {271--281} +} + +@article{rosenthal_mouse_2007, + title = {The mouse ascending: perspectives for human-disease models.}, + volume = {9}, + url = {http://dx.doi.org/10.1038/ncb437}, + doi = {10.1038/ncb437}, + abstract = {The laboratory mouse is widely considered the model organism of choice for studying the diseases of humans, with whom they share 99\% of their genes. A distinguished history of mouse genetic experimentation has been further advanced by the development of powerful new tools to manipulate the mouse genome. The recent launch of several international initiatives to analyse the function of all mouse genes through mutagenesis, molecular analysis and phenotyping underscores the utility of the mouse for translating the information stored in the human genome into increasingly accurate models of human disease.}, + number = {9}, + urldate = {2019-01-12}, + journal = {Nature Cell Biology}, + author = {Rosenthal, Nadia and Brown, Steve}, + month = sep, + year = {2007}, + pmid = {17762889}, + pages = {993--999} +} + +@article{noldus_ethovision:_2001, + title = {{EthoVision}: a versatile video tracking system for automation of behavioral experiments.}, + volume = {33}, + url = {http://dx.doi.org/10.3758/BF03195394}, + doi = {10.3758/BF03195394}, + abstract = {The need for automating behavioral observations and the evolution of systems developed for that purpose is outlined. Video tracking systems enable researchers to study behavior in a reliable and consistent way and over longer time periods than if they were using manual recording. To overcome limitations of currently available systems, we have designed EthoVision, an integrated system for automatic recording of activity, movement, and interactions of animals. The EthoVision software is presented, highlighting some key features that separate EthoVision from other systems: easy file management, independent variable definition, flexible arena and zone design, several methods of data acquisition allowing identification and tracking of multiple animals in multiple arenas, and tools for visualization of the tracks and calculation of a range of analysis parameters. A review of studies using EthoVision is presented, demonstrating the system's use in a wide variety of applications. Possible future directions for development are discussed.}, + number = {3}, + urldate = {2019-07-12}, + journal = {Behavior research methods, instruments, \& computers : a journal of the Psychonomic Society, Inc}, + author = {Noldus, L P and Spink, A J and Tegelenbosch, R A}, + month = aug, + year = {2001}, + pmid = {11591072}, + pages = {398--414} +} + +@article{goulding_robust_2008, + title = {A robust automated system elucidates mouse home cage behavioral structure.}, + volume = {105}, + issn = {1091-6490}, + url = {http://dx.doi.org/10.1073/pnas.0809053106}, + doi = {10.1073/pnas.0809053106}, + abstract = {Patterns of behavior exhibited by mice in their home cages reflect the function and interaction of numerous behavioral and physiological systems. Detailed assessment of these patterns thus has the potential to provide a powerful tool for understanding basic aspects of behavioral regulation and their perturbation by disease processes. However, the capacity to identify and examine these patterns in terms of their discrete levels of organization across diverse behaviors has been difficult to achieve and automate. Here, we describe an automated approach for the quantitative characterization of fundamental behavioral elements and their patterns in the freely behaving mouse. We demonstrate the utility of this approach by identifying unique features of home cage behavioral structure and changes in distinct levels of behavioral organization in mice with single gene mutations altering energy balance. The robust, automated, reproducible quantification of mouse home cage behavioral structure detailed here should have wide applicability for the study of mammalian physiology, behavior, and disease.}, + number = {52}, + urldate = {2019-03-11}, + journal = {Proceedings of the National Academy of Sciences of the United States of America}, + author = {Goulding, Evan H and Schenk, A Katrin and Juneja, Punita and MacKay, Adrienne W and Wade, Jennifer M and Tecott, Laurence H}, + month = dec, + year = {2008}, + pmid = {19106295}, + pmcid = {PMC2634928}, + pages = {20575--20582} +} + +@article{jhuang_automated_2010, + title = {Automated home-cage behavioural phenotyping of mice.}, + volume = {1}, + url = {http://dx.doi.org/10.1038/ncomms1064}, + doi = {10.1038/ncomms1064}, + abstract = {Neurobehavioural analysis of mouse phenotypes requires the monitoring of mouse behaviour over long periods of time. In this study, we describe a trainable computer vision system enabling the automated analysis of complex mouse behaviours. We provide software and an extensive manually annotated video database used for training and testing the system. Our system performs on par with human scoring, as measured from ground-truth manual annotations of thousands of clips of freely behaving mice. As a validation of the system, we characterized the home-cage behaviours of two standard inbred and two non-standard mouse strains. From these data, we were able to predict in a blind test the strain identity of individual animals with high accuracy. Our video-based software will complement existing sensor-based automated approaches and enable an adaptable, comprehensive, high-throughput, fine-grained, automated analysis of mouse behaviour.}, + urldate = {2019-03-11}, + journal = {Nature Communications}, + author = {Jhuang, Hueihan and Garrote, Estibaliz and Mutch, Jim and Yu, Xinlin and Khilnani, Vinita and Poggio, Tomaso and Steele, Andrew D and Serre, Thomas}, + month = sep, + year = {2010}, + pmid = {20842193}, + pages = {68} +} + +@article{casadesus_automated_2001, + title = {Automated measurement of age-related changes in the locomotor response to environmental novelty and home-cage activity.}, + volume = {122}, + url = {https://www.ncbi.nlm.nih.gov/pubmed/11557287}, + abstract = {The likelihood to explore in an open-field environment decreases with age. Older animals tend to be less active and explore less both in novel and home-cage environments. The locomotor performance (fine movements, ambulatory movements, and rearing) of male Fischer 344 (F344) rats that were 6 (n=6) or 22 (n=6) months of age was evaluated by continuous automated counting of photobeam interruptions, every 30 min, during 60 consecutive hours, in standard polycarbonate cages. Novel environment performance was determined by photobeam interruption counting during the first hour in the new cage. The remaining 59 h were evaluated as home-cage activity. A significant age-related decrease in ambulatory and fine motor activity was seen during the first hour of testing (novel environment). In addition, aged rats showed a decreased number of ambulatory and fine movements in home-cage activity, predominantly during the dark portion of the light cycle and during or around both light-switch periods (05:00 and 17:00). No differences were seen in rearing behavior. These findings provide a more detailed analysis and additional evidence of the activity decreases and rhythmic changes seen in aged F344 rats under uninterrupted testing conditions.}, + number = {15}, + urldate = {2019-07-12}, + journal = {Mechanisms of Ageing and Development}, + author = {Casadesus, G and Shukitt-Hale, B and Joseph, J A}, + month = oct, + year = {2001}, + pmid = {11557287}, + pages = {1887--1897}, + doi ={10.1016/s0047-6374(01)00324-4 }, +} + +@article{crawley_behavioral_2008, + title = {Behavioral phenotyping strategies for mutant mice.}, + volume = {57}, + url = {http://dx.doi.org/10.1016/j.neuron.2008.03.001}, + doi = {10.1016/j.neuron.2008.03.001}, + abstract = {Comprehensive behavioral analyses of transgenic and knockout mice have successfully identified the functional roles of many genes in the brain. Over the past 10 years, strategies for mouse behavioral phenotyping have evolved to maximize the scope and replicability of findings from a cohort of mutant mice, minimize the interpretation of procedural artifacts, and provide robust translational tools to test hypotheses and develop treatments. This Primer addresses experimental design issues and offers examples of high-throughput batteries, learning and memory tasks, and anxiety-related tests.}, + number = {6}, + urldate = {2019-03-14}, + journal = {Neuron}, + author = {Crawley, Jacqueline N}, + month = mar, + year = {2008}, + pmid = {18367082}, + pages = {809--818} +} + +@article{tester_arm_2012, + title = {Arm and leg coordination during treadmill walking in individuals with motor incomplete spinal cord injury: a preliminary study.}, + volume = {36}, + url = {http://dx.doi.org/10.1016/j.gaitpost.2012.01.004}, + doi = {10.1016/j.gaitpost.2012.01.004}, + abstract = {Arm and leg coordination naturally emerges during walking, but can be affected by stroke or Parkinson's disease. The purpose of this preliminary study was to characterize arm and leg coordination during treadmill walking at self-selected comfortable walking speeds (CWSs) in individuals using arm swing with motor incomplete spinal cord injury (iSCI). Hip and shoulder angle cycle durations and amplitudes, strength of peak correlations between contralateral hip and shoulder joint angle time series, the time shifts at which these peak correlations occur, and associated variability were quantified. Outcomes in individuals with iSCI selecting fast CWSs (range, 1.0-1.3m/s) and speed-matched individuals without neurological injuries are similar. Differences, however, are detected in individuals with iSCI selecting slow CWSs (range, 0.25-0.65 m/s) and may represent compensatory strategies to improve walking balance or forward propulsion. These individuals elicit a 1:1, arm:leg frequency ratio versus the 2:1 ratio observed in non-injured individuals. Shoulder and hip movement patterns, however, are highly reproducible (coordinated) in participants with iSCI, regardless of CWS. This high degree of inter-extremity coordination could reflect an inability to modify a single movement pattern post-iSCI. Combined, these data suggest inter-extremity walking coordination may be altered, but is present after iSCI, and therefore may be regulated, in part, by neural control. Published by Elsevier B.V.}, + number = {1}, + urldate = {2019-07-26}, + journal = {Gait \& Posture}, + author = {Tester, Nicole J and Barbeau, Hugues and Howland, Dena R and Cantrell, Amy and Behrman, Andrea L}, + month = may, + year = {2012}, + pmid = {22341058}, + pmcid = {PMC3362672}, + pages = {49--55} +} + +@article{tester_device_2011, + title = {Device use, locomotor training and the presence of arm swing during treadmill walking after spinal cord injury.}, + volume = {49}, + url = {http://dx.doi.org/10.1038/sc.2010.128}, + doi = {10.1038/sc.2010.128}, + abstract = {STUDY DESIGN: Observational, cross-sectional study from a convenience sample with pretest/posttest data from a sample subset. OBJECTIVES: Determine the presence of walking-related arm swing after spinal cord injury (SCI), its associated factors and whether arm swing may change after locomotor training (LT). SETTING: Malcom Randall VAMC and University of Florida, Gainesville, FL. METHODS: Arm movement was assessed during treadmill stepping, pre-LT, in 30 individuals with motor incomplete SCI (iSCI, American Spinal Injury Association Impairment Scale grade C/D, as defined by the International Standards for Neurological Classifications of SCI, with neurological level of impairment at or below C4). Partial body weight support and manual-trainer assistance were provided, as needed, to achieve stepping and allow arm swing. Arm swing presence was compared on the basis of cervical versus thoracic neurological levels of impairment and device type. Leg and arm strength and walking independence were compared between individuals with and without arm swing. Arm swing was reevaluated post-LT in the 21 out of 30 individuals who underwent LT. RESULTS: Of 30 individuals with iSCI, 12 demonstrated arm swing during treadmill stepping, pre-LT. Arm movement was associated with device type, lower extremity motor scores and walking independence. Among the 21 individuals who received LT, only 5 demonstrated arm swing pre-LT. Of the 16 individuals lacking arm swing pre-LT, 8 integrated arm swing post-LT. CONCLUSION: Devices routinely used for walking post-iSCI appeared associated with arm swing. Post-LT, arm swing presence increased. Therefore, arm swing may be experience dependent. Daily neuromuscular experiences provided to the arms may produce training effects, thereby altering arm swing expression.}, + number = {3}, + urldate = {2019-07-26}, + journal = {Spinal Cord}, + author = {Tester, N J and Howland, D R and Day, K V and Suter, S P and Cantrell, A and Behrman, A L}, + month = mar, + year = {2011}, + pmid = {20938449}, + pmcid = {PMC3021654}, + pages = {451--456} +} + +@article{masocha_assessment_2009, + title = {Assessment of weight bearing changes and pharmacological antinociception in mice with {LPS}-induced monoarthritis using the {Catwalk} gait analysis system.}, + volume = {85}, + url = {http://dx.doi.org/10.1016/j.lfs.2009.07.015}, + doi = {10.1016/j.lfs.2009.07.015}, + abstract = {AIMS: We evaluated the possibility of using the video-based Catwalk gait analysis method to measure weight bearing changes and for testing pharmacological antinociception in freely moving mice with lipopolysaccharide (LPS)-induced monoarthritis. MAIN METHODS: LPS or its solvent (PBS) was injected intra-articularly into the right hind (RH) limb ankle joint through the Achilles tendon of C57BL/6 mice. The Catwalk system was used to assess behavioral changes in freely moving mice. The effects of indomethacin on changes in LPS-inoculated mice were examined. KEY FINDINGS: Mice inoculated with LPS into the RH limb showed reduced paw pressure (measured as light intensity) and print area on the RH limb, whereas they exerted more pressure with the left hind (LH) and front limbs, showing a transfer of weight bearing from RH to LH and front limbs, which was significant at 2 days post-LPS inoculation. There were no differences between the front limbs. No changes were observed in the PBS injected controls. There were no changes in interlimb coordination (regularity index) in both PBS- and LPS-injected mice. Treatment with indomethacin (10 and 100mg/kg) restored the weight bearing (measured as the ratio of the pressure exerted by the paws) and the print area ratios of LPS-inoculated mice similar to that observed in control mice. SIGNIFICANCE: This study shows that the Catwalk gait analysis system can be used to objectively quantify LPS-induced monoarthritis weight bearing changes in all four limbs and evaluate pharmacological antinociception in freely moving mice.}, + number = {11-12}, + urldate = {2019-07-26}, + journal = {Life Sciences}, + author = {Masocha, Willias and Parvathy, Subramanian S}, + month = sep, + year = {2009}, + pmid = {19683012}, + pages = {462--469} +} + +@article{lemieux_speed-dependent_2016, + title = {Speed-{Dependent} {Modulation} of the {Locomotor} {Behavior} in {Adult} {Mice} {Reveals} {Attractor} and {Transitional} {Gaits}.}, + volume = {10}, + url = {http://dx.doi.org/10.3389/fnins.2016.00042}, + doi = {10.3389/fnins.2016.00042}, + abstract = {Locomotion results from an interplay between biomechanical constraints of the muscles attached to the skeleton and the neuronal circuits controlling and coordinating muscle activities. Quadrupeds exhibit a wide range of locomotor gaits. Given our advances in the genetic identification of spinal and supraspinal circuits important to locomotion in the mouse, it is now important to get a better understanding of the full repertoire of gaits in the freely walking mouse. To assess this range, young adult C57BL/6J mice were trained to walk and run on a treadmill at different locomotor speeds. Instead of using the classical paradigm defining gaits according to their footfall pattern, we combined the inter-limb coupling and the duty cycle of the stance phase, thus identifying several types of gaits: lateral walk, trot, out-of-phase walk, rotary gallop, transverse gallop, hop, half-bound, and full-bound. Out-of-phase walk, trot, and full-bound were robust and appeared to function as attractor gaits (i.e., a state to which the network flows and stabilizes) at low, intermediate, and high speeds respectively. In contrast, lateral walk, hop, transverse gallop, rotary gallop, and half-bound were more transient and therefore considered transitional gaits (i.e., a labile state of the network from which it flows to the attractor state). Surprisingly, lateral walk was less frequently observed. Using graph analysis, we demonstrated that transitions between gaits were predictable, not random. In summary, the wild-type mouse exhibits a wider repertoire of locomotor gaits than expected. Future locomotor studies should benefit from this paradigm in assessing transgenic mice or wild-type mice with neurotraumatic injury or neurodegenerative disease affecting gait.}, + urldate = {2019-07-26}, + journal = {Frontiers in Neuroscience}, + author = {Lemieux, Maxime and Josset, Nicolas and Roussel, Marie and Couraud, SĆ©bastien and Bretzner, FrĆ©dĆ©ric}, + month = feb, + year = {2016}, + pmid = {26941592}, + pmcid = {PMC4763020}, + pages = {42} +} + +@article{aragao_automatic_2011, + title = {Automatic system for analysis of locomotor activity in rodentsā€“a reproducibility study.}, + volume = {195}, + url = {http://dx.doi.org/10.1016/j.jneumeth.2010.12.016}, + doi = {10.1016/j.jneumeth.2010.12.016}, + abstract = {Automatic analysis of locomotion in studies of behavior and development is of great importance because it eliminates the subjective influence of evaluators on the study. This study aimed to develop and test the reproducibility of a system for automated analysis of locomotor activity in rats. For this study, 15 male Wistar were evaluated at P8, P14, P17, P21, P30 and P60. A monitoring system was developed that consisted of an open field of 1m in diameter with a black surface, an infrared digital camera and a video capture card. The animals were filmed for 2 min as they moved freely in the field. The images were sent to a computer connected to the camera. Afterwards, the videos were analyzed using software developed using MATLABĀ® (mathematical software). The software was able to recognize the pixels constituting the image and extract the following parameters: distance traveled, average speed, average potency, time immobile, number of stops, time spent in different areas of the field and time immobile/number of stops. All data were exported for further analysis. The system was able to effectively extract the desired parameters. Thus, it was possible to observe developmental changes in the patterns of movement of the animals. We also discuss similarities and differences between this system and previously described systems. {\textbackslash}copyright 2010 Elsevier B.V. All rights reserved.}, + number = {2}, + urldate = {2019-07-26}, + journal = {Journal of Neuroscience Methods}, + author = {AragĆ£o, Raquel da Silva and Rodrigues, Marco AurĆ©lio Benedetti and de Barros, Karla MĆ“nica Ferraz Teixeira and Silva, SebastiĆ£o RogĆ©rio Freitas and Toscano, Ana Elisa and de Souza, Ricardo Emmanuel and ManhĆ£es-de-Castro, Raul}, + month = feb, + year = {2011}, + pmid = {21182870}, + pages = {216--221} +} + +@article{park_method_2014, + title = {A method for generating a mouse model of stroke: evaluation of parameters for blood flow, behavior, and survival [corrected].}, + volume = {23}, + url = {http://dx.doi.org/10.5607/en.2014.23.1.104}, + doi = {10.5607/en.2014.23.1.104}, + abstract = {Stroke is one of the common causes of death and disability. Despite extensive efforts in stroke research, therapeutic options for improving the functional recovery remain limited in clinical practice. Experimental stroke models using genetically modified mice could aid in unraveling the complex pathophysiology triggered by ischemic brain injury. Here, we optimized the procedure for generating mouse stroke model using an intraluminal suture in the middle cerebral artery and verified the blockage of blood flow using indocyanine green coupled with near infra-red radiation. The first week after the ischemic injury was critical for survivability. The survival rate of 11\% in mice without any treatment but increased to 60\% on administering prophylactic antibiotics. During this period, mice showed severe functional impairment but recovered spontaneously starting from the second week onward. Among the various behavioral tests, the pole tests and neurological severity score tests remained reliable up to 4 weeks after ischemia, whereas the rotarod and corner tests became less sensitive for assessing the severity of ischemic injury with time. Further, loss of body weight was also observed for up 4 weeks after ischemia induction. In conclusion, we have developed an improved approach which allows us to investigate the role of the cell death-related genes in the disease progression using genetically modified mice and to evaluate the modes of action of candidate drugs.}, + number = {1}, + urldate = {2019-07-26}, + journal = {Experimental neurobiology}, + author = {Park, Sin-Young and Marasini, Subash and Kim, Geu-Hee and Ku, Taeyun and Choi, Chulhee and Park, Min-Young and Kim, Eun-Hee and Lee, Young-Don and Suh-Kim, Haeyoung and Kim, Sung-Soo}, + month = mar, + year = {2014}, + pmid = {24737945}, + pmcid = {PMC3984953}, + pages = {104--114} +} + +@article{bailoo_precision_2010, + title = {The precision of video and photocell tracking systems and the elimination of tracking errors with infrared backlighting.}, + volume = {188}, + url = {http://dx.doi.org/10.1016/j.jneumeth.2010.01.035}, + doi = {10.1016/j.jneumeth.2010.01.035}, + abstract = {Automated tracking offers a number of advantages over both manual and photocell tracking methodologies, including increased reliability, validity, and flexibility of application. Despite the advantages that video offers, our experience has been that video systems cannot track a mouse consistently when its coat color is in low contrast with the background. Furthermore, the local lab lighting can influence how well results are quantified. To test the effect of lighting, we built devices that provide a known path length for any given trial duration, at a velocity close to the average speed of a mouse in the open-field and the circular water maze. We found that the validity of results from two commercial video tracking systems (ANY-maze and EthoVision XT) depends greatly on the level of contrast and the quality of the lighting. A photocell detection system was immune to lighting problems but yielded a path length that deviated from the true length. Excellent precision was achieved consistently, however, with video tracking using infrared backlighting in both the open field and water maze. A high correlation (r=0.98) between the two software systems was observed when infrared backlighting was used with live mice. Copyright 2010 Elsevier B.V. All rights reserved.}, + number = {1}, + urldate = {2019-07-26}, + journal = {Journal of Neuroscience Methods}, + author = {Bailoo, Jeremy D and Bohlen, Martin O and Wahlsten, Douglas}, + month = apr, + year = {2010}, + pmid = {20138914}, + pmcid = {PMC2847046}, + pages = {45--52} +} + +@article{samson_mousemove:_2015, + title = {{MouseMove}: an open source program for semi-automated analysis of movement and cognitive testing in rodents.}, + volume = {5}, + url = {http://dx.doi.org/10.1038/srep16171}, + doi = {10.1038/srep16171}, + abstract = {The Open Field (OF) test is one of the most commonly used assays for assessing exploratory behaviour and generalised locomotor activity in rodents. Nevertheless, the vast majority of researchers still rely upon costly commercial systems for recording and analysing OF test results. Consequently, our aim was to design a freely available program for analysing the OF test and to provide an accompanying protocol that was minimally invasive, rapid, unbiased, without the need for specialised equipment or training. Similar to commercial systems, we show that our software-called MouseMove-accurately quantifies numerous parameters of movement including travel distance, speed, turning and curvature. To assess its utility, we used MouseMove to quantify unilateral locomotor deficits in mice following the filament-induced middle cerebral artery occlusion model of acute ischemic stroke. MouseMove can also monitor movement within defined regions-of-interest and is therefore suitable for analysing the Novel Object Recognition test and other field-related cognitive tests. To the best of our knowledge, MouseMove is the first open source software capable of providing qualitative and quantitative information on mouse locomotion in a semi-automated and high-throughput fashion, and hence MouseMove represents a sound alternative to commercial movement analysis systems.}, + urldate = {2017-04-10}, + journal = {Scientific reports}, + author = {Samson, Andre L and Ju, Lining and Ah Kim, Hyun and Zhang, Shenpeng R and Lee, Jessica A A and Sturgeon, Sharelle A and Sobey, Christopher G and Jackson, Shaun P and Schoenwaelder, Simone M}, + month = nov, + year = {2015}, + pmid = {26530459}, + pmcid = {PMC4632026}, + pages = {16171} +} + +@book{bishop_pattern_2006, + address = {New York}, + series = {Information {Science} and {Statistics}}, + title = {Pattern {Recognition} and {Machine} {Learning}}, + isbn = {978-0-387-31073-2}, + url = {https://www.springer.com/de/book/9780387310732}, + abstract = {The dramatic growth in practical applications for machine learning over the last ten years has been accompanied by many important developments in the underlying algorithms and techniques. For example, Bayesian methods have grown from a specialist niche to become mainstream, while graphical models have emerged as a general framework for describing and applying probabilistic techniques. The practical applicability of Bayesian methods has been greatly enhanced by the development of a range of approximate inference algorithms such as variational Bayes and expectation propagation, while new models based on kernels have had a significant impact on both algorithms and applications. This completely new textbook reflects these recent developments while providing a comprehensive introduction to the fields of pattern recognition and machine learning. It is aimed at advanced undergraduates or first-year PhD students, as well as researchers and practitioners. No previous knowledge of pattern recognition or machine learning concepts is assumed. Familiarity with multivariate calculus and basic linear algebra is required, and some experience in the use of probabilities would be helpful though not essential as the book includes a self-contained introduction to basic probability theory. The book is suitable for courses on machine learning, statistics, computer science, signal processing, computer vision, data mining, and bioinformatics. Extensive support is provided for course instructors, including more than 400 exercises, graded according to difficulty. Example solutions for a subset of the exercises are available from the book web site, while solutions for the remainder can be obtained by instructors from the publisher. The book is supported by a great deal of additional material, and the reader is encouraged to visit the book web site for the latest information. Christopher M. Bishop is Deputy Director of Microsoft Research Cambridge, and holds a Chair in Computer Science at the University of Edinburgh. He is a Fellow of Darwin College Cambridge, a Fellow of the Royal Academy of Engineering, and a Fellow of the Royal Society of Edinburgh. His previous textbook "Neural Networks for Pattern Recognition" has been widely adopted. Coming soon: *For students, worked solutions to a subset of exercises available on a public web site (for exercises marked "www" in the text) *For instructors, worked solutions to remaining exercises from the Springer web site *Lecture slides to accompany each chapter *Data sets available for download}, + language = {en}, + urldate = {2020-06-28}, + publisher = {Springer-Verlag}, + author = {Bishop, Christopher}, + year = {2006}, +} + +@misc{bosch_engineering_2021, + type = {chapter}, + title = {Engineering {AI} {Systems}: {A} {Research} {Agenda}}, + copyright = {Access limited to members}, + shorttitle = {Engineering {AI} {Systems}}, + url = {www.igi-global.com/chapter/engineering-ai-systems/266130}, + abstract = {Artificial intelligence (AI) and machine learning (ML) are increasingly broadly adopted in industry. However, based on well over a dozen case studies, we have learned that deploying industry-strength, production quality ML models in systems proves to be challenging. Companies experience challenges r...}, + language = {en}, + urldate = {2021-02-02}, + journal = {Artificial Intelligence Paradigms for Smart Cyber-Physical Systems}, + author = {Bosch, Jan and Olsson, Helena Holmstrƶm and Crnkovic, Ivica}, + year = {2021}, + doi = {10.4018/978-1-7998-5101-1.ch001}, + note = {ISBN: 9781799851011 +Pages: 1-19 +Publisher: IGI Global}, +} + +@article{shenk_automated_2020, + title = {Automated {Analysis} of {Stroke} {Mouse} {Trajectory} {Data} {With} {Traja}}, + volume = {14}, + issn = {1662-453X}, + url = {https://www.frontiersin.org/articles/10.3389/fnins.2020.00518/full}, + doi = {10.3389/fnins.2020.00518}, + abstract = {Quantitative characterization of mouse activity, locomotion and walking patterns requires the monitoring of position and activity over long periods of time. Manual behavioral phenotyping, however, is time and skill-intensive, vulnerable to researcher bias and often stressful for the animals. We present examples for using a platform-independent open source trajectory analysis software, Traja, for semi-automated analysis of high throughput mouse home-cage data for neurobehavioral research. Our software quantifies numerous parameters of movement including travelled distance, velocity, turnings, and laterality which are demonstrated for application to neurobehavioral analysis. In this study, the open source software for trajectory analysis Traja is applied to movement and walking pattern observations of transient stroke induced female C57BL/6 mice (30 min middle cerebral artery occlusion) on an acute multinutrient diet intervention (Fortasyn). Mice were housed individually in Digital Ventilated Cages (DVC, GM500, Tecniplast S.p.A., Buguggiate (VA), Italy) and activity was recorded 24/7, every 250 ms using a DVC board. Significant changes in activity, velocity, and distance walked are computed with Traja. Traja identified increased walked distance and velocity in Control and Fortasyn animals over time. No diet effect was found in preference of turning direction (laterality) and distance travelled. As open source software for trajectory analysis, Traja supports independent development and validation of numerical methods and provides a useful tool for computational analysis of 24/7 mouse locomotion in home-cage environment for application in behavioral research or movement disorders.}, + language = {English}, + urldate = {2020-12-21}, + journal = {Frontiers in Neuroscience}, + author = {Shenk, Justin and Lohkamp, Klara J. and Wiesmann, Maximilian and Kiliaan, Amanda J.}, + year = {2020}, + note = {Publisher: Frontiers}, + keywords = {animal tracking, Home-cage, machine learning, Mouse, neuropsychiatric disorders, Stroke}, + file = {Full Text PDF:C\:\\Users\\hpaye\\Zotero\\storage\\IBNLUH9P\\Shenk et al. - 2020 - Automated Analysis of Stroke Mouse Trajectory Data.pdf:application/pdf}, +} + +@misc{shenk_towards_2020, + title = {Towards {Explainable} {AI} with {Feature} {Space} {Exploration}}, + url = {https://towardsdatascience.com/towards-explainable-ai-with-feature-space-exploration-628930baf8ef}, + abstract = {Neural networks trained on large amounts of data have led to incredible technological leaps affecting nearly every part of our lives.}, + language = {en}, + urldate = {2021-02-08}, + journal = {Medium}, + author = {Shenk, Justin}, + month = jun, + year = {2020}, +} + +@book{grus_data_2015, + address = {Beijing}, + title = {Data {Science} from {Scratch}: {First} {Principles} with {Python}}, + isbn = {978-1-4919-0142-7}, + url = {http://my.safaribooksonline.com/97814919-01427}, + abstract = {Data science libraries, frameworks, modules, and toolkits are great for doing data science, but they're also a good way to dive into the discipline without actually understanding data science. In this book, you'll learn how many of the most fundamental data science tools and algorithms work by implementing them from scratch. If you have an aptitude for mathematics and some programming skills, author Joel Grus will help you get comfortable with the math and statistics at the core of data science, and with hacking skills you need to get started as a data scientist.}, + publisher = {O'Reilly}, + author = {Grus, Joel}, + year = {2015}, + keywords = {01624 103 safari book ai software development data pattern recognition analysis python}, +} + +@article{chandra_traphic_2019, + title = {{TraPHic}: {Trajectory} {Prediction} in {Dense} and {Heterogeneous} {Traffic} {Using} {Weighted} {Interactions}}, + url = {http://arxiv.org/abs/1812.04767 https://arxiv.org/abs/1812.04767}, + journal = {arXiv:1812.04767 [cs]}, + author = {Chandra, Rohan and Bhattacharya, Uttaran and Bera, Aniket and Manocha, Dinesh}, + year = {2019}, + doi = {10.1109/cvpr.2019.00868}, + note = {Type: Journal Article}, +} diff --git a/paper/paper.md b/paper/paper.md new file mode 100644 index 00000000..6ecceb6f --- /dev/null +++ b/paper/paper.md @@ -0,0 +1,282 @@ +--- +title: 'Traja: A Python toolbox for animal trajectory analysis' +tags: + - Python + - animal behavior + - trajectory + - multivariate time series + - neuroscience +authors: + - name: Justin Shenk + orcid: 0000-0002-0664-7337 + affiliation: "1, 2" + - name: Wolf Byttner + affiliation: 3 + orcid: 0000-0002-9525-9730 + - name: Saranraj Nambusubramaniyan + affiliation: 1 + orcid: 0000-0002-7314-0261 + - name: Alexander Zoeller + affiliation: 4 + orcid: 0000-0002-4043-3420 +affiliations: + - name: VisioLab, Berlin, Germany + index: 1 + - name: Radboud University, Nijmegen, Netherlands + index: 2 + - name: Rapid Health, London, England, United Kingdom + index: 3 + - name: Independent researcher + index: 4 +date: 4 June 2021 +bibliography: paper.bib +--- + +# Summary +There are generally four categories of trajectory data: mobility of people, mobility of transportation vehicles, mobility of animals, and mobility of natural phenomena [@zheng-trajectory-2015]. Animal tracking is important for fields as diverse as ethology, optimal foraging theory, and neuroscience. Mouse behavior, for example, is a widely studied in biomedical and brain research in models of neurological disease such as stroke.[^1] + +Several tools exist which allow analyzing mouse locomotion. Tools such as Ethovision [@spink_ethovision_2001] and DeepLabCut [@Mathisetal2018] allow converting video data to pose coordinates, which can further be analyzed by other open source tools. DLCAnalyzer[^2] provides a collection of R scripts for analyzing positional data, in particular visualizing, classifying and plotting movement. B-SOiD [@Hsu770271] allows unsupervised clustering of behaviors, extracted from the pose coordinate outputs of DeepLabCut. SimBA [@sgoldenlab_2021_4521178] provides several classifiers and tools for behavioral analysis in video streams in a Windows-based graphical user interface (GUI) application. + +These tools are primarily useful for video data, which is not available for the majority of animal studies. For example, video monitoring of home cage mouse data is impractical today due to housing space constraints. Researchers using Python working with non-visual animal tracking data sources are not able to fully leverage these tools. Thus, a tool that supports modeling in the language of state-of-the-art predictive modelsĀ  [@amirian_social_2019; @liang_peeking_2019; @chandra_traphic_2019], and which provides animal researchers with a high-level API for multivariate time series feature extraction, modeling and visualization is needed. + +Traja is a Python package for statistical analysis and computational modelling of trajectories. Traja extends the familiar pandas [@mckinney-proc-scipy-2010; @reback2020pandas] methods by providing a pandas accessor to the `df.traja` namespace upon import. The API for Traja was designed to provide an object-oriented and user-friendly interface to common methods in analysis and visualization of animal trajectories. Traja also interfaces well with relevant spatial analysis packages in R (e.g., trajr [@mclean_trajr:_2018] and adehabitat [@adehabitat]), Shapely [@shapely], and MovingPandas [@graser_movingpandas_2019] allowing rapid prototyping and comparison of relevant methods in Python. A comprehensive source of documentation is provided on the home page +([http://traja.readthedocs.io](traja.readthedocs.io)). + +## Statement of Need +The data used in this project includes animal trajectory data provided by [http://www.tecniplast.it](Tecniplast S.p.A.), manufacturer of laboratory animal equipment based in Varese, Italy, and Radboud University, Nijmegen, Netherlands. Tecniplast provided the mouse locomotion data collected with their Digital Ventilated Cages (DVC). The extracted coordinates of the mice requires further analysis with external tools. Due to lack of access to equipment, mouse home cage data is rather difficult to collect and analyze, thus few studies have been done on home cage data. Furthermore, researchers who are interested in developing novel algorithms must implement from scratch much of the computational and algorithmic infrastructure for analysis and visualization. By packaging a library that is particularly useful for animal locomotion analysis, future researchers can benefit from access to a high-level interface and clearly documented methods for their work. + +Other toolkits for animal behavioral analysis either rely on visual data [@Mathisetal2018; @vivek_hari_sridhar_2017_1134016] to estimate the pose of animals or are limited to the R programming language [@mclean_trajr:_2018]. Prototyping analytical approaches and exploratory data analysis is furthered by access to a wide range of methods which existing libraries do not provide. Python is the *de facto* language for machine learning and data science programming, thus a toolkit in Python which provides methods for prototyping multivariate time series data analysis and deep neural network modeling is needed. + +## Overview of the Library +Traja targets Python because of its popularity with data scientists. The library leverages the powerful pandas library [@mckinney-proc-scipy-2010], while adding methods specifically for trajectory analysis. When importing Traja, the Traja namespace registers itself within the pandas dataframe namespace via `df.traja`. + +The software is structured into three parts. These provide functionality to transform, analyse and visualize trajectories. Full details are available at . The `trajectory` module provides analytical and preprocessing functionalities. The `models` subpackage provides both traditional and neural network-based tools to determine trajectory properties. The `plotting` module allows visualizing trajectories in various ways. + +Data, e.g., x and y coordinates, are stored as one-dimensional labelled arrays as instances of the pandas native `Series` class. Further, subclassing the pandas `DataFrame` allows providing an API that mirrors the pandas API which is familiar to most data scientists, thus reducing the barrier for entry while providing methods and properties specific to trajectories for rapid prototyping. +Traja depends on Matplotlib [@Hunter:2007] and Seaborn [@Waskom2021] for plotting and NumPy [@harris2020array] for computation. + +### Trajectory Data Sources +Trajectory data as time series can be extracted from a wide range of sources, including video processing tools as described above, GPS sensors for large animals or via home cage floor sensors, as described in the section below. The methods presented here are implemented for orthogonal coordinates *(x, y)* primarily to track animal centroids, however with some modification they could be extended to work in 3-dimensions and with body part locations as inputs. Traja is thus positioned at the end of the data scientist's chain of tools with the hope of supporting prototyping novel data processing approaches. A sample dataset of jaguar movement [@morato_jaguar_2018] is provided in the `traja.dataset` subpackage. + +## Mouse Locomotion Data +The data samples presented here[^3] are in 2-dimensional location coordinates, reflecting the mouse home cage (25x12.5 cm) dimensions. Analytical methods relevant to 2D rectilinear analysis of highly constrained spatial coordinates are thus primarily considered. + +High volume data like animal trajectories has an increased tendency to have missing data due to data collection issues or noise. Filling in the missing data values, referred to as _data imputation_, is achieved with a wide variety of statistical or learning-based methods. As previously observed, data science projects typically require at least _95%_ of the time to be spent on cleaning, pre-processing and managing the data [@bosch_engineering_2021]. Therefore, several methods relevant to preprocessing animal data are demonstrated throughout the following sections. + +[^1]: The examples in this paper focus on animal motion, however it is useful for other domains. + +[^2]: + +[^3]: This dataset has been collected for other studies of our laboratory [@shenk_automated_2020]. + +## Spatial Trajectory +A *spatial trajectory* is a trace generated by a moving object in geographical space. Trajectories are traditionally modelled as a sequence of spatial points like: + +$$T_k = \{P_{k1}, P_{k2},...\}$$ + +where $P_{ki}(i\geq 1)$ is a point in the trajectory. + +Generating spatial trajectory data via a random walk is possible by sampling from a distribution of angles and step sizes [@kareiva_analyzing_1983; @mclean_trajr:_2018]. A correlated random walk (Figure [1](#fig:generated){reference-type="ref" reference="fig:generated"}) is generated with `traja.generate`. + +![Generation of a random walk[]{label="fig:generated"}](./images/generate.png){#fig:generated width=80%} + +## Spatial Transformations +Transformation of trajectories can be useful for comparing trajectories from various geospatial coordinates, data compression, or simply for visualization purposes. + +### Feature Scaling +Feature scaling is common practice for preprocessing data for machine learningĀ [@grus_data_2015] and is essential for even application of methods to attributes. For example, a high dimensional feature vector $\mathbf{x} \in \mathbb{R}^n$ where some attributes are in $(0,100)$ and others are in $(-1,1)$ would lead to biases in the treatment of certain attributes. To limit the dynamic range for multiple data instances simultaneously, scaling is applied to a feature matrix $X = \{\mathbf{x_1}, \mathbf{x_2}, ..., \mathbf{x_N}\} \in \mathbb{R}^{n\times{N}}$, where $n$ is the number of instances. + +**Min-Max Scaling** To guarantee that the algorithm applies equally to all attributes, the normalized feature matrix $\hat{X}$ is rescaled into range $(0,1)$ such that + +$\hat{X} = \frac{X - X_{min}}{X_{max} - X_{min}}$. + +**Standardization** The result of standardization is that the features will be rescaled to have the property of a standard normal distribution with $\mu = 0$ andĀ $\sigma = 1$ where $\mu$ is the mean (average) of the data and $\sigma$ is the standard deviation from the mean. Standard scores (also known as **z**-scores are calculated such that + +$z = \frac{x-\mu}{\sigma}$. + +**Scaling** Scaling a trajectory is implemented for factor $f$ in `scale` where $f \in R: f \in (-\infty, +\infty)$. + +### Rotation +Rotation of a 2D rectilinear trajectory is a coordinate transformation of orthonormal bases x and y at angle $\theta$ (in radians) around the origin defined by + +$$\begin{bmatrix} x'\\y' \end{bmatrix} = \begin{bmatrix} cos\theta & i sin\theta\\ sin\theta & cos\theta \end{bmatrix} \begin{bmatrix} x\\y \end{bmatrix} $$ + +with angle $\theta$ where $\theta \in R : \theta \in [-180,180]$. + +### Trip Grid +One strategy for compressing the representation of trajectories is binning the coordinates to produce an image as shown in Figure [2](#fig:tripgridalgo){reference-type="ref" reference="fig:tripgridalgo"}. + +![Trip grid image generation from mouse +trajectory.](./images/trip_grid_algo.png){#fig:tripgridalgo width=100%} + +Allowing computation on discrete variables rather than continuous ones has several advantages stemming from the ability to store trajectories in a more memory efficient form.[^4] The advantage is that computation is generally faster, more data can fit in memory in the case of complex models, and item noise can be reduced. + +[^4]: In this experiment, for example, data can be reduced from single-precision floating point (32 bits) to 8-bit unsigned integer (*uint8*) format. + +Creation of an $M * N$ grid allows mapping trajectory $T_k$ onto uniform +grid cells. Generalizing the nomenclature of [@wang_modeling_2017] to rectangular grids, $C_{mn}(1\leq{m}\leq M; 1\leq{n}\leq{N})$ denotes the cell in row $m$ and column $n$ of the grid. Each point $P_{ki}$ is assigned to a cell $C(m,n)$. The result is a two-dimensional image $M*N$ image $I_k$, where the value of pixel $I_k(m,n)(1\leq{m,n}\leq{M})$ indicates the relative number of points assigned to cell $C_{mn}$. Partionining of spatial position into separate grid cells is often followed by generation of hidden Markov models [@jeung_mining_2007] (see below) or visualization of heat maps (Figure [3](#fig:heatmap){reference-type="ref" reference="fig:heatmap"}). + +![Visualization of heat map from bins generated with `df.trip_grid`. Note regularly spaced artifacts (bright yellow) in this sample due to a bias in the sensor data interpolation. This type of noise can be minimized by thresholding or using a logarithmic scale, as shown above.[]{label="fig:heatmap"}](./images/tripgrid.png){#fig:heatmap width=50%} + +### Smoothing +Smoothing a trajectory can also be achieved with Traja using Savitzky-Golay filtering with `smooth_sg` [@savitzky_smoothing_1964]. + +## Resampling and Rediscretizing +Trajectories can be resampled by time or rediscretized by an arbitrary step length. This can be useful for aligning trajectories from various data sources and sampling rates or reducing the number of data points to improve computational efficiency. Care must be taken to select a time interval which maintains information on the significant behavior. If the minimal time interval observed is selected for the points, calculations will be computationally intractable for some systems. If too large of an interval is selected, we will fail to capture changes relevant to the target behavior in the data. + +Resampling by time is performed with `resample_time` (Figure [4](#fig:sample){reference-type="ref" reference="fig:sample"}). Rediscretizing by step length is performed with `rediscretize`. + +![Resampling trajectories by different time scales is performed with `resample_time`.[]{label="fig:sample"}](./images/sample_rate.png){#fig:step width=80%} + +For example, the Fortasyn dataset [@shenk_automated_2020] demonstrated in this paper was sampled at 4 Hz and converted to single-precision floating point data. Pandas dataframes store this data in 4 bytes, thus there are approximately 4.15 MB[^5] bytes required to store data for x and y dimensions plus an index reference for a single day. In the case of [@shenk_automated_2020], 24 mice were observed over 35 days. This translates to 3.4 GB ($10^9$) of storage capacity for the uncompressed datasets prior to feature engineering. Thus resampling can be a useful way to reduce the memory footprint for memory constrained processes that have to fit into a standard laptop with 8 GB memory space. A demonstration of how reduction in precision for trajectory data analysis is provided in FigureĀ [4](#fig:step){reference-type="ref" reference="fig:step"}, as applied to a sample from the Fortasyn experiment [@shenk_automated_2020]. Broad effects such as cage crossings, for example, can still be identified while downsampling data to a lower frequency, such as 0.1 Hz, reducing the memory footprint by a factor of 40 (4 Hz/0.1 Hz) and providing significant speedups for processing. + +## Movement Analysis +Traja includes traditional as well as advanced methods for trajectory analysis. + +### Distance traveled +Distance traveled is a common metric in animal studies - it accounts for the total distance covered by the animal within a given time interval. The distance traveled is typically quantified by summing the square straight-line displacement between discretely sampled trajectories [@rowcliffe_bias_2012; @solla_eliminating_1999]. Alternative distance metrics for the case of animal tracking are discussed in [@noonan_scale-insensitive_2019]. + +Let $p(t) = [p_x(t), p_y(t)]$ be a $2\times 1$ vector of coordinates on the ground representing the position of the animal at time t. Then, the distance traveled within the time interval $t_1$ and $t_2$ can be computed as a sum of step-wise Euclidean distances + +$$p(t_1,t_2) = \Sigma^{t_2}_{t=t_1+1} d(t),$$ + +where +$$d(t) = \sqrt{(p_x(t) -p_x(t-1))^2 + (p_y(t) - p_y(t-1))^2} $$ + +is the Euclidean distance between two positions in adjacent time samples. + +[^5]: 4 x 4 Hz x 60 seconds x 60 minutes x 24 hours x 3 features (x, y, and time) + +![Velocity histogram from one day of mouse activity.[]{label="fig:velocity-hist"}](./images/velocitylog.png){#fig:velocity-hist width=50%} + +### Speed +Speed or velocity is the first derivative of centroids with respect to time. Peak velocity in a home cage environment is perhaps less interesting than a distribution of velocity observations, as in Figure [5](#fig:velocity-hist){reference-type="ref" reference="fig:velocity-hist"}. Additionally, noise can be eliminated from velocity calculations by using a minimal distance moved threshold, as demonstrated in [@shenk_automated_2020]. This allows identifying broad-scale behaviors such as cage crossings. + +### Turn Angles +Turn angles are the angle between the movement vectors of two consecutive samples. They can be calculated with `calc_turn_angles`. + +### Laterality +Laterality is the preference for left or right turning and a *laterality index* is defined as: +$$LI = \frac{RT}{LT + RT} $$ + +where RT is the number of right turns observed and LT is the number of left turns observed. Turns are counted within a left turn angle $\in$ ($\theta$, 90) and right turn angle $\in(-\theta,-90)$. A turn is considered to have a minimal step length. + +## Periodicity +Periodic behaviors are a consequence of the circadian rhythm as well as observing expression of underlying cognitive traits. Some basic implementations of periodic analysis of mouse cage data are presented. + +### Autocorrelation +Autocorrelation is the correlation of a signal with a delayed copy of itself as a function of the decay. Basically, it is similarity of observations as a function of the time lag between them. +An example is shown in Figure [6](#fig:autocorrelation){reference-type="ref" reference="fig:autocorrelation"}. + +![Autocorrelation of the y-dimension reveals daily (1440 minutes) periodic behavior[]{label="fig:autocorrelation"}](./images/autocorrelation_E1.png){#fig:autocorrelation width=80%} + +### Power Spectrum +Power spectrum of a time series signal can be estimated (Figure [7](#fig:powerspectrum){reference-type="ref" reference="fig:powerspectrum"}). This is useful for analyzing signals, for example, the influence of neuromotor noise on delays in hand movement [@van_galen_effects_1990]. + +![Power Spectral Density. One day of activity reveals fairly smooth power spectral density.[]{label="fig:powerspectrum"}](./images/spectrum.png){#fig:powerspectrum width=70%} + +## Algorithms and Statistical Models + +### Machine Learning for Time Series Data +Machine learning methods enable researchers to solve tasks computationally without explicit instructions by detecting patterns or relying on inference. Thus they are particularly relevant for data exploration of high volume datasets such as spatial trajectories and other multivariate time series. + +### Principal Component Analysis +Principal Component Analysis projects the data into a linear subspace with a minimum loss of information by multiplying the data by the eigenvectors of the covariance matrix. + +![PCA of Fortasyn trajectory data. Daily trajectories (day and night) +were binned into 8x8 grids before applying +PCA.[]{label="fig:pca"}](./images/pca_fortasyn-period.png){#fig:pca +width=80%} + +This requires converting the trajectory to a trip grid (see Figure [2(#fig:tripgridalgo){reference-type="ref" reference="fig:tripgridalgo"}]) and performing PCA on the grid in 2D (Figure [8](#fig:pca){reference-type="ref" reference="fig:pca"}) or 3D (Figure [9](#fig:3dpca){reference-type="ref" reference="fig:3dpca"}). Structure in the data is visible if light and dark time periods are compared. + +![3D PCA of Fortasyn trajectory data. Daily trajectories (day and night) +were binned into 8x8 grids before applying +PCA.[]{label="fig:3dpca"}](./images/pca_fortasyn-period-3d.png){#fig:3dpca +width=80%} + +### Clustering +Clustering of trajectories is an extensive topic with applications in geospatial data, vehicle and pedestrian classification, as well as molecular identification. K-means clustering is an iterative unsupervised learning method that assigns a label to data points based on a distance function [@bishop_pattern_2006] (Figure [10](#fig:kmeans){reference-type="ref" reference="fig:3dpca"}). + +![K-means clustering on the results of the PCA shown above reveals a high accuracy +of classification, with a few errors. Cluster labels are generated by +the model.[]{label="fig:kmeans"}](./images/kmeans_pca-fortasyn.png){#fig:kmeans +width=80%} + +### Hierarchical Agglomerative Clustering +Clustering spatial trajectories has broad applications for behavioral research, including unsupervised phenotyping [@huang_mapping_2020]. For mice, hierarchical agglomerative clustering can also be used to identify similarities between groups, for example periodic activity and location visit frequency [@clustering_mice]. + +### Gaussian Processes +Gaussian Processes is a non-parametric method which can be used to model spatial trajectories. This method is not currently implemented in Traja +and is thus outside the scope of the current paper, however the interested reader is directed to the excellent text on Gaussian processes by Rasmussen and Williams [@rasmussen_gaussian_2006] for a complete reference and [@cox_gaussian_2012] for an application to spatial trajectories. + +## Other Methods + +### Fractal Methods +Fractal (i.e. multiscale) methods are useful for analyzing transitions and clustering in trajectories. For example, search trajectories such as eye movement, hand-eye coordination, and foraging can be analyzed by quantifying the spatial distribution or nesting of temporal point processes using spatial Allen Factor analysis [@kerster_spatial_2016; @huette_drawing_2013]. + +Recurrence plots and derivative recurrence factor analysis can be applied to trajectories to identify multiscale temporal processes to study transition or nonlinear parameters in a system, such as postural fluctuation [@ross_influence_2016] and synchrony [@shockley] in humans and to movement of animals such as ants [@neves_recurrence_2017] and bees [@ayers]. These methods are not yet implemented in Traja, but are planned for a future release. + +### Graph Models +A graph is a pair $G = (V, E)$ comprising a set of vertices and a set of connecting edges. A probabilistic graphical model of a spatial occupancy grid can be used to identify probabilities of state transitions between nodes. A basic example is given with hidden Markov models below. + +![Transition matrix. Rows and columns are flattened histogram of a grid +20 cells high and 10 cells wide. Spatially adjacent grid cells are +visible at a spacing of -11, -10, -9, 1, 10, and 11 cells from the +diagonal. The intensity of pixels in the diagonal represents relative +likelihood to stay in the same +position.[]{label="fig:transitionmatrix"}](./images/transition_matrix.png){#fig:transitionmatrix +width=60%} + +### Hidden Markov Models +Transition probabilities are most commonly modelled with Hidden Markov Models (HMM) because of their ability to capture spatial and temporal dependencies. A recent introduction to these methods is available provided by [@patterson_statistical_2017]. HMMs have successfully been used to analyze movement of caribou [@franke_analysis_2004], fruit flies [@holzmann_hidden_2006], and tuna [@patterson_migration_2018], among others. Trajectories are typically modelled as bivariate time series consisting of step length and turn angle, regularly spaced in time. + +Traja implements the rectangular spatial grid version of HMM with transitions. + +The probability of transition from each cell to another cell is stored as a probability within the transition matrix. This can visualized as a heatmap and plotted with `plot_transition_matrix` (Figure [11](#fig:transitionmatrix){reference-type="ref" reference="fig:transitionmatrix"}). + +### Convex Hull +The convex hull of a subtrajectory is the set $X$ of points in the Euclidean plane that is the smallest convex set to include $X$. For computational efficiency, a geometric k-simplex can be plotted covering the convex hull by converting to a Shapely object and using Shapelyā€™s `convex_hull` method. + +### Recurrent Neural Networks +In recent years, deep learning has transformed the field of machine learning. For example, the current state of the art models for a wide range of tasks, including computer vision, speech to text, and pedestrian trajectory prediction, are achieved with deep neural networks. Neural networks are essentially sequences of matrix operations and elementwise function application based on a collection of computing units known as nodes or neurons. These units perform operations, such as matrix multiplication on input features of a dataset, followed by backpropagation of errors, to identify parameters useful for approximating a function. + +![Neural network architectures available in Traja](./images/dnns.jpg){width=100%} + +Recurrent Neural Networks (RNNs) are a special type of Neural Networks that use +a state $S(t_{i-1})$ from the previous timestep $t_{i-1}$ alongside X($t_i$) as input. They output a prediction $Y(t_i)$ and a new state $S(t_i)$ at every step. Utilising previous states makes RNNs particularly good at analyzing time series like trajectories, since they can process arbitrarily long inputs. They remember information from previous time steps $X(t_{i-k}), ..., X(t_{i-1})$ when processing the current time step $X(t_i)$. + +Trajectory prediction lets researchers forecast the location and trajectory of animals [@wijeyakulasuriya_machine_2020]. Where this technique works well, it is also a sign that the trajectory is highly regular and, fundamentally, follows certain rules and patterns. When tracking an animal live, it would also let researchers predict when it will arrive at a particular location, or where it will go, letting them rig cameras and other equipment ahead of time. + +A particularly interesting type of RNN is the Long Short Term Memory (LSTM) architecture. Their layers use stacks of units, each with two hidden variables - one that quickly discards old states and one that slowly does so - to consider relevant information from previous time steps. They can thus look at a trajectory and determine a property of the animal ā€“ whether it is sick or injured, say ā€“ something that is time-consuming and difficult to do by hand. They can also predict future time steps based on past ones, letting researchers estimate where the animal will go next. LSTMs can also classify trajectories, determining whether a trajectory comes from an animal belonging in a specific category. This lets researchers determine how a controlled or semi-controlled variable (e.g., pregnancy) changes the movement pattern of an animal. + +Traja implements neural networks by extending the widely used open source machine learning library PyTorch [@pytorch], primarily developed by Facebook AI Research Group. Traja allows framework-agnostic modeling through data loaders designed for time series. In addition, the Traja package comes with several predefined model architectures which can be configured according to the userā€™s requirements. + +Because RNNs work with time series, the trajectories require special handling. The `traja.dataset.MultiModalDataLoader` efficiently groups subsequent samples and into series and splits these series into training and test data. It represents a Python iterable over the dataset and extends the PyTorch `DataLoader` class, with support for + +- random, weighted sampling, +- data scaling, +- data shuffling, +- train/validation/test split. + +`MultiModalDataLoader` accepts several important configuration parameters and +allows batched sampling of the data. The two constructor arguments `n_past` and +`n_future` specify the number of samples that the network will be shown and the number that the network will have to guess, respectively. `batch_size` is generally in the dozens and is used to regularise the network. + +The RNNs also need to be trained - this is done by the high-level `Trainer` class below. It performs nonlinear optimisation with a Stochastic Gradient Descent-like algorithm. The `Trainer` class by default implements the Huber loss function [@huber_robust_1964], also known as smooth $L_1$ loss, which is a loss function commonly used in robust regression: + +$$L_{\delta} (a) = \begin{cases} + \frac{1}{2}{a^2} & \text{for } |a| \le \delta, \\ + \delta (|a| - \frac{1}{2}\delta), & \text{otherwise.} +\end{cases}$$ + +In comparison to mean-squared error loss, Huber loss is less sensitive to outliers in data: it is quadratic for small values of a, and linear for large values. It extends the PyTorch `SmoothL1Loss` class, where the $d$ parameter is set to 1.[^6] A common optimization algorithm is ADAM and is Trajaā€™s default, but several others are provided as well. Although training with only a CPU is possible, a GPU can provide a $40-100x$ speedup [@Arpteg2018SoftwareEC]. + +[^6]: [https://pytorch.org/docs/stable/generated/torch.nn.SmoothL1Loss.html](https://pytorch.org/docs/stable/generated/torch.nn.SmoothL1Loss.html) + +### Recurrent Autoencoder Networks +Traja can also train autoencoders to either predict the future position of a track or classify the track into a number of categories. Autoencoders embed the time series into a time-invariant latent space, allowing representation of each trajectory or sub-trajectory as a vector. A class of well-separated trajectories would then be restricted to a region of the latent space. The technique is similar to Word2vec [@word2vec], where words are converted to a 100+ dimensional vector. In this approach, forecasting and classification are both preceded by training the data in an autoencoder, which learns an efficient representation of the data for further computation of the target function. + +Traja allows training a classifier that works directly on the latent space output - since each class of trajectories converges to a distinct region in the latent space, this technique is often superior to classifying the trajectory itself. Traja trains classifiers for both Autoencoder-style and Variational Autoencoder-style RNNs. When investigating whether animal behavior has changed, or whether two experimental categories of animals behave differently, this unstructured data mining can suggest fruitful avenues for investigation. + +# References diff --git a/paper/paper.pdf b/paper/paper.pdf new file mode 100644 index 00000000..6de0cdc7 Binary files /dev/null and b/paper/paper.pdf differ diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..8a0cb37d --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,21 @@ +[tool.black] +line-length = 88 +py36 = true +include = '\.pyi?$' +exclude = ''' + +( + /( + \.eggs # exclude a few common directories in the + | \.git # root of the project + | \.hg + | \.mypy_cache + | \.tox + | \.venv + | _build + | buck-out + | build + | dist + )/ +) +''' \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..5e4ea833 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,11 @@ +pandas>=1.2.0 +numpy==1.22.0 +matplotlib +shapely +scipy>=1.4.1 +fastdtw +networkx +seaborn +torch +statsmodels +scikit-learn \ No newline at end of file diff --git a/requirements/dev.txt b/requirements/dev.txt new file mode 100644 index 00000000..3ab33d81 --- /dev/null +++ b/requirements/dev.txt @@ -0,0 +1,5 @@ +# install all mandatory dependencies +-r ../requirements.txt + +# install all extra dependencies for full package testing +-r ./extra.txt diff --git a/requirements/docs.txt b/requirements/docs.txt new file mode 100644 index 00000000..07611519 --- /dev/null +++ b/requirements/docs.txt @@ -0,0 +1,17 @@ +pandas>=1.2.0 +numpy==1.22.0 +matplotlib +shapely +scipy +scikit-learn +sphinx +sphinx-gallery +sphinx_rtd_theme +fastdtw +networkx +seaborn +torch +pytest +pytest-cov +codecov +ipython diff --git a/requirements/extra.txt b/requirements/extra.txt new file mode 100644 index 00000000..9193415a --- /dev/null +++ b/requirements/extra.txt @@ -0,0 +1,16 @@ +# extended list of package dependencies to reach full functionality + +pytest +h5py +ipython +pre-commit +shapely +scipy>=1.4.1 +scikit-learn +fastdtw +networkx +seaborn +torch +h5py +numba>=0.50.0 +pyDOE2>=1.3.0 \ No newline at end of file diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 00000000..674af40a --- /dev/null +++ b/setup.cfg @@ -0,0 +1,16 @@ +[bumpversion] +current_version = 0.2.0 + +[yapf] +column_limit = 120 + +[tool:pytest] +log_cli = True +log_level = INFO +filterwarnings = + ignore::DeprecationWarning + ignore::FutureWarning + +[metadata] +license_file = LICENSE + diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..62edd5da --- /dev/null +++ b/setup.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from setuptools import setup, find_packages + +import os +import re + +here = os.path.abspath(os.path.dirname(__file__)) + + +def read(*parts): + with open(os.path.join(here, *parts), "r", encoding="utf8") as fp: + return fp.read() + + +# Get package version +def find_version(*file_paths): + version_file = read(*file_paths) + version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", version_file, re.M) + if version_match: + return version_match.group(1) + raise RuntimeError("Unable to find version string.") + + +requirements = ["matplotlib", "pandas", "numpy", "shapely", "scipy", "tzlocal"] + +extras_requirements = {"all": ["torch", "tzlocal", "fastdtw"]} + +with open(os.path.join(here, "README.rst"), encoding="utf-8") as f: + long_description = f.read() + +setup( + name="traja", + version=find_version("traja", "__init__.py"), + description="Traja is a trajectory analysis and visualization tool", + url="https://github.com/traja-team/traja", + author="Justin Shenk", + author_email="shenkjustin@gmail.com", + long_description=long_description, + long_description_content_type="text/x-rst", + install_requires=requirements, + extras_require=extras_requirements, + classifiers=[ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Intended Audience :: Education", + "Intended Audience :: Science/Research", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Topic :: Scientific/Engineering :: Mathematics", + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: Software Development :: Libraries", + ], + python_requires=">= 3.6", + project_urls={ + "Bug Tracker": "https://github.com/traja-team/traja/issues", + "Documentation": "https://traja.rtfd.io/en/latest/", + "Source Code": "https://github.com/traja-team/traja", + }, + packages=find_packages(exclude=["*tests.*", "*tests"]), + include_package_data=True, + license="MIT", + keywords="trajectory analysis", + zip_safe=False, +) diff --git a/traja-gui.py b/traja-gui.py new file mode 100644 index 00000000..c0c0b62d --- /dev/null +++ b/traja-gui.py @@ -0,0 +1,315 @@ +import os +from os.path import basename +from functools import partial +import sys + +import matplotlib + +matplotlib.use("Qt5Agg") +import pandas as pd +import matplotlib.pyplot as plt + +plt.ioff() + +import matplotlib.style as style +import matplotlib.backends.backend_qt5agg.FigureCanvasQTAgg as FigureCanvas +from matplotlib.backends.backend_qt5agg import ( + FigureCanvasQTAgg as FigureCanvas, + NavigationToolbar2QT as NavigationToolbar, +) +from PyQt5 import QtGui, QtWidgets, QtCore +from PyQt5.QtCore import Qt, QThread, QObject, pyqtSignal, pyqtSlot +from PyQt5.QtWidgets import QProgressBar, QMenu, QAction, QStatusBar + +import traja + +CUR_STYLE = "fast" +style.use(CUR_STYLE) +TIME_WINDOW = "30s" + + +class QtFileLoader(QObject): + finished = pyqtSignal() + progressMaximum = pyqtSignal(int) + completed = pyqtSignal(list) + intReady = pyqtSignal(int) + + def __init__(self, filepath): + super(QtFileLoader, self).__init__() + self.filepath = filepath + + @pyqtSlot() + def read_in_chunks(self): + """ load dataset in parts and update the progess par """ + chunksize = 10 ** 3 + lines_number = sum(1 for line in open(self.filepath)) + self.progressMaximum.emit(lines_number // chunksize) + dfList = [] + + # self.df = traja.read_file( + # str(filepath), + # index_col="time_stamps_vec", + # parse_dates=["time_stamps_vec"], + # ) + + TextFileReader = pd.read_csv( + self.filepath, + index_col="time_stamps_vec", + parse_dates=["time_stamps_vec"], + chunksize=chunksize, + ) + for idx, df in enumerate(TextFileReader): + df.index = pd.to_datetime(df.index, format="%Y-%m-%d %H:%M:%S:%f") + dfList.append(df) + self.intReady.emit(idx) + self.completed.emit(dfList) + self.finished.emit() + + +class PlottingWidget(QtWidgets.QMainWindow): + def __init__(self): + super().__init__() + # super(PrettyWidget, self).__init__() + self.initUI() + + def initUI(self): + self.setGeometry(600, 300, 1000, 600) + self.center() + self.setWindowTitle("Plot Trajectory") + + mainMenu = self.menuBar() + fileMenu = mainMenu.addMenu("File") + + saveAction = QAction("Save as...") + saveAction.setShortcut("Ctrl+S") + saveAction.setStatusTip("Save plot to file") + saveAction.setMenuRole(QAction.NoRole) + saveAction.triggered.connect(self.file_save) + fileMenu.addAction(saveAction) + + exitAction = QAction("&Exit", self) + exitAction.setShortcut("Ctrl+Q") + exitAction.setStatusTip("Exit Application") + exitAction.setMenuRole(QAction.NoRole) + exitAction.triggered.connect(self.close) + fileMenu.addAction(exitAction) + + settingsMenu = mainMenu.addMenu("Settings") + self.setStyleMenu = QMenu("Set Style", self) + settingsMenu.addMenu(self.setStyleMenu) + for style_name in ["default", "fast", "ggplot", "grayscale", "seaborn"]: + styleAction = QAction(style_name, self, checkable=True) + if style_name is CUR_STYLE: + styleAction.setChecked(True) + styleAction.triggered.connect(partial(self.set_style, style_name)) + self.setStyleMenu.addAction(styleAction) + self.setTimeWindowMenu = QMenu("Set Time Window", self) + settingsMenu.addMenu(self.setTimeWindowMenu) + for window_str in ["None", "s", "30s", "H", "D"]: + windowAction = QAction(window_str, self, checkable=True) + if window_str is TIME_WINDOW: + windowAction.setChecked(True) + windowAction.triggered.connect(partial(self.set_time_window, window_str)) + self.setTimeWindowMenu.addAction(windowAction) + + # Grid Layout + grid = QtWidgets.QGridLayout() + widget = QtWidgets.QWidget(self) + self.setCentralWidget(widget) + widget.setLayout(grid) + + # Import CSV Button + btn1 = QtWidgets.QPushButton("Import CSV", self) + btn1.resize(btn1.sizeHint()) + btn1.clicked.connect(self.getCSV) + grid.addWidget(btn1, 1, 0) + + # Canvas and Toolbar + self.figure = plt.figure(figsize=(15, 5)) + self.canvas = FigureCanvas(self.figure) + self.canvas.setContextMenuPolicy(Qt.CustomContextMenu) + self.canvas.customContextMenuRequested.connect(self.popup) + grid.addWidget(self.canvas, 2, 0, 1, 2) + + # DropDown mean / comboBox + self.df = pd.DataFrame() + self.columns = [] + self.plot_list = [] + + self.comboBox = QtWidgets.QComboBox(self) + self.comboBox.addItems(self.columns) + grid.addWidget(self.comboBox, 0, 0) + + self.comboBox2 = QtWidgets.QComboBox(self) + self.comboBox2.addItems(self.plot_list) + grid.addWidget(self.comboBox2, 0, 1) + + # Plot Button + btn2 = QtWidgets.QPushButton("Plot", self) + btn2.resize(btn2.sizeHint()) + btn2.clicked.connect(self.plot) + grid.addWidget(btn2, 1, 1) + + # Progress bar + self.progress = QProgressBar(self) + # self.progress.setRange(0, 1) + grid.addWidget(self.progress, 3, 0, 1, 2) + + self.statusBar = QStatusBar() + self.setStatusBar(self.statusBar) + self.show() + + def set_style(self, style_name: str): + global CUR_STYLE + self.statusBar.showMessage(f"Style set to {style_name}") + actions = self.setStyleMenu.actions() + CUR_STYLE = style_name + for action in actions: + if action.text() == CUR_STYLE: + # print(f"āœ“ {CUR_STYLE}") + action.setChecked(True) + else: + action.setChecked(False) + print(f"Style set to {CUR_STYLE}") + + def popup(self, pos): + menu = QMenu() + saveAction = menu.addAction("Save...") + action = menu.exec_(self.canvas.viewport().mapToGlobal(pos)) + if action == saveAction: + self.file_save() + + def file_save(self, target="figure"): + name = QtGui.QFileDialog.getSaveFileName(self, "Save File") + if target == "figure": + self.figure.savefig(name) + + def update_progress_bar(self, i: int): + self.progress.setValue(i) + max = self.progress.maximum() + self.statusBar.showMessage(f"Loading ... {100*i/max:.0f}%") + + def set_progress_bar_max(self, max: int): + self.progress.setMaximum(max) + + def clear_progress_bar(self): + self.progress.hide() + self.statusBar.showMessage("Completed.") + + def getCSV(self): + self.statusBar.showMessage("Loading CSV...") + filepath, _ = QtWidgets.QFileDialog.getOpenFileName( + self, "Open CSV", (QtCore.QDir.homePath()), "CSV (*.csv *.tsv)" + ) + + if filepath != "": + self.filepath = filepath + self.loaderThread = QThread() + self.loaderWorker = QtFileLoader(filepath) + self.loaderWorker.moveToThread(self.loaderThread) + self.loaderThread.started.connect(self.loaderWorker.read_in_chunks) + self.loaderWorker.intReady.connect(self.update_progress_bar) + self.loaderWorker.progressMaximum.connect(self.set_progress_bar_max) + # self.loaderWorker.read_in_chunks.connect(self.df) + self.loaderWorker.completed.connect(self.list_to_df) + self.loaderWorker.completed.connect(self.clear_progress_bar) + self.loaderThread.finished.connect(self.loaderThread.quit) + self.loaderThread.start() + + @pyqtSlot(list) + def list_to_df(self, dfs: list): + df = pd.concat(dfs) + self.df = df + self.columns = self.df.columns.tolist() + self.plot_list = ["Actogram", "Polar Bar", "Polar Histogram", "Trajectory"] + self.comboBox.clear() + self.comboBox.addItems(self.columns) + self.comboBox2.clear() + self.comboBox2.addItems(self.plot_list) + self.statusBar.clearMessage() + + def mousePressEvent(self, QMouseEvent): + if QMouseEvent.button() == Qt.RightButton: + + print("Right Button Clicked") + + def load_project_structure(self, startpath, tree): + """ + Load Project structure tree + :param startpath: + :param tree: + :return: + """ + from PyQt5.QtWidgets import QTreeWidgetItem + from PyQt5.QtGui import QIcon + + for element in os.listdir(startpath): + path_info = startpath + "/" + element + parent_itm = QTreeWidgetItem(tree, [os.path.basename(element)]) + if os.path.isdir(path_info): + self.load_project_structure(path_info, parent_itm) + parent_itm.setIcon(0, QIcon("assets/folder.ico")) + else: + parent_itm.setIcon(0, QIcon("assets/file.ico")) + + def set_time_window(self, window: str): + global TIME_WINDOW + TIME_WINDOW = window + self.statusBar.showMessage(f"Time window set to {window}") + actions = self.setTimeWindowMenu.actions() + for action in actions: + if action.text() == TIME_WINDOW: + action.setChecked(True) + else: + action.setChecked(False) + print(f"Time window set to {window}") + + def plot(self): + plt.clf() + + plot_kind = self.comboBox2.currentText() + self.statusBar.showMessage(f"Plotting {plot_kind}") + projection = ( + "polar" if plot_kind in ["Polar Bar", "Polar Histogram"] else "rectilinear" + ) + + ax = self.figure.add_subplot(111, projection=projection) + + title = f"{basename(self.filepath)}" + + # TODO: Move mapping to separate method + if plot_kind == "Actogram": + displacement = traja.trajectory.calc_displacement(self.df) + if TIME_WINDOW != "None": + displacement = displacement.rolling(TIME_WINDOW).mean() + # from pyqtgraph.Qt import QtGui, QtCore + traja.plotting.plot_actogram(displacement, ax=ax, interactive=False) + elif plot_kind == "Trajectory": + traja.plotting.plot(self.df, ax=ax, interactive=False) + elif plot_kind == "Quiver": + traja.plotting.plot_quiver(self.df, ax=ax, interactive=False) + elif plot_kind == "Polar Bar": + traja.plotting.polar_bar(self.df, ax=ax, title=title, interactive=False) + elif plot_kind == "Polar Histogram": + traja.plotting.polar_bar( + self.df, ax=ax, title=title, overlap=False, interactive=False + ) + plt.tight_layout() + self.canvas.draw() + self.statusBar.clearMessage() + + def center(self): + qr = self.frameGeometry() + cp = QtWidgets.QDesktopWidget().availableGeometry().center() + qr.moveCenter(cp) + self.move(qr.topLeft()) + + +def main(): + app = QtWidgets.QApplication(sys.argv) + w = PlottingWidget() + sys.exit(app.exec_()) + + +if __name__ == "__main__": + main() diff --git a/traja/__init__.py b/traja/__init__.py new file mode 100644 index 00000000..90fa0d51 --- /dev/null +++ b/traja/__init__.py @@ -0,0 +1,18 @@ +import logging + +from traja import dataset +from traja import models +from .accessor import TrajaAccessor +from .frame import TrajaDataFrame, TrajaCollection +from .parsers import read_file, from_df +from .plotting import * +from .trajectory import * + +__author__ = "justinshenk" +__version__ = "22.0.0" + +logging.basicConfig(level=logging.INFO) + + +def set_traja_axes(axes: list): + TrajaAccessor._set_axes(axes) diff --git a/traja/accessor.py b/traja/accessor.py new file mode 100644 index 00000000..96255d9a --- /dev/null +++ b/traja/accessor.py @@ -0,0 +1,532 @@ +from typing import Union + +import pandas as pd +from pandas.api.types import is_datetime64_any_dtype + +import traja + + +@pd.api.extensions.register_dataframe_accessor("traja") +class TrajaAccessor(object): + """Accessor for pandas DataFrame with trajectory-specific numerical and analytical functions. + + Access with `df.traja`.""" + + def __init__(self, pandas_obj): + self._validate(pandas_obj) + self._obj = pandas_obj + + __axes = ["x", "y"] + + @staticmethod + def _set_axes(axes): + if len(axes) != 2: + raise ValueError( + "TrajaAccessor requires precisely two axes, got {}".format(len(axes)) + ) + TrajaAccessor.__axes = axes + + def _strip(self, text): + try: + return text.strip() + except AttributeError: + return pd.to_numeric(text, errors="coerce") + + @staticmethod + def _validate(obj): + if ( + TrajaAccessor.__axes[0] not in obj.columns + or TrajaAccessor.__axes[1] not in obj.columns + ): + raise AttributeError( + "Must have '{}' and '{}'.".format(*TrajaAccessor.__axes) + ) + + @property + def center(self): + """Return the center point of this trajectory.""" + x = self._obj.x + y = self._obj.y + return float(x.mean()), float(y.mean()) + + @property + def bounds(self): + """Return limits of x and y dimensions (``(xmin, xmax), (ymin, ymax)``).""" + xlim = self._obj.x.min(), self._obj.x.max() + ylim = self._obj.y.min(), self._obj.y.max() + return (xlim, ylim) + + def night(self, begin: str = "19:00", end: str = "7:00"): + """Get nighttime dataset between `begin` and `end`. + + Args: + begin (str): (Default value = '19:00') + end (str): (Default value = '7:00') + + Returns: + trj (:class:`~traja.frame.TrajaDataFrame`): Trajectory during night. + + """ + return self.between(begin, end) + + def day(self, begin: str = "7:00", end: str = "19:00"): + """Get daytime dataset between `begin` and `end`. + + Args: + begin (str): (Default value = '7:00') + end (str): (Default value = '19:00') + + Returns: + trj (:class:`~traja.frame.TrajaDataFrame`): Trajectory during day. + + """ + return self.between(begin, end) + + def _get_time_col(self): + """Returns time column in trajectory. + + Args: + + Returns: + time_col (str or None): name of time column, 'index' or None + + """ + return traja.trajectory._get_time_col(self._obj) + + def between(self, begin: str, end: str): + """Returns trajectory between `begin` and end` if `time` column is `datetime64`. + + Args: + begin (str): Beginning of time slice. + end (str): End of time slice. + + Returns: + trj (:class:`~traja.frame.TrajaDataFrame`): Dataframe between values. + + .. doctest :: + + >>> s = pd.to_datetime(pd.Series(['Jun 30 2000 12:00:01', 'Jun 30 2000 12:00:02', 'Jun 30 2000 12:00:03'])) + >>> df = traja.TrajaDataFrame({'x':[0,1,2],'y':[1,2,3],'time':s}) + >>> df.traja.between('12:00:00','12:00:01') + time x y + 0 2000-06-30 12:00:01 0 1 + + """ + time_col = self._get_time_col() + if time_col == "index": + return self._obj.between_time(begin, end) + elif time_col and is_datetime64_any_dtype(self._obj[time_col]): + # Backup index + dt_index_col = self._obj.index.name + # Set dt_index + trj = self._obj.copy() + trj.set_index(time_col, inplace=True) + # Create slice of trajectory + trj = trj.between_time(begin, end) + # Restore index and return column + if dt_index_col: + trj.set_index(dt_index_col, inplace=True) + else: + trj.reset_index(inplace=True) + return trj + else: + raise TypeError("Either time column or index must be datetime64") + + def resample_time(self, step_time: float): + """Returns trajectory resampled with ``step_time``. + + Args: + step_time (float): Step time + + Returns: + trj (:class:`~traja.frame.TrajaDataFrame`): Dataframe resampled. + """ + return traja.trajectory.resample_time(self._obj, step_time=step_time) + + def rediscretize_points(self, R, **kwargs): + """Rediscretize points""" + return traja.trajectory.rediscretize_points(self._obj, R=R, **kwargs) + + def trip_grid( + self, + bins: Union[int, tuple] = 10, + log: bool = False, + spatial_units=None, + normalize: bool = False, + hist_only: bool = False, + plot: bool = True, + **kwargs, + ): + """Returns a 2D histogram of trip. + + Args: + bins (int, optional): Number of bins (Default value = 16) + log (bool): log scale histogram (Default value = False) + spatial_units (str): units for plotting + normalize (bool): normalize histogram into density plot + hist_only (bool): return histogram without plotting + + Returns: + hist (:class:`numpy.ndarray`): 2D histogram as array + image (:class:`matplotlib.collections.PathCollection`: image of histogram + + """ + hist, image = traja.plotting.trip_grid( + self._obj, + bins=bins, + log=log, + spatial_units=self._obj.get("spatial_units", "m"), + normalize=normalize, + hist_only=hist_only, + plot=plot, + **kwargs, + ) + return hist, image + + def plot(self, n_coords: int = None, show_time=False, **kwargs): + """Plot trajectory over period. + + Args: + n_coords (int): Number of coordinates to plot + **kwargs: additional keyword arguments to :meth:`matplotlib.axes.Axes.scatter` + + Returns: + ax (:class:`~matplotlib.axes.Axes`): Axes of plot + """ + ax = traja.plotting.plot( + trj=self._obj, + accessor=self, + n_coords=n_coords, + show_time=show_time, + **kwargs, + ) + return ax + + def plot_3d(self, **kwargs): + """Plot 3D trajectory for single identity over period. + + Args: + trj (:class:`traja.TrajaDataFrame`): trajectory + n_coords (int, optional): Number of coordinates to plot + **kwargs: additional keyword arguments to :meth:`matplotlib.axes.Axes.scatter` + + Returns: + collection (:class:`~matplotlib.collections.PathCollection`): collection that was plotted + + .. note:: + Takes a while to plot large trajectories. Consider using first:: + + rt = trj.traja.rediscretize(R=1.) # Replace R with appropriate step length + rt.traja.plot_3d() + + """ + ax = traja.plotting.plot_3d(trj=self._obj, **kwargs) + return ax + + def plot_flow(self, kind="quiver", **kwargs): + """Plot grid cell flow. + + Args: + kind (str): Kind of plot (eg, 'quiver','surface','contour','contourf','stream') + **kwargs: additional keyword arguments to :meth:`matplotlib.axes.Axes.scatter` + + Returns: + ax (:class:`~matplotlib.axes.Axes`): Axes of plot + + """ + ax = traja.plotting.plot_flow(trj=self._obj, kind=kind, **kwargs) + return ax + + def plot_collection(self, colors=None, **kwargs): + return traja.plotting.plot_collection( + self._obj, id_col=self._id_col, colors=colors, **kwargs + ) + + def apply_all(self, method, id_col=None, **kwargs): + """Applies method to all trajectories and returns grouped dataframes or series""" + id_col = id_col or getattr(self, "_id_col", "id") + return self._obj.groupby(by=id_col).apply(method, **kwargs) + + def _has_cols(self, cols: list): + return traja.trajectory._has_cols(self._obj, cols) + + @property + def xy(self): + """Returns a :class:`numpy.ndarray` of x,y coordinates. + + Args: + split (bool): Split into seaprate x and y :class:`numpy.ndarrays` + + Returns: + xy (:class:`numpy.ndarray`) -- x,y coordinates (separate if `split` is `True`) + + .. doctest:: + + >>> df = traja.TrajaDataFrame({'x':[0,1,2],'y':[1,2,3]}) + >>> df.traja.xy + array([[0, 1], + [1, 2], + [2, 3]]) + + """ + if self._has_cols(["x", "y"]): + xy = self._obj[["x", "y"]].values + return xy + else: + raise Exception("'x' and 'y' are not in the dataframe.") + + def _check_has_time(self): + """Check for presence of displacement time column.""" + time_col = self._get_time_col() + if time_col is None: + raise Exception("Missing time information in trajectory.") + + def __getattr__(self, name): + """Catch all method calls which are not defined and forward to modules.""" + + def method(*args, **kwargs): + if name in traja.plotting.__all__: + return getattr(traja.plotting, name)(self._obj, *args, **kwargs) + elif name in traja.trajectory.__all__: + return getattr(traja.plotting, name)(self._obj, *args, **kwargs) + elif name in dir(self): + return getattr(self, name)(*args)(**kwargs) + else: + raise AttributeError(f"{name} attribute not defined") + + return method + + def transitions(self, *args, **kwargs): + """Calculate transition matrix""" + return traja.transitions(self._obj, *args, **kwargs) + + def calc_derivatives(self, assign: bool = False): + """Returns derivatives `displacement` and `displacement_time`. + + Args: + assign (bool): Assign output to ``TrajaDataFrame`` (Default value = False) + + Returns: + derivs (:class:`~collections.OrderedDict`): Derivatives. + + .. doctest:: + + >>> df = traja.TrajaDataFrame({'x':[0,1,2],'y':[1,2,3],'time':[0., 0.2, 0.4]}) + >>> df.traja.calc_derivatives() + displacement displacement_time + 0 NaN 0.0 + 1 1.414214 0.2 + 2 1.414214 0.4 + + + """ + derivs = traja.trajectory.calc_derivatives(self._obj) + if assign: + trj = self._obj.merge(derivs, left_index=True, right_index=True) + self._obj = trj + return derivs + + def get_derivatives(self) -> pd.DataFrame: + """Returns derivatives as DataFrame.""" + derivs = traja.trajectory.get_derivatives(self._obj) + return derivs + + def speed_intervals( + self, + faster_than: Union[float, int] = None, + slower_than: Union[float, int] = None, + ): + """Returns ``TrajaDataFrame`` with speed time intervals. + + Returns a dataframe of time intervals where speed is slower and/or faster than specified values. + + Args: + faster_than (float, optional): Minimum speed threshold. (Default value = None) + slower_than (float or int, optional): Maximum speed threshold. (Default value = None) + + Returns: + result (:class:`~pandas.DataFrame`) -- time intervals as dataframe + + .. note:: + + Implementation ported to Python, heavily inspired by Jim McLean's trajr package. + + """ + result = traja.trajectory.speed_intervals(self._obj, faster_than, slower_than) + return result + + def to_shapely(self): + """Returns shapely object for area, bounds, etc. functions. + + Args: + + Returns: + shape (shapely.geometry.linestring.LineString): Shapely shape. + + .. doctest:: + + >>> df = traja.TrajaDataFrame({'x':[0,1,2],'y':[1,2,3]}) + >>> shape = df.traja.to_shapely() + >>> shape.is_closed + False + + """ + trj = self._obj[["x", "y"]].dropna() + tracks_shape = traja.trajectory.to_shapely(trj) + return tracks_shape + + def calc_displacement(self, assign: bool = True) -> pd.Series: + """Returns ``Series`` of `float` with displacement between consecutive indices. + + Args: + assign (bool, optional): Assign displacement to TrajaAccessor (Default value = True) + + Returns: + displacement (:class:`pandas.Series`): Displacement series. + + .. doctest:: + + >>> df = traja.TrajaDataFrame({'x':[0,1,2],'y':[1,2,3]}) + >>> df.traja.calc_displacement() + 0 NaN + 1 1.414214 + 2 1.414214 + Name: displacement, dtype: float64 + + """ + displacement = traja.trajectory.calc_displacement(self._obj) + if assign: + self._obj = self._obj.assign(displacement=displacement) + return displacement + + def calc_angle(self, assign: bool = True) -> pd.Series: + """Returns ``Series`` with angle between steps as a function of displacement with regard to x axis. + + Args: + assign (bool, optional): Assign turn angle to TrajaAccessor (Default value = True) + + Returns: + angle (:class:`pandas.Series`): Angle series. + + .. doctest:: + + >>> df = traja.TrajaDataFrame({'x':[0,1,2],'y':[1,2,3]}) + >>> df.traja.calc_angle() + 0 NaN + 1 45.0 + 2 45.0 + dtype: float64 + + """ + angle = traja.trajectory.calc_angle(self._obj) + if assign: + self._obj["angle"] = angle + return angle + + def scale(self, scale: float, spatial_units: str = "m"): + """Scale trajectory when converting, eg, from pixels to meters. + + Args: + scale(float): Scale to convert coordinates + spatial_units(str., optional): Spatial units (eg, 'm') (Default value = "m") + + .. doctest:: + + >>> df = traja.TrajaDataFrame({'x':[0,1,2],'y':[1,2,3]}) + >>> df.traja.scale(0.1) + >>> df + x y + 0 0.0 0.1 + 1 0.1 0.2 + 2 0.2 0.3 + + """ + self._obj[["x", "y"]] *= scale + self._obj.__dict__["spatial_units"] = spatial_units + + def _transfer_metavars(self, df): + for attr in self._obj._metadata: + df.__dict__[attr] = getattr(self._obj, attr, None) + return df + + def rediscretize(self, R: float): + """Resample a trajectory to a constant step length. R is rediscretized step length. + + Args: + R (float): Rediscretized step length (eg, 0.02) + + Returns: + rt (:class:`traja.TrajaDataFrame`): rediscretized trajectory + + .. note:: + + Based on the appendix in Bovet and Benhamou, (1988) and Jim McLean's + `trajr `_ implementation. + + .. doctest:: + + >>> df = traja.TrajaDataFrame({'x':[0,1,2],'y':[1,2,3]}) + >>> df.traja.rediscretize(1.) + x y + 0 0.000000 1.000000 + 1 0.707107 1.707107 + 2 1.414214 2.414214 + + """ + if not isinstance(R, (int, float)): + raise ValueError(f"R must be provided as float or int") + rt = traja.trajectory.rediscretize_points(self._obj, R) + self._transfer_metavars(rt) + return rt + + def grid_coordinates(self, **kwargs): + return traja.grid_coordinates(self._obj, **kwargs) + + def calc_heading(self, assign: bool = True): + """Calculate trajectory heading. + + Args: + assign (bool): (Default value = True) + + Returns: + heading (:class:`pandas.Series`): heading as a ``Series`` + + ..doctest:: + + >>> df = traja.TrajaDataFrame({'x':[0,1,2],'y':[1,2,3]}) + >>> df.traja.calc_heading() + 0 NaN + 1 45.0 + 2 45.0 + Name: heading, dtype: float64 + + """ + heading = traja.trajectory.calc_heading(self._obj) + if assign: + self._obj["heading"] = heading + return heading + + def calc_turn_angle(self, assign: bool = True): + """Calculate turn angle. + + Args: + assign (bool): (Default value = True) + + Returns: + turn_angle (:class:`~pandas.Series`): Turn angle + + .. doctest:: + + >>> df = traja.TrajaDataFrame({'x':[0,1,2],'y':[1,2,3]}) + >>> df.traja.calc_turn_angle() + 0 NaN + 1 NaN + 2 0.0 + Name: turn_angle, dtype: float64 + + """ + turn_angle = traja.trajectory.calc_turn_angle(self._obj) + + if assign: + self._obj["turn_angle"] = turn_angle + return turn_angle diff --git a/traja/contrib/__init__.py b/traja/contrib/__init__.py new file mode 100644 index 00000000..30f7adc8 --- /dev/null +++ b/traja/contrib/__init__.py @@ -0,0 +1 @@ +from traja.contrib.rdp import rdp diff --git a/traja/contrib/rdp.py b/traja/contrib/rdp.py new file mode 100644 index 00000000..e00c4179 --- /dev/null +++ b/traja/contrib/rdp.py @@ -0,0 +1,199 @@ +""" +rdp +~~~ +Python implementation of the Ramer-Douglas-Peucker algorithm. +:copyright: 2014-2016 Fabian Hirschmann +:license: MIT. + +Copyright (c) 2014 Fabian Hirschmann . +With minor modifictions by Justin Shenk (c) 2019. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +""" +from functools import partial +from typing import Union, Callable + +import numpy as np + + +def pldist(point: np.ndarray, start: np.ndarray, end: np.ndarray): + """ + Calculates the distance from ``point`` to the line given + by the points ``start`` and ``end``. + :param point: a point + :type point: numpy array + :param start: a point of the line + :type start: numpy array + :param end: another point of the line + :type end: numpy array + """ + if np.all(np.equal(start, end)): + return np.linalg.norm(point - start) + + return np.divide( + np.abs(np.linalg.norm(np.cross(end - start, start - point))), + np.linalg.norm(end - start), + ) + + +def rdp_rec(M, epsilon, dist=pldist): + """ + Simplifies a given array of points. + Recursive version. + :param M: an array + :type M: numpy array + :param epsilon: epsilon in the rdp algorithm + :type epsilon: float + :param dist: distance function + :type dist: function with signature ``f(point, start, end)`` -- see :func:`rdp.pldist` + """ + dmax = 0.0 + index = -1 + + for i in range(1, M.shape[0]): + d = dist(M[i], M[0], M[-1]) + + if d > dmax: + index = i + dmax = d + + if dmax > epsilon: + r1 = rdp_rec(M[: index + 1], epsilon, dist) + r2 = rdp_rec(M[index:], epsilon, dist) + + return np.vstack((r1[:-1], r2)) + else: + return np.vstack((M[0], M[-1])) + + +def _rdp_iter(M, start_index, last_index, epsilon, dist=pldist): + stk = [] + stk.append([start_index, last_index]) + global_start_index = start_index + indices = np.ones(last_index - start_index + 1, dtype=bool) + + while stk: + start_index, last_index = stk.pop() + + dmax = 0.0 + index = start_index + + for i in range(index + 1, last_index): + if indices[i - global_start_index]: + d = dist(M[i], M[start_index], M[last_index]) + if d > dmax: + index = i + dmax = d + + if dmax > epsilon: + stk.append([start_index, index]) + stk.append([index, last_index]) + else: + for i in range(start_index + 1, last_index): + indices[i - global_start_index] = False + + return indices + + +def rdp_iter( + M: Union[list, np.ndarray], + epsilon: float, + dist: Callable = pldist, + return_mask: bool = False, +): + """ + Simplifies a given array of points. + Iterative version. + :param M: an array + :type M: numpy array + :param epsilon: epsilon in the rdp algorithm + :type epsilon: float + :param dist: distance function + :type dist: function with signature ``f(point, start, end)`` -- see :func:`rdp.pldist` + :param return_mask: return the mask of points to keep instead + :type return_mask: bool + + .. note:: + Yanked from Fabian Hirschmann's PyPI package ``rdp``. + + """ + mask = _rdp_iter(M, 0, len(M) - 1, epsilon, dist) + + if return_mask: + return mask + + return M[mask] + + +def rdp( + M: Union[list, np.ndarray], + epsilon: float = 0, + dist: Callable = pldist, + algo: str = "iter", + return_mask: bool = False, +): + """ + Simplifies a given array of points using the Ramer-Douglas-Peucker + algorithm. + Example: + >>> from traja.contrib import rdp + >>> rdp([[1, 1], [2, 2], [3, 3], [4, 4]]) + [[1, 1], [4, 4]] + This is a convenience wrapper around both :func:`rdp.rdp_iter` + and :func:`rdp.rdp_rec` that detects if the input is a numpy array + in order to adapt the output accordingly. This means that + when it is called using a Python list as argument, a Python + list is returned, and in case of an invocation using a numpy + array, a NumPy array is returned. + The parameter ``return_mask=True`` can be used in conjunction + with ``algo="iter"`` to return only the mask of points to keep. Example: + >>> from traja.contrib import rdp + >>> import numpy as np + >>> arr = np.array([1, 1, 2, 2, 3, 3, 4, 4]).reshape(4, 2) + >>> arr + array([[1, 1], + [2, 2], + [3, 3], + [4, 4]]) + >>> mask = rdp(arr, algo="iter", return_mask=True) + >>> mask + array([ True, False, False, True], dtype=bool) + >>> arr[mask] + array([[1, 1], + [4, 4]]) + :param M: a series of points + :type M: numpy array with shape ``(n,d)`` where ``n`` is the number of points and ``d`` their dimension + :param epsilon: epsilon in the rdp algorithm + :type epsilon: float + :param dist: distance function + :type dist: function with signature ``f(point, start, end)`` -- see :func:`rdp.pldist` + :param algo: either ``iter`` for an iterative algorithm or ``rec`` for a recursive algorithm + :type algo: string + :param return_mask: return mask instead of simplified array + :type return_mask: bool + + .. note:: + Yanked from Fabian Hirschmann's PyPI package ``rdp``. + + """ + + if algo == "iter": + algo = partial(rdp_iter, return_mask=return_mask) + elif algo == "rec": + if return_mask: + raise NotImplementedError('return_mask=True not supported with algo="rec"') + algo = rdp_rec + + if "numpy" in str(type(M)): + return algo(M, epsilon, dist) + + return algo(np.array(M), epsilon, dist).tolist() diff --git a/traja/dataset/__init__.py b/traja/dataset/__init__.py new file mode 100644 index 00000000..0feb17b9 --- /dev/null +++ b/traja/dataset/__init__.py @@ -0,0 +1,3 @@ +from . import example +from .dataset import TimeSeriesDataset, MultiModalDataLoader +from .pedestrian import load_ped_data, ped_datasets diff --git a/traja/dataset/dataset.py b/traja/dataset/dataset.py new file mode 100644 index 00000000..3a8e1413 --- /dev/null +++ b/traja/dataset/dataset.py @@ -0,0 +1,432 @@ +""" +Modified from https://github.com/agrimgupta92/sgan/blob/master/sgan/data/trajectories.py. + +This module contains: + +Classes: +1. Pytorch Time series dataset class instance +2. Weighted train and test dataset loader with respect to class distribution + +Helpers: +1. Class distribution in the dataset + +""" +import logging +import math +from collections import defaultdict + +import numpy as np +import pandas as pd +import sklearn +import torch +from sklearn.base import TransformerMixin +from sklearn.preprocessing import MinMaxScaler +from torch.utils.data import Dataset +from torch.utils.data.sampler import SubsetRandomSampler, WeightedRandomSampler + +from traja.dataset import generator +from traja.dataset.generator import get_indices_from_sequence_ids + +logger = logging.getLogger(__name__) + + +class TimeSeriesDataset(Dataset): + r"""Pytorch Dataset object + + Args: + Dataset (torch.utils.data.Dataset): Pyptorch dataset object + """ + + def __init__( + self, + data, + target, + sequence_ids=None, + parameters=None, + classes=None, + scaler: TransformerMixin = None, + ): + r""" + Args: + data (array): Data + target (array): Target + sequence_ids (array): Sequence ID + parameters (array): Parameters + classes (array): Sequence classes + scaler (sklearn.base.TransformerMixin) + """ + + self.data = data + self.target = target + self.sequence_ids = sequence_ids + self.parameters = parameters + self.classes = classes + self.scaler = scaler + + def __getitem__(self, index): + data = self.data[index] + target = self.target[index] + ids = self.sequence_ids[index] if self.sequence_ids else torch.zeros(1) + parameters = self.parameters[index] if self.parameters else torch.zeros(1) + classes = self.classes[index] if self.classes else torch.zeros(1) + + if self.scaler is not None: + data = torch.tensor(self.scaler.transform(data)) + target = torch.tensor(self.scaler.transform(target)) + return data, target, ids, parameters, classes + + def __len__(self): + return len(self.data) + + +class MultiModalDataLoader: + """ + MultiModalDataLoader wraps the following data preparation steps, + + 1. Data generator: Extract x and y time series and corresponding ID (sequence_id) in the dataset. This process split the dataset into + i) Train samples with sequence length equals n_past + ii) Target samples with sequence length equals n_future + iii) Target sequence_id(ID) of both train and target data + 2. Data scalling: Scale the train and target data columns between the range (-1,1) using MinMaxScalers; TODO: It is more optimal to scale data for each ID(sequence_id) + 3. Data shuffling: Shuffle the order of samples in the dataset without loosing the train<->target<->sequence_id combination + 4. Create train test split: Split the shuffled batches into train (data, target, sequence_id) and test(data, target, sequence_id) + 5. Weighted Random sampling: Apply weights with respect to sequence_id counts in the dataset: category_sample_weight = 1/num_category_samples; This avoid model overfit to sequence_id appear often in the dataset + 6. Create pytorch Dataset instances + 7. Returns the train and test data loader instances along with their scalers as a dictionaries given the dataset instances and batch size + + Args: + df (pd.DataFrame): Dataset + batch_size (int): Number of samples per batch of data + n_past (int): Input sequence length. Number of time steps from the past. + n_future (int): Target sequence length. Number of time steps to the future. + num_workers (int): Number of cpu subprocess occupied during data loading process + train_split_ratio (float):Should be between 0.0 and 1.0 and represent the proportion of the dataset-validation_dataset + to include in the train split. + validation_split_ratio (float): Should be between 0.0 and 1.0 and represent the proportion of the dataset + to include in the validation split. + stride: Size of the sliding window. Defaults to sequence_length + split_by_id (bool): Whether to split data based on the sequence's ID (default) or split each sequence + length-wise. + scale (bool): If True, scale the input and target and return the corresponding scalers in a dict. + parameter_columns (list): Columns in data frame with regression parameters. + weighted_sampling (bool): Whether to weigh the likelihood of picking each sample by the sequence length. + This balances the accuracy if trajectories have different lengths. + + Usage: + ------ + dataloaders, scalers = MultiModalDataLoader(df = data_frame, batch_size=32, n_past = 20, n_future = 10, num_workers=4) + """ + + def __init__( + self, + df: pd.DataFrame, + batch_size: int, + n_past: int, + n_future: int, + num_workers: int = 1, + train_split_ratio: float = 0.4, + validation_split_ratio: float = 0.2, + stride: int = None, + split_by_id: bool = True, + scale: bool = True, + test: bool = True, + parameter_columns: list = [], + weighted_sampling: bool = False, + ): + self.df = df + self.batch_size = batch_size + self.n_past = n_past + self.n_future = n_future + self.num_workers = num_workers + self.test = test + self.train_split_ratio = train_split_ratio + self.validation_split_ratio = validation_split_ratio + self.split_by_id = split_by_id + self.scale = scale + self.stride = stride + + # Train and test data from df-val_df + ( + train_data, + target_data, + target_ids, + target_parameters, + target_classes, + samples_in_sequence_id, + ) = generator.generate_dataset( + self.df, + self.n_past, + self.n_future, + stride=self.stride, + parameter_columns=parameter_columns, + ) + + if self.scale: + scaler = MinMaxScaler(feature_range=(-1, 1)) + scaler.fit(np.vstack(train_data + target_data)) + else: + scaler = None + + # Dataset + dataset = TimeSeriesDataset( + train_data, + target_data, + target_ids, + target_parameters, + target_classes, + scaler=scaler, + ) + + # We initialise sample weights in case we need them to weigh samples. + train_weights = defaultdict(float) + test_weights = defaultdict(float) + validation_weights = defaultdict(float) + + if self.split_by_id: + ids = list(set(target_ids)) + np.random.shuffle(ids) + + train_split_index = round(train_split_ratio * len(ids)) + validation_split_index = round((1 - validation_split_ratio) * len(ids)) + + train_ids = np.sort(ids[:train_split_index]) + test_ids = np.sort(ids[train_split_index:validation_split_index]) + validation_ids = np.sort(ids[validation_split_index:]) + + train_indices, train_weights = get_indices_from_sequence_ids( + train_ids, samples_in_sequence_id + ) + test_indices, test_weights = get_indices_from_sequence_ids( + test_ids, samples_in_sequence_id + ) + validation_indices, validation_weights = get_indices_from_sequence_ids( + validation_ids, samples_in_sequence_id + ) + + else: # Do not sample by sequence ID + if stride is None: + stride = n_past + n_future + + sequence_length = n_past + n_future + train_indices = list() + test_indices = list() + validation_indices = list() + id_start_index = 0 + for sequence_index, sequence_count in enumerate(samples_in_sequence_id): + overlap = math.ceil(sequence_length / stride) + + start_test_index = round(sequence_count * train_split_ratio) + end_train_index = start_test_index - overlap + + start_validation_index = round( + sequence_count * (1 - validation_split_ratio) + ) + end_test_index = start_validation_index - overlap + + train_indices.extend( + list(range(id_start_index, id_start_index + end_train_index)) + ) + test_indices.extend( + list( + range( + id_start_index + start_test_index, + id_start_index + end_test_index, + ) + ) + ) + validation_indices.extend( + list( + range( + id_start_index + start_validation_index, + id_start_index + sequence_count, + ) + ) + ) + + train_weights[sequence_index] = ( + 1.0 / end_train_index if end_train_index > 0 else 0 + ) + test_weights[sequence_index] = ( + 1.0 / (end_test_index - start_test_index) + if (end_test_index - start_test_index) > 0 + else 0 + ) + validation_weights[sequence_index] = ( + 1.0 / (sequence_count - start_validation_index) + if (sequence_count - start_validation_index) > 0 + else 0 + ) + + id_start_index += sequence_count + + sequential_train_dataset = torch.utils.data.Subset( + dataset, np.sort(train_indices[:]) + ) + sequential_test_dataset = torch.utils.data.Subset( + dataset, np.sort(test_indices[:]) + ) + sequential_validation_dataset = torch.utils.data.Subset( + dataset, np.sort(validation_indices[:]) + ) + + if weighted_sampling: + train_index_weights = list() + test_index_weights = list() + validation_index_weights = list() + + for ( + data, + target, + sequence_id, + parameters, + classes, + ) in sequential_train_dataset: + train_index_weights.append(train_weights[sequence_id]) + for ( + data, + target, + sequence_id, + parameters, + classes, + ) in sequential_test_dataset: + test_index_weights.append(test_weights[sequence_id]) + for ( + data, + target, + sequence_id, + parameters, + classes, + ) in sequential_validation_dataset: + validation_index_weights.append(validation_weights[sequence_id]) + + train_dataset = sequential_train_dataset + test_dataset = sequential_test_dataset + validation_dataset = sequential_validation_dataset + + train_sampler = WeightedRandomSampler( + weights=train_index_weights, + num_samples=len(train_index_weights), + replacement=True, + ) + test_sampler = WeightedRandomSampler( + weights=test_index_weights, + num_samples=len(test_index_weights), + replacement=True, + ) + validation_sampler = WeightedRandomSampler( + weights=validation_index_weights, + num_samples=len(validation_index_weights), + replacement=True, + ) + + else: + train_dataset = dataset + test_dataset = dataset + validation_dataset = dataset + + np.random.shuffle(train_indices) + np.random.shuffle(test_indices) + np.random.shuffle(validation_indices) + + train_sampler = SubsetRandomSampler(train_indices) + test_sampler = SubsetRandomSampler(test_indices) + validation_sampler = SubsetRandomSampler(validation_indices) + + # Dataloader + self.train_loader = torch.utils.data.DataLoader( + dataset=train_dataset, + shuffle=False, + batch_size=self.batch_size, + sampler=train_sampler, + drop_last=True, + num_workers=num_workers, + ) + self.test_loader = torch.utils.data.DataLoader( + dataset=test_dataset, + shuffle=False, + batch_size=self.batch_size, + sampler=test_sampler, + drop_last=True, + num_workers=num_workers, + ) + self.validation_loader = torch.utils.data.DataLoader( + dataset=validation_dataset, + shuffle=False, + batch_size=self.batch_size, + sampler=validation_sampler, + drop_last=True, + num_workers=num_workers, + ) + self.sequential_loader = torch.utils.data.DataLoader( + dataset=dataset, + shuffle=False, + batch_size=self.batch_size, + drop_last=True, + num_workers=num_workers, + ) + self.sequential_train_loader = torch.utils.data.DataLoader( + dataset=sequential_train_dataset, + shuffle=False, + batch_size=self.batch_size, + drop_last=True, + num_workers=num_workers, + ) + self.sequential_test_loader = torch.utils.data.DataLoader( + dataset=sequential_test_dataset, + shuffle=False, + batch_size=self.batch_size, + drop_last=True, + num_workers=num_workers, + ) + self.sequential_validation_loader = torch.utils.data.DataLoader( + dataset=sequential_validation_dataset, + shuffle=False, + batch_size=self.batch_size, + drop_last=True, + num_workers=num_workers, + ) + + self.dataloaders = { + "train_loader": self.train_loader, + "test_loader": self.test_loader, + "validation_loader": self.validation_loader, + "sequential_loader": self.sequential_loader, + "sequential_train_loader": self.sequential_train_loader, + "sequential_test_loader": self.sequential_test_loader, + "sequential_validation_loader": self.sequential_validation_loader, + } + + def __new__( + cls, + df: pd.DataFrame, + batch_size: int, + n_past: int, + n_future: int, + num_workers: int, + split_by_id: bool = True, + stride: int = None, + train_split_ratio: float = 0.4, + validation_split_ratio: float = 0.2, + scale: bool = True, + parameter_columns: list = list(), + weighted_sampling: bool = False, + ): + """Constructor of MultiModalDataLoader""" + # Loader instance + loader_instance = super(MultiModalDataLoader, cls).__new__(cls) + loader_instance.__init__( + df, + batch_size, + n_past, + n_future, + num_workers, + train_split_ratio=train_split_ratio, + validation_split_ratio=validation_split_ratio, + split_by_id=split_by_id, + stride=stride, + scale=scale, + parameter_columns=parameter_columns, + weighted_sampling=weighted_sampling, + ) + # Return train and test loader attributes + return loader_instance.dataloaders diff --git a/traja/dataset/example.py b/traja/dataset/example.py new file mode 100644 index 00000000..32ad890e --- /dev/null +++ b/traja/dataset/example.py @@ -0,0 +1,10 @@ +import pandas as pd + +default_cache_url = "dataset_cache" + + +def jaguar(cache_url=default_cache_url): + # Sample data + data_url = "https://raw.githubusercontent.com/traja-team/traja-research/dataset_und_notebooks/dataset_analysis/jaguar5.csv" + df = pd.read_csv(data_url, error_bad_lines=False) + return df diff --git a/traja/dataset/generator.py b/traja/dataset/generator.py new file mode 100644 index 00000000..8509057c --- /dev/null +++ b/traja/dataset/generator.py @@ -0,0 +1,133 @@ +import logging +from collections import defaultdict + +import numpy as np + +logger = logging.getLogger(__name__) + + +def generate_dataset( + df, n_past: int, n_future: int, stride: int = None, parameter_columns: list = list() +): + """ + df : Dataframe + n_past: Number of past observations + n_future: Number of future observations + stride: Size of the sliding window. Defaults to sequence_length + Returns: + X: Past steps + Y: Future steps (Sequence target) + Z: Sequence ID""" + + # Split the dataframe with respect to IDs + sequence_ids = dict( + tuple(df.groupby("ID")) + ) # Dict of ids as keys and x,y,id as values + + train_data, target_data, target_category, target_parameters, target_classes = ( + list(), + list(), + list(), + list(), + list(), + ) + + if stride is None: + stride = n_past + n_future + + assert n_past >= 1, "n_past has to be positive!" + assert n_future >= 1, "n_past has to be positive!" + assert stride >= 1, "Stride has to be positive!" + + samples_in_sequence_id = list() + + class_column = ["class"] if "class" in df.columns else [] + if not class_column: + target_classes = None + + for ID in sequence_ids.keys(): + xx, yy, zz, ww, cc = list(), list(), list(), list(), list() + # Drop the column ids and convert the pandas into arrays + data_columns = [ + column + for column in df.columns + if column not in parameter_columns + class_column + ] + series = ( + sequence_ids[ID] + .drop(columns=["ID"] + class_column + parameter_columns) + .to_numpy() + ) + parameters = sequence_ids[ID].drop(columns=data_columns).to_numpy()[0, :] + classes = sequence_ids[ID][class_column].to_numpy()[0, :] + window_start = 0 + sequences_in_category = 0 + while window_start <= len(series): + past_end = window_start + n_past + future_end = past_end + n_future + if not future_end >= len(series): + # slicing the past and future parts of the window + past, future = ( + series[window_start:past_end, :], + series[past_end:future_end, :], + ) + # past, future = series[window_start:future_end, :], series[past_end:future_end, :] + xx.append(past) + yy.append(future) + # For each sequence length set target sequence_id + zz.append( + int(ID), + ) + ww.append(parameters) + if class_column: + cc.append(classes) + sequences_in_category += 1 + window_start += stride + + train_data.extend(np.array(xx)) + target_data.extend(np.array(yy)) + target_category.extend(np.array(zz)) + target_parameters.extend(np.array(ww)) + if class_column: + target_classes.extend(np.array(cc)) + samples_in_sequence_id.append(sequences_in_category) + return ( + train_data, + target_data, + target_category, + target_parameters, + target_classes, + samples_in_sequence_id, + ) + + +def get_indices_from_sequence_ids(sequence_ids: list, samples_in_sequence_id: list): + indices = list() + + # We compute weights since it is cheap and they are used when weighing samples. + weights = defaultdict(float) + sequence_index = 0 + start_index = 0 + + for sequence_id in sequence_ids: + # We need to compute the start of each sequence's samples. To do this, we + # compute the start of all sequences' sample starts. start_index + # keeps track of where each sequence's samples start. + while ( + sequence_index < len(samples_in_sequence_id) + and sequence_index < sequence_id + ): + start_index += samples_in_sequence_id[sequence_index] + sequence_index += 1 + if sequence_index >= len(samples_in_sequence_id): + break + if sequence_index == sequence_id: + # The weight is simply one over the number of samples in this sequence. + # We can never divide by zero - empty categories are implicitly excluded + weights[sequence_id] = 1.0 / samples_in_sequence_id[sequence_id] + indices += list( + range(start_index, start_index + samples_in_sequence_id[sequence_id]) + ) + start_index += samples_in_sequence_id[sequence_index] + sequence_index += 1 + return indices, weights diff --git a/traja/dataset/pedestrian.py b/traja/dataset/pedestrian.py new file mode 100644 index 00000000..89ad8f26 --- /dev/null +++ b/traja/dataset/pedestrian.py @@ -0,0 +1,69 @@ +import subprocess +import glob +import os +from typing import List +import pandas as pd +from traja.dataset import dataset +import traja + + +"""Convenience module for downloading pedestrian-related datasets.""" + + +def ped_datasets() -> List[str]: + """Returns paths after downloading pedestrian datasets.""" + if not os.path.exists("datasets"): + subprocess.call( + ["wget", "https://www.dropbox.com/s/8n02xqv3l9q18r1/datasets.zip"] + ) + subprocess.call(["unzip", "-q", "datasets.zip"]) + subprocess.call(["rm", "-rf", "datasets.zip"]) + else: + print("Directory 'datasets' exists, skipping download") + + return glob.glob(f"datasets/*/*") + + +def load_ped_data(dataset_name=None, aspaths=False) -> dict: + """Returns pedestrian (ETH, Zara1, Zara2, Univ, Hotel) datasets as dataframe or as paths. + + Args: + dataset_name: Optional(str) - returns specific dataset + eth + zara1 + zara2 + univ + hotel + aspaths: (bool) - Returns paths only + + Returns: + paths/dfs (dict) - train/val/test split for paths or dfs, depending on `aspaths` value + + + Paths are .txt files with format . + """ + paths = ped_datasets() + + if dataset_name: + # Get subset of data + paths = [path for path in paths if dataset_name in path] + + train_dir = [path for path in paths if "train" in path][0] + val_dir = [path for path in paths if "val" in path][0] + test_dir = [path for path in paths if "test" in path][0] + + train_paths = glob.glob(os.path.join(train_dir, "*.txt")) + val_paths = glob.glob(os.path.join(val_dir, "*.txt")) + test_paths = glob.glob(os.path.join(test_dir, "*.txt")) + + paths = {"train": train_paths, "val": val_paths, "test": test_paths} + if aspaths: + return paths + + col_names = ["frame_id", "ped_id", "x", "y"] + dfs = { + "train": [pd.read_csv(path, sep="\t", names=col_names) for path in train_paths], + "val": [pd.read_csv(path, sep="\t", names=col_names) for path in train_paths], + "test": [pd.read_csv(path, sep="\t", names=col_names) for path in train_paths], + } + return dfs diff --git a/traja/dataset/pituitary_gland.py b/traja/dataset/pituitary_gland.py new file mode 100644 index 00000000..ed6c9e63 --- /dev/null +++ b/traja/dataset/pituitary_gland.py @@ -0,0 +1,151 @@ +import numpy as np +import pandas as pd +from numpy import exp +from numba import jit +from scipy.integrate import odeint +from pyDOE2 import lhs + + +# PyTest will not compute coverage correctly for @jit-compiled code. +# Thus we must explicitly suppress the coverage check. +@jit +def pituitary_ode(w, t, p): # pragma: no cover + """ + Defines the differential equations for the pituirary gland system. + To be used with scipy.integrate.odeint (this is the rhs equation). + + Arguments: + w : vector of the state variables: + w = [v, n, f, c] + t : time + p : vector of the parameters: + p = [gk, gcal, gsk, gbk, gl, k] + """ + vca = 60 + vk = -75 + vl = -50 + Cm = 10 + vn = -5 + vm = -20 + vf = -20 + sn = 10 + sm = 12 + sf = 2 + taun = 30 + taubk = 5 + ff = 0.01 + alpha = 0.0015 + ks = 0.4 + auto = 0 + cpar = 0 + noise = 4.0 + + v, n, f, c = w + + gk, gcal, gsk, gbk, gl, kc = p + + cd = (1 - auto) * c + auto * cpar + + phik = 1 / (1 + exp((vn - v) / sn)) + phif = 1 / (1 + exp((vf - v) / sf)) + phical = 1 / (1 + exp((vm - v) / sm)) + cinf = cd ** 2 / (cd ** 2 + ks ** 2) + + ica = gcal * phical * (v - vca) + isk = gsk * cinf * (v - vk) + ibk = gbk * f * (v - vk) + ikdr = gk * n * (v - vk) + ileak = gl * (v - vl) + + ikdrx = ikdr + ibkx = ibk + + ik = isk + ibk + ikdr + inoise = 0 # noise*w #TODO fix + + dv = -(ica + ik + inoise + ileak) / Cm + dn = (phik - n) / taun + df = (phif - f) / taubk + dc = -ff * (alpha * ica + kc * c) + return dv, dn, df, dc + + +def compute_pituitary_gland_df_from_parameters(downsample_rate, + gcal, gsk, gk, gbk, gl, kc, + sample_id, + trim_start=20000): + """ + Computes a Traja dataframe from the pituitary gland simulation. + + It is easier to discuss ion flow in term of conductances than resistances. + If V / R = I, where V is the voltage, R is the resistance and I is the + current, then V * C = I, where C = 1 / R is the conductance. + + Below we specify arguments in terms of maximum conductances, + i.e. the maximum rate at which ion channels let ions through + the cell walls. + + Arguments: + downsample_rate : How much the dataframe will be downsampled (relative + to the original simulation) + gcal : The maximum calcium conductance + gsk : The maximum s-potassiun conductance + gk : The maximum potassium conductance + gbk : The maximum b-potassium conductance + gl : The maximum leak conductance + kc : + sample_id : The ID of this particular sample. Must be unique + trim_start : How much of the start of the sample to trim. + The start of an activation (before converging to a limit cycle + or fixed point) is usually not interesting from a biological + perspective, so the default is to remove it. + """ + + # Initial conditions + v = -60. + n = 0.1 + f = 0.01 + c = 0.1 + + p = (gk, gcal, gsk, gbk, gl, kc) + w0 = (v, n, f, c) + abserr = 1.0e-8 + relerr = 1.0e-6 + + t = np.arange(0, 5000, 0.05) + # print("Generating gcal={}, gsk={}, gk={}, gbk={}, gl={}, kc={}".format(gcal, gsk, gk, gbk, gl, kc)) + wsol = odeint(pituitary_ode, w0, t, args=(p,), atol=abserr, rtol=relerr) + df = pd.DataFrame(wsol, columns=['v', 'n', 'f', 'c']) + df = df[trim_start:] + df['ID'] = sample_id + df['gcal'] = gcal + df['gsk'] = gsk + df['gk'] = gk + df['gbk'] = gbk + df['gl'] = gl + df['kc'] = kc + df = df.iloc[::downsample_rate, :] + # df = df.drop(columns=['t', 'ikdrx', 'ibkx']) + + return df + + +def create_latin_hypercube_sampled_pituitary_df(downsample_rate=100, samples=1000): + latin_hypercube_samples = lhs(6, criterion='center', samples=samples) + + # gcal, gsk, gk, gbk, gl, kc, + range_start = (0.5, 0.5, 0.8, 0., 0.05, 0.03) + range_end = (3.5, 3.5, 5.6, 4., 0.35, 0.21) + + parameters = latin_hypercube_samples * range_end - latin_hypercube_samples * range_start + + dataframes = [] + for sample_id, parameter in enumerate(parameters): + gcal, gsk, gk, gbk, gl, kc = parameter + df = compute_pituitary_gland_df_from_parameters(downsample_rate, + gcal, gsk, gk, gbk, gl, kc, + sample_id) + dataframes.append(df) + + num_samples = len(dataframes) + return pd.concat(dataframes), num_samples diff --git a/traja/frame.py b/traja/frame.py new file mode 100644 index 00000000..9c60c872 --- /dev/null +++ b/traja/frame.py @@ -0,0 +1,322 @@ +import logging +from typing import Optional, Union, Tuple +import warnings + +import numpy as np +import pandas as pd +from pandas import DataFrame +from pandas.api.types import is_numeric_dtype + +import traja + +logging.basicConfig(format="%(levelname)s:%(message)s", level=logging.ERROR) + + +class TrajaDataFrame(pd.DataFrame): + """A TrajaDataFrame object is a subclass of pandas :class:`<~pandas.dataframe.DataFrame>`. + + Args: + args: Typical arguments for pandas.DataFrame. + + Returns: + traja.TrajaDataFrame -- TrajaDataFrame constructor. + + >>> traja.TrajaDataFrame({'x':[0,1,2],'y':[1,2,3]}) # doctest: +SKIP + x y + 0 0 1 + 1 1 2 + 2 2 3 + + """ + + _metadata = [ + "xlim", + "ylim", + "spatial_units", + "xlabel", + "ylabel", + "title", + "fps", + "time_units", + "time_col", + "id", + ] + + def __init__(self, *args, **kwargs): + # Allow setting metadata from constructor + traja_kwargs = dict() + for key in list(kwargs.keys()): + for name in self._metadata: + if key == name: + traja_kwargs[key] = kwargs.pop(key) + super(TrajaDataFrame, self).__init__(*args, **kwargs) + if len(args) == 1 and isinstance(args[0], TrajaDataFrame): + args[0]._copy_attrs(self) + for name, value in traja_kwargs.items(): + self.__dict__[name] = value + + # Initialize + self._convex_hull = None + + # Initialize metadata like 'fps','spatial_units', etc. + self._init_metadata() + + @property + def _constructor(self): + return TrajaDataFrame + + def _copy_attrs(self, df): + for attr in self._metadata: + df.__dict__[attr] = getattr(self, attr, None) + + def __finalize__(self, other, method=None, **kwargs): + """propagate metadata from other to self""" + # merge operation: using metadata of the left object + if method == "merge": + for name in self._metadata: + object.__setattr__(self, name, getattr(other.left, name, None)) + # concat operation: using metadata of the first object + elif method == "concat": + for name in self._metadata: + object.__setattr__(self, name, getattr(other.objs[0], name, None)) + else: + for name in self._metadata: + object.__setattr__(self, name, getattr(other, name, None)) + return self + + # def __getitem__(self, key): + # """ + # If result is a DataFrame with a x or X column, return a + # TrajaDataFrame. + # """ + # result = super(TrajaDataFrame, self).__getitem__(key) + # if isinstance(result, DataFrame) and "x" == result or "X" == result: + # result.__class__ = TrajaDataFrame + # elif isinstance(result, DataFrame): + # result.__class__ = DataFrame + # return result + + def _init_metadata(self): + defaults = dict(fps=None, spatial_units="m", time_units="s") + for name, value in defaults.items(): + if name not in self.__dict__: + self.__dict__[name] = value + + def _get_time_col(self): + time_cols = [col for col in self if "time" in col.lower()] + if time_cols: + time_col = time_cols[0] + if is_numeric_dtype(self[time_col]): + return time_col + else: + return None + + @classmethod + def from_xy(cls, xy: np.ndarray): + """Convenience function for initializing :class:`~traja.frame.TrajaDataFrame` with x,y coordinates. + + Args: + xy (:class:`numpy.ndarray`): x,y coordinates + + Returns: + traj_df (:class:`~traja.frame.TrajaDataFrame`): Trajectory as dataframe + + .. doctest:: + + >>> import numpy as np + >>> xy = np.array([[0,1],[1,2],[2,3]]) + >>> traja.from_xy(xy) + x y + 0 0 1 + 1 1 2 + 2 2 3 + + """ + df = cls.from_records(xy, columns=["x", "y"]) + return df + + def set(self, key, value): + """Set metadata.""" + self.__dict__[key] = value + + def __setattr__(self, name: str, value) -> None: + """Override method for pandas.core.generic method __setattr__ + + Allows for setting attributes to dataframe without warning. + """ + try: + object.__getattribute__(self, name) + return object.__setattr__(self, name, value) + except AttributeError: + pass + if name in self._internal_names_set: + object.__setattr__(self, name, value) + elif name in self._metadata: + object.__setattr__(self, name, value) + else: + try: + existing = getattr(self, name) + if isinstance(existing, type(self.index)): + object.__setattr__(self, name, value) + elif name in self._info_axis: + self[name] = value + else: + object.__setattr__(self, name, value) + except (AttributeError, TypeError): + object.__setattr__(self, name, value) + + @property + def center(self): + """Return the center point of this trajectory.""" + x = self.x + y = self.y + return float(x.mean()), float(y.mean()) + + @property + def convex_hull(self): + """Property of TrajaDataFrame class representing + bounds for convex area enclosing trajectory points. + + """ + # Calculate if it doesn't exist + if self._convex_hull is None: + xy_arr = self.traja.xy + point_arr = traja.trajectory.calc_convex_hull(xy_arr) + self._convex_hull = point_arr + return self._convex_hull + + @convex_hull.setter + def convex_hull(self, values): + """Set convex_hull property of TrajaDataFrame. + + Returns: + np.array, calculated coordinates of convex hull boundary + """ + if values is not None and not values.shape[1] == 2: + raise Exception( + "XY coordinates must be in separate columns " + "for convex hull calculation." + ) + elif values is None: + self._convex_hull = np.array([]) + else: + point_arr = traja.trajectory.calc_convex_hull(values) + self._convex_hull = point_arr + + @convex_hull.deleter + def convex_hull(self): + self._convex_hull = None + + +def tocontainer(func): + def wrapper(*args, **kwargs): + result = func(*args, **kwargs) + return TrajaCollection(result) + + return wrapper + + +class TrajaCollection(TrajaDataFrame): + """Collection of trajectories.""" + + _metadata = [ + "xlim", + "ylim", + "spatial_units", + "xlabel", + "ylabel", + "title", + "fps", + "time_units", + "time_col", + "_id_col", + ] + + def __init__( + self, + trjs: Union[TrajaDataFrame, pd.DataFrame, dict], + id_col: Optional[str] = None, + **kwargs, + ): + """Initialize with trajectories with x, y, and time columns. + + Args:self. + trjs + id_col (str) - Default is "id" + + """ + # Add id column + if isinstance(trjs, dict): + _trjs = [] + for name, df in trjs.items(): + df["id"] = name + _trjs.append(df) + super(TrajaCollection, self).__init__(pd.concat(_trjs), **kwargs) + elif isinstance(trjs, (TrajaDataFrame, DataFrame)): + super(TrajaCollection, self).__init__(trjs, **kwargs) + else: + super(TrajaCollection, self).__init__(trjs, **kwargs) + + if id_col: + self._id_col = id_col + elif hasattr(self, "_id_col"): + self._id_col = self._id_col + else: + self._id_col = "id" # default + + @property + def _constructor(self): + return TrajaCollection + + def _copy_attrs(self, df): + for attr in self._metadata: + df.__dict__[attr] = getattr(self, attr, None) + + # def __copy__(self): + # return TrajaCollection(self.trjs).__dict__.update(self.__dict__) + + def __repr__(self): + return "TrajaCollection:\n" + super(TrajaCollection, self).__repr__() + + # def __add__(self, other): + # trjs = self.trjs.append(other, ignore_index=True) + # return TrajaCollection(trjs, id_col=self._id_col) + + def plot(self, colors=None, **kwargs): + """Plot collection of trajectories with colors assigned to each id. + + >>> trjs = {ind: traja.generate(seed=ind) for ind in range(3)} # doctest: +SKIP + >>> coll = traja.TrajaCollection(trjs) # doctest: +SKIP + >>> coll.plot() # doctest: +SKIP + + """ + return traja.plotting.plot_collection( + self, self._id_col, colors=colors, **kwargs + ) + + def apply_all(self, method, **kwargs): + """Applies method to all trajectories + + Args: + method + + Returns: + dataframe or series + + >>> trjs = {ind: traja.generate(seed=ind) for ind in range(3)} # doctest: +SKIP + >>> coll = traja.TrajaCollection(trjs) # doctest: +SKIP + >>> angles = coll.apply_all(traja.calc_angle) # doctest: +SKIP + + """ + return self.groupby(by=self._id_col).apply(method) + + +class StaticObject(object): + def __init__( + self, + x: Optional[float] = None, + y: Optional[float] = None, + bounding_box: Tuple[float] = None, + ): + ... + pass diff --git a/traja/models/__init__.py b/traja/models/__init__.py new file mode 100644 index 00000000..65c12776 --- /dev/null +++ b/traja/models/__init__.py @@ -0,0 +1,7 @@ +from traja.models.generative_models.vae import MultiModelVAE +from traja.models.generative_models.vaegan import MultiModelVAEGAN +from traja.models.predictive_models.ae import MultiModelAE +from traja.models.predictive_models.lstm import LSTM +from .inference import * +from .train import HybridTrainer +from .utils import TimeDistributed, read_hyperparameters, save, load diff --git a/traja/models/base_models/MLPClassifier.py b/traja/models/base_models/MLPClassifier.py new file mode 100644 index 00000000..9f507a70 --- /dev/null +++ b/traja/models/base_models/MLPClassifier.py @@ -0,0 +1,51 @@ +import torch +from torch import nn + + +class MLPClassifier(torch.nn.Module): + """MLP classifier: Classify the input data using the latent embeddings + input_size: The number of expected latent size + hidden_size: The number of features in the hidden state h + output_size: Size of labels or the number of sequence_ids in the data + dropout: If non-zero, introduces a Dropout layer on the outputs of each LSTM layer except the last layer, + with dropout probability equal to dropout + num_layers: Number of hidden layers in the classifier + """ + + def __init__( + self, + input_size: int, + hidden_size: int, + output_size: int, + num_layers: int, + dropout: float, + ): + super(MLPClassifier, self).__init__() + + self.input_size = input_size + self.hidden_size = hidden_size + self.num_classes = output_size + self.num_layers = num_layers + self.dropout = dropout + + # Classifier layers + layers = list() + + layers.append(nn.Linear(self.input_size, self.hidden_size)) + layers.append(nn.ReLU()) + torch.nn.Dropout(p=dropout) + + for layer in range(1, self.num_layers): + layers.append(nn.Linear(self.hidden_size, self.hidden_size)) + layers.append(nn.ReLU()) + torch.nn.Dropout(p=dropout) + + layers.append(nn.Linear(self.hidden_size, self.num_classes)) + + self.hidden = nn.Sequential(*layers) + self.sigmoid = nn.Sigmoid() + + def forward(self, x): + x = self.hidden(x) + output = self.sigmoid(x) + return output diff --git a/traja/models/base_models/MLPRegressor.py b/traja/models/base_models/MLPRegressor.py new file mode 100644 index 00000000..c7bcc255 --- /dev/null +++ b/traja/models/base_models/MLPRegressor.py @@ -0,0 +1,49 @@ +import torch +from torch import nn + + +class MLPRegressor(torch.nn.Module): + """MLP regressor: Regress the input data using the latent embeddings + input_size: The number of expected latent size + hidden_size: The number of features in the hidden state h + output_size: Size of labels or the number of sequence_ids in the data + dropout: If non-zero, introduces a Dropout layer on the outputs of each LSTM layer except the last layer, + with dropout probability equal to dropout + num_layers: Number of hidden layers in the classifier + """ + + def __init__( + self, + input_size: int, + hidden_size: int, + output_size: int, + num_layers: int, + dropout: float, + ): + super(MLPRegressor, self).__init__() + + self.input_size = input_size + self.hidden_size = hidden_size + self.output_size = output_size + self.num_layers = num_layers + self.dropout = dropout + + # Classifier layers + layers = list() + + layers.append(nn.Linear(self.input_size, self.hidden_size)) + layers.append(nn.ReLU()) + torch.nn.Dropout(p=dropout) + + for layer in range(1, self.num_layers): + layers.append(nn.Linear(self.hidden_size, self.hidden_size)) + layers.append(nn.ReLU()) + torch.nn.Dropout(p=dropout) + + layers.append(nn.Linear(self.hidden_size, self.output_size)) + + self.hidden = nn.Sequential(*layers) + + def forward(self, x): + output = self.hidden(x) + return output diff --git a/traja/models/base_models/__init__.py b/traja/models/base_models/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/traja/models/generative_models/__init__.py b/traja/models/generative_models/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/traja/models/generative_models/vae.py b/traja/models/generative_models/vae.py new file mode 100644 index 00000000..cb31d1f5 --- /dev/null +++ b/traja/models/generative_models/vae.py @@ -0,0 +1,447 @@ +""" This module implement the Variational Autoencoder model for +both forecasting and classification of time series data. +""" + +import torch + +from traja.models.base_models.MLPClassifier import MLPClassifier +from traja.models.base_models.MLPRegressor import MLPRegressor +from traja.models.utils import TimeDistributed + +device = "cuda" if torch.cuda.is_available() else "cpu" + + +class LSTMEncoder(torch.nn.Module): + """Implementation of Encoder network using LSTM layers + input_size: The number of expected features in the input x + num_past: Number of time steps to look backwards to predict num_future steps forward + batch_size: Number of samples in a batch + hidden_size: The number of features in the hidden state h + num_lstm_layers: Number of layers in the LSTM model + + batch_first: If True, then the input and output tensors are provided as (batch, seq, feature) + dropout: If non-zero, introduces a Dropout layer on the outputs of each LSTM layer except the last layer, + with dropout probability equal to dropout + reset_state: If True, will reset the hidden and cell state for each batch of data + bidirectional: If True, becomes a bidirectional LSTM + """ + + def __init__( + self, + input_size: int, + num_past: int, + batch_size: int, + hidden_size: int, + num_lstm_layers: int, + batch_first: bool, + dropout: float, + reset_state: bool, + bidirectional: bool, + ): + super(LSTMEncoder, self).__init__() + + self.input_size = input_size + self.num_past = num_past + self.batch_size = batch_size + self.hidden_size = hidden_size + self.num_lstm_layers = num_lstm_layers + self.batch_first = batch_first + self.dropout = dropout + self.reset_state = reset_state + self.bidirectional = bidirectional + + self.lstm_encoder = torch.nn.LSTM( + input_size=input_size, + hidden_size=self.hidden_size, + num_layers=num_lstm_layers, + dropout=dropout, + bidirectional=self.bidirectional, + batch_first=True, + ) + + def _init_hidden(self): + return ( + torch.zeros(self.num_lstm_layers, self.batch_size, self.hidden_size) + .requires_grad_() + .to(device), + torch.zeros(self.num_lstm_layers, self.batch_size, self.hidden_size) + .requires_grad_() + .to(device), + ) + + def forward(self, x): + (h0, c0) = self._init_hidden() + enc_output, _ = self.lstm_encoder(x, (h0.detach(), c0.detach())) + # RNNs obeys, Markovian. So, the last state of the hidden is the markovian state for the entire + # sequence in that batch. + enc_output = enc_output[:, -1, :] # Shape(batch_size,hidden_dim) + return enc_output + + +class DisentangledAELatent(torch.nn.Module): + """Dense Dientangled Latent Layer between encoder and decoder""" + + def __init__(self, hidden_size: int, latent_size: int, dropout: float): + super(DisentangledAELatent, self).__init__() + self.latent_size = latent_size + self.hidden_size = hidden_size + self.dropout = dropout + self.latent = torch.nn.Linear(self.hidden_size, self.latent_size * 2) + + @staticmethod + def reparameterize(mu, logvar, training=True): + if training: + std = logvar.mul(0.5).exp_() + eps = std.data.new(std.size()).normal_() + return eps.mul(std).add_(mu) + return mu + + def forward(self, x, training=True): + z_variables = self.latent(x) # [batch_size, latent_size*2] + mu, logvar = torch.chunk(z_variables, 2, dim=1) # [batch_size,latent_size] + # Reparameterize + z = self.reparameterize( + mu, logvar, training=training + ) # [batch_size,latent_size] + return z, mu, logvar + + +class LSTMDecoder(torch.nn.Module): + """Implementation of Decoder network using LSTM layers + input_size: The number of expected features in the input x + num_future: Number of time steps to be predicted given the num_past steps + batch_size: Number of samples in a batch + hidden_size: The number of features in the hidden state h + num_lstm_layers: Number of layers in the LSTM model + output_size: Number of expectd features in the output x_ + batch_first: If True, then the input and output tensors are provided as (batch, seq, feature) + dropout: If non-zero, introduces a Dropout layer on the outputs of each LSTM layer except the last layer, + with dropout probability equal to dropout + reset_state: If True, will reset the hidden and cell state for each batch of data + bidirectional: If True, becomes a bidirectional LSTM + """ + + def __init__( + self, + batch_size: int, + num_future: int, + hidden_size: int, + num_lstm_layers: int, + output_size: int, + latent_size: int, + batch_first: bool, + dropout: float, + reset_state: bool, + bidirectional: bool, + ): + super(LSTMDecoder, self).__init__() + self.batch_size = batch_size + self.latent_size = latent_size + self.num_future = num_future + self.hidden_size = hidden_size + self.num_lstm_layers = num_lstm_layers + self.output_size = output_size + self.batch_first = batch_first + self.dropout = dropout + self.reset_state = reset_state + self.bidirectional = bidirectional + + # RNN decoder + self.lstm_decoder = torch.nn.LSTM( + input_size=self.latent_size, + hidden_size=self.hidden_size, + num_layers=self.num_lstm_layers, + dropout=self.dropout, + bidirectional=self.bidirectional, + batch_first=True, + ) + self.output = TimeDistributed( + torch.nn.Linear(self.hidden_size, self.output_size) + ) + + def _init_hidden(self): + return ( + torch.zeros(self.num_lstm_layers, self.batch_size, self.hidden_size) + .requires_grad_() + .to(device), + torch.zeros(self.num_lstm_layers, self.batch_size, self.hidden_size) + .requires_grad_() + .to(device), + ) + + def forward(self, x, num_future=None): + + # To feed the latent states into lstm decoder, + # repeat the tensor n_future times at second dim + (h0, c0) = self._init_hidden() + decoder_inputs = x.unsqueeze(1) + + if num_future is None: + decoder_inputs = decoder_inputs.repeat(1, self.num_future, 1) + else: # For multistep a prediction after training + decoder_inputs = decoder_inputs.repeat(1, num_future, 1) + + # Decoder input Shape(batch_size, num_futures, latent_size) + dec, _ = self.lstm_decoder(decoder_inputs, (h0.detach(), c0.detach())) + + # Map the decoder output: Shape(batch_size, sequence_len, hidden_dim) + # to Time Dsitributed Linear Layer + output = self.output(dec) + return output + + +class MultiModelVAE(torch.nn.Module): + """Implementation of Multimodel Variational autoencoders; This Module wraps the Variational Autoencoder + models [Encoder,Latent[Sampler],Decoder]. If classify=True, then the wrapper also include classification layers + + input_size: The number of expected features in the input x + num_future: Number of time steps to be predicted given the num_past steps + batch_size: Number of samples in a batch + hidden_size: The number of features in the hidden state h + num_lstm_layers: Number of layers in the LSTM model + output_size: Number of expectd features in the output x_ + batch_first: If True, then the input and output tensors are provided as (batch, seq, feature) + dropout: If non-zero, introduces a Dropout layer on the outputs of each LSTM layer except the last layer, + with dropout probability equal to dropout + reset_state: If True, will reset the hidden and cell state for each batch of data + bidirectional: If True, becomes a bidirectional LSTM + """ + + def __init__( + self, + input_size: int, + num_past: int, + batch_size: int, + num_future: int, + lstm_hidden_size: int, + num_lstm_layers: int, + output_size: int, + latent_size: int, + batch_first: bool, + dropout: float, + reset_state: bool, + bidirectional: bool = False, + num_classifier_layers: int = None, + classifier_hidden_size: int = None, + num_classes: int = None, + num_regressor_layers: int = None, + regressor_hidden_size: int = None, + num_regressor_parameters: int = None, + ): + + super(MultiModelVAE, self).__init__() + self.input_size = input_size + self.num_past = num_past + self.batch_size = batch_size + self.latent_size = latent_size + self.num_future = num_future + self.lstm_hidden_size = lstm_hidden_size + self.num_lstm_layers = num_lstm_layers + self.classifier_hidden_size = classifier_hidden_size + self.num_classifier_layers = num_classifier_layers + self.output_size = output_size + self.num_classes = num_classes + self.batch_first = batch_first + self.dropout = dropout + self.reset_state = reset_state + self.bidirectional = bidirectional + self.num_regressor_layers = num_regressor_layers + self.regressor_hidden_size = regressor_hidden_size + self.num_regressor_parameters = num_regressor_parameters + + self.latent_output_disabled = False # Manually override latent output + + # Let the trainer know what kind of model this is + self.model_type = "vae" + + self.encoder = LSTMEncoder( + input_size=self.input_size, + num_past=self.num_past, + batch_size=self.batch_size, + hidden_size=self.lstm_hidden_size, + num_lstm_layers=self.num_lstm_layers, + batch_first=self.batch_first, + dropout=self.dropout, + reset_state=True, + bidirectional=self.bidirectional, + ) + + self.latent = DisentangledAELatent( + hidden_size=self.lstm_hidden_size, + latent_size=self.latent_size, + dropout=self.dropout, + ) + + self.decoder = LSTMDecoder( + batch_size=self.batch_size, + num_future=self.num_future, + hidden_size=self.lstm_hidden_size, + num_lstm_layers=self.num_lstm_layers, + output_size=self.output_size, + latent_size=self.latent_size, + batch_first=self.batch_first, + dropout=self.dropout, + reset_state=True, + bidirectional=self.bidirectional, + ) + + if self.num_classes is not None: + self.classifier = MLPClassifier( + input_size=self.latent_size, + hidden_size=self.classifier_hidden_size, + output_size=self.num_classes, + num_layers=self.num_classifier_layers, + dropout=self.dropout, + ) + + if self.num_regressor_parameters is not None: + self.regressor = MLPRegressor( + input_size=self.latent_size, + hidden_size=self.regressor_hidden_size, + output_size=self.num_regressor_parameters, + num_layers=self.num_regressor_layers, + dropout=self.dropout, + ) + + def reset_classifier(self, classifier_hidden_size: int, num_classifier_layers: int): + """Reset the classifier, with a new hidden size and depth. + This is useful when parameter searching. + + classifier_hidden_size: The number of units in each classifier layer + num_layers: Number of layers in the classifier + """ + self.classifier_hidden_size = classifier_hidden_size + self.num_classifier_layers = num_classifier_layers + + self.classifier = MLPClassifier( + input_size=self.latent_size, + hidden_size=self.classifier_hidden_size, + output_size=self.num_classes, + num_layers=self.num_classifier_layers, + dropout=self.dropout, + ) + + def reset_regressor(self, regressor_hidden_size: int, num_regressor_layers: int): + """Reset the regressor, with a new hidden size and depth. + This is useful when parameter searching. + + regressor_hidden_size: The number of units in each classifier layer + num_regressor_layers: Number of layers in the classifier + """ + self.num_regressor_layers = num_regressor_layers + self.regressor_hidden_size = regressor_hidden_size + + self.regressor = MLPRegressor( + input_size=self.latent_size, + hidden_size=self.regressor_hidden_size, + output_size=self.num_regressor_parameters, + num_layers=self.num_regressor_layers, + dropout=self.dropout, + ) + + def disable_latent_output(self): + """Disable latent output, to make the VAE behave like a standard autoencoder while training. + This modifies the training loss computed.""" + self.latent_output_disabled = True + + def enable_latent_output(self): + """Enable latent output, to make the VAE behave like a variational autoencoder while training. + This modifies the training loss computed. + NOTE: By default, latent output is enabled.""" + self.latent_output_disabled = False + + def forward(self, data, training=True, classify=False, regress=False, latent=True): + """ + Parameters: + ----------- + data: Train or test data + training: If Training= False, latents are deterministic + classify: If True, perform classification of input data using the latent embeddings + Return: + ------- + decoder_out,latent_out or classifier out + """ + + assert not (classify and regress), "Model cannot both classify and regress!" + + if not (classify or regress): + # Set the classifier and regressor grads off + if self.num_classes is not None: + for param in self.classifier.parameters(): + param.requires_grad = False + if self.num_regressor_parameters is not None: + for param in self.regressor.parameters(): + param.requires_grad = False + + for param in self.encoder.parameters(): + param.requires_grad = True + for param in self.decoder.parameters(): + param.requires_grad = True + for param in self.latent.parameters(): + param.requires_grad = True + + # Encoder -->Latent --> Decoder + enc_out = self.encoder(data) + latent_out, mu, logvar = self.latent(enc_out) + decoder_out = self.decoder(latent_out) + if latent: + return decoder_out, latent_out, mu, logvar + else: + return decoder_out + + elif classify: + # Unfreeze classifier and freeze the rest + assert self.num_classes is not None, "Classifier not found" + + for param in self.classifier.parameters(): + param.requires_grad = True + if self.num_regressor_parameters is not None: + for param in self.regressor.parameters(): + param.requires_grad = False + for param in self.encoder.parameters(): + param.requires_grad = False + for param in self.decoder.parameters(): + param.requires_grad = False + for param in self.latent.parameters(): + param.requires_grad = False + + # Encoder -->Latent --> Classifier + enc_out = self.encoder(data) + latent_out, mu, logvar = self.latent(enc_out, training=training) + + classifier_out = self.classifier(mu) # Deterministic + if latent: + return classifier_out, latent_out, mu, logvar + else: + return classifier_out + + elif regress: + # Unfreeze classifier and freeze the rest + assert self.num_regressor_parameters is not None, "Regressor not found" + + if self.num_classes is not None: + for param in self.classifier.parameters(): + param.requires_grad = False + for param in self.regressor.parameters(): + param.requires_grad = True + for param in self.encoder.parameters(): + param.requires_grad = False + for param in self.decoder.parameters(): + param.requires_grad = False + for param in self.latent.parameters(): + param.requires_grad = False + + # Encoder -->Latent --> Regressor + enc_out = self.encoder(data) + latent_out, mu, logvar = self.latent(enc_out, training=training) + + regressor_out = self.regressor(mu) # Deterministic + + if self.latent_output_disabled: + mu = None + logvar = None + + if latent: + return regressor_out, latent_out, mu, logvar + else: + return regressor_out diff --git a/traja/models/generative_models/vaegan.py b/traja/models/generative_models/vaegan.py new file mode 100644 index 00000000..16f1c66a --- /dev/null +++ b/traja/models/generative_models/vaegan.py @@ -0,0 +1,26 @@ +"""This module contains the variational autoencoders - GAN and its variants +1. classic VAE-GAN +2. ***** + +Loss functions: +1. MSE +2. Huber Loss""" + +import torch + + +class MultiModelVAEGAN(torch.nn.Module): + def __init__(self, *model_hyperparameters, **kwargs): + super(MultiModelVAEGAN, self).__init__() + + for dictionary in model_hyperparameters: + for key in dictionary: + setattr(self, key, dictionary[key]) + for key in kwargs: + setattr(self, key, kwargs[key]) + + def __new__(cls): + pass + + def forward(self, *input: None, **kwargs: None): + return NotImplementedError diff --git a/traja/models/inference.py b/traja/models/inference.py new file mode 100644 index 00000000..2bab46f1 --- /dev/null +++ b/traja/models/inference.py @@ -0,0 +1,286 @@ +"""Generate time series from model""" + +import matplotlib.pyplot as plt +import numpy as np +import torch + +from traja.models.generative_models.vae import MultiModelVAE +from traja.models.generative_models.vaegan import MultiModelVAEGAN +from traja.models.predictive_models.ae import MultiModelAE +from traja.models.predictive_models.lstm import LSTM + +device = "cuda" if torch.cuda.is_available() else "cpu" + + +class Generator: + def __init__( + self, + model_type: str = None, + model_path: str = None, + model_hyperparameters: dict = None, + model: torch.nn.Module = None, + ): + """Generate a batch of future steps from a random latent state of Multi variate multi label models + + Args: + model_type (str, optional): Type of model ['vae','vaegan','custom']. Defaults to None. + model_path (str, optional): Path to trained model (model.pt). Defaults to None. + model_hyperparameters (dict, optional): [description]. Defaults to None. + model (torch.nn.Module, optional): Custom model from user. Defaults to None + """ + + self.model_type = model_type + self.model_path = model_path + self.model_hyperparameters = model_hyperparameters + + if self.model_type == "vae": + self.model = MultiModelVAE(**self.model_hyperparameters) + + if self.model_type == "vaegan": + self.model = MultiModelVAEGAN(**self.model_hyperparameters) + + if self.model_type == "custom": + assert model is not None + self.model = model(**self.model_hyperparameters) + + ( + self.generated_category, + self.generated_data, + ) = (None, None) + + def generate(self, num_steps, classify=True, scaler=None, plot_data=True): + + self.model.to(device) + if self.model_type == "vae": + # Random noise + z = ( + torch.empty( + self.model_hyperparameters["batch_size"], + self.model_hyperparameters["latent_size"], + ) + .normal_(mean=0, std=0.1) + .to(device) + ) + # Generate trajectories from the noise + self.generated_data = ( + self.model.decoder(z, num_steps).cpu().detach().numpy() + ) + self.generated_data = self.generated_data.reshape( + self.generated_data.shape[0] * self.generated_data.shape[1], + self.generated_data.shape[2], + ) + if classify: + try: + self.generated_category = self.model.classifier(z) + print( + "IDs in this batch of synthetic data", + torch.max(self.generated_category, 1).indices.detach() + 1, + ) + except Exception as error: + print("Classifier not found: " + repr(error)) + + # Scale original data and generated data + + # Rescaling predicted data + self.generated_data = scaler.inverse_transform(self.generated_data) + + # TODO:Depreself.generated_categoryed;Slicing the data into batches + self.generated_data = np.array( + [ + self.generated_data[i : i + num_steps] + for i in range(0, len(self.generated_data), num_steps) + ] + ) + + # Reshape [batch_size*num_steps,input_dim] + self.generated_data = self.generated_data.reshape( + self.generated_data.shape[0] * self.generated_data.shape[1], + self.generated_data.shape[2], + ) + + if plot_data: + fig, ax = plt.subplots(nrows=2, ncols=5, figsize=(16, 5), sharey=True) + fig.set_size_inches(20, 5) + + for i in range(2): + for j in range(5): + if classify: + try: + label = "Animal ID {}".format( + ( + torch.max(self.generated_category, 1).indices + + 1 + ).detach()[i + j] + ) + except Exception as error: + print("Classifier not found:" + repr(error)) + else: + label = "" + ax[i, j].plot( + self.generated_data[:, 0][ + (i + j) * num_steps : (i + j) * num_steps + num_steps + ], + self.generated_data[:, 1][ + (i + j) * num_steps : (i + j) * num_steps + num_steps + ], + label=label, + color="g", + ) + ax[i, j].legend() + plt.show() + + return self.generated_data + + elif self.model_type == "vaegan" or "custom": + return NotImplementedError + +class Predictor: + def __init__( + self, + model_type: str = None, + model_path: str = None, + model_hyperparameters: dict = None, + model: torch.nn.Module = None, + ): + """Generate a batch of future steps from a random latent state of Multi variate multi label models + + Args: + model_type (str, optional): Type of model ['ae','lstm','custom']. Defaults to None. + model_path (str, optional): [description]. Defaults to None. + model_hyperparameters (dict, optional): [description]. Defaults to None. + model (torch.nn.Module, optional): Custom model from user. Defaults to None + """ + + self.model_type = model_type + self.model_path = model_path + self.model_hyperparameters = model_hyperparameters + + if self.model_type == "ae": + self.model = MultiModelAE( + num_regressor_layers=2, + regressor_hidden_size=32, + num_regressor_parameters=3, + **self.model_hyperparameters, + ) + + if self.model_type == "lstm": + self.model = LSTM(**self.model_hyperparameters) + + if self.model_type == "custom": + assert model is not None + self.model = model(**self.model_hyperparameters) + + ( + self.predicted_category, + self.target_data, + self.target_data_, + self.predicted_data, + self.predicted_data_, + ) = (None, None, None, None, None) + + def predict(self, data_loader, num_steps, scaler, classify=True): + """[summary] + + Args: + data_loader ([type]): [description] + num_steps ([type]): [description] + scaler (dict): Scalers of the target data. This scale the model predictions to the scale of the target (future steps). + : This scaler will be returned by the traja data preprocessing and loading helper function. + classify (bool, optional): [description]. Defaults to True. + + Returns: + [type]: [description] + """ + + self.model.to(device) + if self.model_type == "ae": + for data, target, self.generated_category in data_loader: + data, target = data.to(device), target.to(device) + self.predicted_data = self.model.encoder(data) + self.predicted_data = self.model.latent(self.generated_data) + self.predicted_data = self.model.decoder(self.generated_data) + if classify: + self.generated_category = self.model.classifier(self.predicted_data) + + target = target.cpu().detach().numpy() + target = target.reshape( + target.shape[0] * target.shape[1], target.shape[2] + ) + self.predicted_data = self.predicted_data.cpu().detach().numpy() + self.predicted_data = self.predicted_data.reshape( + self.predicted_data.shape[0] * self.predicted_data.shape[1], + self.predicted_data.shape[2], + ) + + # Rescaling predicted data + for i in range(self.predicted_data.shape[1]): + s_s = scaler.inverse_transform( + self.predicted_data[:, i].reshape(-1, 1) + ) + s_s = np.reshape(s_s, len(s_s)) + self.predicted_data[:, i] = s_s + + predicted_data = np.array( + [ + self.predicted_data[i : i + num_steps] + for i in range(0, len(self.predicted_data), num_steps) + ] + ) + # Rescaling target data + self.target_data = target.copy() + for i in range(self.target_data.shape[1]): + s_s = scaler.inverse_transform( + self.target_data[:, i].reshape(-1, 1) + ) + s_s = np.reshape(s_s, len(s_s)) + self.target_data[:, i] = s_s + self.target_data = np.array( + [ + self.target_data[i : i + num_steps] + for i in range(0, len(self.target_data), num_steps) + ] + ) + + # Reshape [batch_size*num_steps,input_dim] + predicted_data_ = predicted_data.reshape( + self.predicted_data.shape[0] * self.predicted_data.shape[1], + self.predicted_data.shape[2], + ) + self.target_data_ = self.target_data.reshape( + self.target_data.shape[0] * self.target_data.shape[1], + self.target_data.shape[2], + ) + + fig, ax = plt.subplots(nrows=2, ncols=5, figsize=(16, 5), sharey=False) + fig.set_size_inches(40, 20) + for i in range(2): + for j in range(5): + ax[i, j].plot( + predicted_data_[:, 0][ + (i + j) * num_steps : (i + j) * num_steps + num_steps + ], + predicted_data_[:, 1][ + (i + j) * num_steps : (i + j) * num_steps + num_steps + ], + label=f"Predicted ID {self.generated_categoryegory[i + j]}", + ) + + ax[i, j].plot( + self.target_data_[:, 0][ + (i + j) * num_steps : (i + j) * num_steps + num_steps + ], + self.target_data_[:, 1][ + (i + j) * num_steps : (i + j) * num_steps + num_steps + ], + label=f"Target ID {self.generated_category[i + j]}", + color="g", + ) + ax[i, j].legend() + + plt.autoscale(True, axis="y", tight=False) + plt.show() + + return predicted_data + + elif self.model_type == "vaegan" or "custom": + return NotImplementedError diff --git a/traja/models/losses.py b/traja/models/losses.py new file mode 100644 index 00000000..e0b51752 --- /dev/null +++ b/traja/models/losses.py @@ -0,0 +1,69 @@ +import torch + +device = "cuda" if torch.cuda.is_available() else "cpu" + +class Criterion: + """Implements the loss functions of Autoencoders, Variational Autoencoders and LSTM models + Huber loss is set as default for reconstruction loss, alternative is to use rmse, + Cross entropy loss used for classification + Variational loss used huber loss and unweighted KL Divergence loss""" + + def __init__(self): + + self.huber_loss = torch.nn.SmoothL1Loss(reduction="sum") + self.manhattan_loss = torch.nn.L1Loss(reduction="sum") + self.mse_loss = torch.nn.MSELoss() + self.crossentropy_loss = torch.nn.CrossEntropyLoss() + + def forecasting_criterion( + self, predicted, target, mu=None, logvar=None, loss_type="huber" + ): + """Time series forecasting model loss function + Provides loss functions huber, manhattan, mse. Adds KL divergence if mu and logvar specified. + and ae loss functions (huber_ae, manhattan_ae, mse_ae). + :param predicted: Predicted time series by the model + :param target: Target time series + :param mu: Latent variable, Mean + :param logvar: Latent variable, Log(Variance) + :param loss_type: Type of criterion (huber, manhattan, mse, huber_ae, manhattan_ae, mse_ae); Defaults: 'huber' + :return: Reconstruction loss + KLD loss (if not ae) + """ + + if mu is not None and logvar is not None: + kld = -0.5 * torch.sum(1 + logvar - mu ** 2 - logvar.exp()) + else: + kld = 0 + + if loss_type == "huber": + loss = self.huber_loss(predicted, target) + kld + elif loss_type == "manhattan": + loss = self.manhattan_loss(predicted, target) + kld + elif loss_type == "mse": + loss = self.mse_loss(predicted, target) + kld + else: + raise Exception("Loss type '{}' is unknown!".format(loss_type)) + return loss + + def classifier_criterion(self, predicted, target): + """ + Classifier loss function + :param predicted: Predicted label + :param target: Target label + :return: Cross entropy loss + """ + + predicted = predicted.to(device) + target = target.to(device) + loss = self.crossentropy_loss(predicted, target.view(-1)) + return loss + + def regressor_criterion(self, predicted, target): + """ + Regressor loss function + :param predicted: Predicted parameter value + :param target: Target parameter value + :return: MSE loss + """ + + loss = self.mse_loss(predicted, target) + return loss diff --git a/traja/models/manifold.py b/traja/models/manifold.py new file mode 100644 index 00000000..37497f9e --- /dev/null +++ b/traja/models/manifold.py @@ -0,0 +1,10 @@ +class Manifold: + """Wrap all the manifold functionalities provided by scikit learn. Provide interface to apply non-linear dimensionality reduction techniques, + visualize and infer the strucure of the data using neural networks + """ + + def __init__(self, manifold_type): + pass + + def __new__(cls): + pass diff --git a/traja/models/optimizers.py b/traja/models/optimizers.py new file mode 100644 index 00000000..b967583a --- /dev/null +++ b/traja/models/optimizers.py @@ -0,0 +1,153 @@ +import torch +from torch.optim.lr_scheduler import ReduceLROnPlateau + + +class Optimizer: + def __init__(self, model_type, model, optimizer_type, classify=False): + + """ + Wrapper for setting the model optimizer and learning rate schedulers using ReduceLROnPlateau; + If the model type is 'ae' or 'vae' - var optimizers is a dict with separate optimizers for encoder, decoder, + latent and classifier. In case of 'lstm', var optimizers is an optimizer for lstm and TimeDistributed(linear layer) + :param model_type: Type of model 'ae', 'vae' or 'lstm' + :param model: Model instance + :param classify: If True, will return the Optimizer and scheduler for classifier + + :param optimizer_type: Optimizer to be used; Should be one in ['Adam', 'Adadelta', 'Adagrad', 'AdamW', 'SparseAdam', 'RMSprop', 'Rprop', + 'LBFGS', 'ASGD', 'Adamax'] + """ + + assert isinstance(model, torch.nn.Module) + assert str(optimizer_type) in [ + "Adam", + "Adadelta", + "Adagrad", + "AdamW", + "SparseAdam", + "RMSprop", + "Rprop", + "LBFGS", + "ASGD", + "Adamax", + ] + + self.model_type = model_type + self.model = model + self.optimizer_type = optimizer_type + self.classify = classify + self.optimizers = {} + self.forecasting_schedulers = {} + self.classification_schedulers = {} + self.regression_schedulers = {} + + self.forecasting_keys = ["encoder", "decoder", "latent"] + self.classification_keys = ["classifier"] + self.regression_keys = ["regressor"] + + def get_optimizers(self, lr=0.0001): + """Optimizers for each network in the model + + Args: + + lr (float, optional): Optimizer learning rate. Defaults to 0.0001. + + Returns: + dict: Optimizers + + """ + + if self.model_type in ["lstm", "custom"]: + self.optimizers["encoder"] = getattr(torch.optim, f"{self.optimizer_type}")( + self.model.parameters(), lr=lr + ) + + elif self.model_type in ["ae", "vae"]: + keys = ["encoder", "decoder", "latent", "classifier", "regressor"] + for key in keys: + network = getattr(self.model, f"{key}", None) + if network is not None: + self.optimizers[key] = getattr( + torch.optim, f"{self.optimizer_type}" + )(network.parameters(), lr=lr) + + elif self.model_type == "vaegan": + return NotImplementedError + + else: # self.model_type == "irl": + return NotImplementedError + + forecasting_optimizers = [ + self.optimizers[key] + for key in self.forecasting_keys + if key in self.optimizers + ] + classification_optimizers = [ + self.optimizers[key] + for key in self.classification_keys + if key in self.optimizers + ] + regression_optimizers = [ + self.optimizers[key] + for key in self.regression_keys + if key in self.optimizers + ] + return forecasting_optimizers, classification_optimizers, regression_optimizers + + def get_lrschedulers(self, factor: float, patience: int): + + """Learning rate scheduler for each network in the model + NOTE: Scheduler metric should be test set loss + + Args: + factor (float, optional): [description]. Defaults to 0.1. + patience (int, optional): [description]. Defaults to 10. + + Returns: + [dict]: Learning rate schedulers + + """ + + if self.model_type == "irl" or self.model_type == "vaegan": + return NotImplementedError + + forecasting_keys = [ + key for key in self.forecasting_keys if key in self.optimizers + ] + classification_keys = [ + key for key in self.classification_keys if key in self.optimizers + ] + regression_keys = [ + key for key in self.regression_keys if key in self.optimizers + ] + + for network in forecasting_keys: + self.forecasting_schedulers[network] = ReduceLROnPlateau( + self.optimizers[network], + mode="max", + factor=factor, + patience=patience, + verbose=True, + ) + for network in classification_keys: + self.classification_schedulers[network] = ReduceLROnPlateau( + self.optimizers[network], + mode="max", + factor=factor, + patience=patience, + verbose=True, + ) + + for network in regression_keys: + self.regression_schedulers[network] = ReduceLROnPlateau( + self.optimizers[network], + mode="max", + factor=factor, + patience=patience, + verbose=True, + ) + + return ( + self.forecasting_schedulers, + self.classification_schedulers, + self.regression_schedulers, + ) diff --git a/traja/models/predictive_models/__init__.py b/traja/models/predictive_models/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/traja/models/predictive_models/ae.py b/traja/models/predictive_models/ae.py new file mode 100644 index 00000000..3ffacd18 --- /dev/null +++ b/traja/models/predictive_models/ae.py @@ -0,0 +1,434 @@ +import torch + +from traja.models.base_models.MLPClassifier import MLPClassifier +from traja.models.base_models.MLPRegressor import MLPRegressor +from traja.models.utils import TimeDistributed + +device = "cuda" if torch.cuda.is_available() else "cpu" + + +class LSTMEncoder(torch.nn.Module): + """Implementation of Encoder network using LSTM layers + Parameters: + ----------- + input_size: The number of expected features in the input x + num_past: Number of time steps to look backwards to predict num_future steps forward + batch_size: Number of samples in a batch + hidden_size: The number of features in the hidden state h + num_lstm_layers: Number of layers in the LSTM model + + batch_first: If True, then the input and output tensors are provided as (batch, seq, feature) + dropout: If non-zero, introduces a Dropout layer on the outputs of each LSTM layer except the last layer, + with dropout probability equal to dropout + reset_state: If True, will reset the hidden and cell state for each batch of data + bidirectional: If True, becomes a bidirectional LSTM + """ + + def __init__( + self, + input_size: int, + num_past: int, + batch_size: int, + hidden_size: int, + num_lstm_layers: int, + batch_first: bool, + dropout: float, + reset_state: bool, + bidirectional: bool, + ): + super(LSTMEncoder, self).__init__() + + self.input_size = input_size + self.num_past = num_past + self.batch_size = batch_size + self.hidden_size = hidden_size + self.num_lstm_layers = num_lstm_layers + self.batch_first = batch_first + self.dropout = dropout + self.reset_state = reset_state + self.bidirectional = bidirectional + + self.lstm_encoder = torch.nn.LSTM( + input_size=input_size, + hidden_size=self.hidden_size, + num_layers=num_lstm_layers, + dropout=dropout, + bidirectional=self.bidirectional, + batch_first=True, + ) + + def _init_hidden(self): + return ( + torch.zeros(self.num_lstm_layers, self.batch_size, self.hidden_size) + .requires_grad_() + .to(device), + torch.zeros(self.num_lstm_layers, self.batch_size, self.hidden_size) + .requires_grad_() + .to(device), + ) + + def forward(self, x): + (h0, c0) = self._init_hidden() + enc_output, _ = self.lstm_encoder(x, (h0.detach(), c0.detach())) + # RNNs obeys, Markovian. So, the last state of the hidden is the markovian state for the entire + # sequence in that batch. + enc_output = enc_output[:, -1, :] # Shape(batch_size,hidden_dim) + return enc_output + + +class DisentangledAELatent(torch.nn.Module): + """Dense Dientangled Latent Layer between encoder and decoder""" + + def __init__(self, hidden_size: int, latent_size: int, dropout: float): + super(DisentangledAELatent, self).__init__() + self.latent_size = latent_size + self.hidden_size = hidden_size + self.dropout = dropout + self.latent = torch.nn.Linear(self.hidden_size, self.latent_size) + + def forward(self, x): + z = self.latent(x) # Shape(batch_size, latent_size*2) + return z + + +class LSTMDecoder(torch.nn.Module): + """Implementation of Decoder network using LSTM layers + Parameters: + ------------ + input_size: The number of expected features in the input x + num_future: Number of time steps to be predicted given the num_past steps + batch_size: Number of samples in a batch + hidden_size: The number of features in the hidden state h + num_lstm_layers: Number of layers in the LSTM model + output_size: Number of expectd features in the output x_ + batch_first: If True, then the input and output tensors are provided as (batch, seq, feature) + dropout: If non-zero, introduces a Dropout layer on the outputs of each LSTM layer except the last layer, + with dropout probability equal to dropout + reset_state: If True, will reset the hidden and cell state for each batch of data + bidirectional: If True, becomes a bidirectional LSTM + + """ + + def __init__( + self, + batch_size: int, + num_future: int, + hidden_size: int, + num_lstm_layers: int, + output_size: int, + latent_size: int, + batch_first: bool, + dropout: float, + reset_state: bool, + bidirectional: bool, + ): + super(LSTMDecoder, self).__init__() + self.batch_size = batch_size + self.latent_size = latent_size + self.num_future = num_future + self.hidden_size = hidden_size + self.num_lstm_layers = num_lstm_layers + self.output_size = output_size + self.batch_first = batch_first + self.dropout = dropout + self.reset_state = reset_state + self.bidirectional = bidirectional + + # RNN decoder + self.lstm_decoder = torch.nn.LSTM( + input_size=self.latent_size, + hidden_size=self.hidden_size, + num_layers=self.num_lstm_layers, + dropout=self.dropout, + bidirectional=self.bidirectional, + batch_first=True, + ) + self.output = TimeDistributed( + torch.nn.Linear(self.hidden_size, self.output_size) + ) + + def _init_hidden(self): + return ( + torch.zeros(self.num_lstm_layers, self.batch_size, self.hidden_size) + .requires_grad_() + .to(device), + torch.zeros(self.num_lstm_layers, self.batch_size, self.hidden_size) + .requires_grad_() + .to(device), + ) + + def forward(self, x, num_future=None): + + # To feed the latent states into lstm decoder, + # repeat the tensor n_future times at second dim + (h0, c0) = self._init_hidden() + decoder_inputs = x.unsqueeze(1) + + if num_future is None: + decoder_inputs = decoder_inputs.repeat(1, self.num_future, 1) + else: # For multistep a prediction after training + decoder_inputs = decoder_inputs.repeat(1, num_future, 1) + + # Decoder input Shape(batch_size, num_futures, latent_size) + dec, _ = self.lstm_decoder(decoder_inputs, (h0.detach(), c0.detach())) + + # Map the decoder output: Shape(batch_size, sequence_len, hidden_dim) + # to Time Dsitributed Linear Layer + output = self.output(dec) + return output + + +class MultiModelAE(torch.nn.Module): + """Implementation of Multimodel autoencoders; This Module wraps the Autoencoder + models [Encoder,Latent,Decoder]. If classify=True, then the wrapper also include classification layers + + Parameters: + ----------- + input_size: The number of expected features in the input x + num_future: Number of time steps to be predicted given the num_past steps + batch_size: Number of samples in a batch + hidden_size: The number of features in the hidden state h + num_lstm_layers: Number of layers in the LSTM model + output_size: Number of expectd features in the output x_ + batch_first: If True, then the input and output tensors are provided as (batch, seq, feature) + dropout: If non-zero, introduces a Dropout layer on the outputs of each LSTM layer except the last layer, + with dropout probability equal to dropout + reset_state: If True, will reset the hidden and cell state for each batch of data + bidirectional: If True, becomes a bidirectional LSTM + + """ + + def __init__( + self, + input_size: int, + num_past: int, + batch_size: int, + num_future: int, + lstm_hidden_size: int, + num_lstm_layers: int, + output_size: int, + latent_size: int, + batch_first: bool, + dropout: float, + reset_state: bool, + bidirectional: bool = False, + num_classifier_layers: int = None, + classifier_hidden_size: int = None, + num_classes: int = None, + num_regressor_layers: int = None, + regressor_hidden_size: int = None, + num_regressor_parameters: int = None, + ): + + super(MultiModelAE, self).__init__() + self.input_size = input_size + self.num_past = num_past + self.batch_size = batch_size + self.latent_size = latent_size + self.num_future = num_future + self.lstm_hidden_size = lstm_hidden_size + self.num_lstm_layers = num_lstm_layers + self.num_classifier_layers = num_classifier_layers + self.classifier_hidden_size = classifier_hidden_size + self.output_size = output_size + self.num_classes = num_classes + self.batch_first = batch_first + self.dropout = dropout + self.reset_state = reset_state + self.bidirectional = bidirectional + self.num_regressor_layers = num_regressor_layers + self.regressor_hidden_size = regressor_hidden_size + self.num_regressor_parameters = num_regressor_parameters + + # Let the trainer know what kind of model this is + self.model_type = "ae" + + self.encoder = LSTMEncoder( + input_size=self.input_size, + num_past=self.num_past, + batch_size=self.batch_size, + hidden_size=self.lstm_hidden_size, + num_lstm_layers=self.num_lstm_layers, + batch_first=self.batch_first, + dropout=self.dropout, + reset_state=True, + bidirectional=self.bidirectional, + ) + + self.latent = DisentangledAELatent( + hidden_size=self.lstm_hidden_size, + latent_size=self.latent_size, + dropout=self.dropout, + ) + + self.decoder = LSTMDecoder( + batch_size=self.batch_size, + num_future=self.num_future, + hidden_size=self.lstm_hidden_size, + num_lstm_layers=self.num_lstm_layers, + output_size=self.output_size, + latent_size=self.latent_size, + batch_first=self.batch_first, + dropout=self.dropout, + reset_state=True, + bidirectional=self.bidirectional, + ) + + if self.num_classes is not None: + self.classifier = MLPClassifier( + input_size=self.latent_size, + hidden_size=self.classifier_hidden_size, + output_size=self.num_classes, + num_layers=self.num_classifier_layers, + dropout=self.dropout, + ) + + if self.num_regressor_parameters is not None: + self.regressor = MLPRegressor( + input_size=self.latent_size, + hidden_size=self.regressor_hidden_size, + output_size=self.num_regressor_parameters, + num_layers=self.num_regressor_layers, + dropout=self.dropout, + ) + + def reset_classifier(self, classifier_hidden_size: int, num_classifier_layers: int): + """Reset the classifier, with a new hidden size and depth. + This is useful when parameter searching. + + classifier_hidden_size: The number of units in each classifier layer + num_layers: Number of layers in the classifier + """ + self.classifier_hidden_size = classifier_hidden_size + self.num_classifier_layers = num_classifier_layers + + self.classifier = MLPClassifier( + input_size=self.latent_size, + hidden_size=self.classifier_hidden_size, + output_size=self.num_classes, + num_layers=self.num_classifier_layers, + dropout=self.dropout, + ) + + def reset_regressor(self, regressor_hidden_size: int, num_regressor_layers: int): + """Reset the regressor, with a new hidden size and depth. + This is useful when parameter searching. + + regressor_hidden_size: The number of units in each classifier layer + num_regressor_layers: Number of layers in the classifier + """ + self.num_regressor_layers = num_regressor_layers + self.regressor_hidden_size = regressor_hidden_size + + self.regressor = MLPRegressor( + input_size=self.latent_size, + hidden_size=self.regressor_hidden_size, + output_size=self.num_regressor_parameters, + num_layers=self.num_regressor_layers, + dropout=self.dropout, + ) + + def get_ae_parameters(self): + """ + Return: + ------- + Tuple of parameters of the encoder, latent and decoder networks + """ + return [ + self.encoder.parameters(), + self.latent.parameters(), + self.decoder.parameters(), + ] + + def get_classifier_parameters(self): + """ + Return: + ------- + Tuple of parameters of classifier network + """ + assert self.classifier_hidden_size is not None, "Classifier not found" + return [self.classifier.parameters()] + + def forward(self, data, classify=False, regress=False, training=True, latent=True): + """ + Parameters: + ----------- + data: Train or test data + training: If Training= False, latents are deterministic; This arg is unused; + classify: If True, perform classification of input data using the latent embeddings + Return: + ------- + decoder_out,latent_out or classifier out + """ + assert not (classify and regress), "Model cannot both classify and regress!" + + if not (classify or regress): + # Set the classifier and regressor grads off + if self.num_classes is not None: + for param in self.classifier.parameters(): + param.requires_grad = False + if self.num_regressor_parameters is not None: + for param in self.regressor.parameters(): + param.requires_grad = False + + for param in self.encoder.parameters(): + param.requires_grad = True + for param in self.decoder.parameters(): + param.requires_grad = True + for param in self.latent.parameters(): + param.requires_grad = True + + # Encoder -->Latent --> Decoder + enc_out = self.encoder(data) + latent_out = self.latent(enc_out) + decoder_out = self.decoder(latent_out) + if latent: + return decoder_out, latent_out + else: + return decoder_out + + elif classify: # Classify + # Unfreeze classifier and freeze the rest + assert self.num_classifier_layers is not None, "Classifier not found" + + for param in self.classifier.parameters(): + param.requires_grad = True + if self.num_regressor_parameters is not None: + for param in self.regressor.parameters(): + param.requires_grad = False + for param in self.encoder.parameters(): + param.requires_grad = False + for param in self.decoder.parameters(): + param.requires_grad = False + for param in self.latent.parameters(): + param.requires_grad = False + + # Encoder-->Latent-->Classifier + enc_out = self.encoder(data) + latent_out = self.latent(enc_out) + + classifier_out = self.classifier(latent_out) # Deterministic + return classifier_out + + elif regress: + # Unfreeze regressor and freeze the rest + assert self.num_regressor_layers is not None, "Regressor not found" + + if self.num_classes is not None: + for param in self.classifier.parameters(): + param.requires_grad = False + for param in self.regressor.parameters(): + param.requires_grad = True + for param in self.encoder.parameters(): + param.requires_grad = False + for param in self.decoder.parameters(): + param.requires_grad = False + for param in self.latent.parameters(): + param.requires_grad = False + + # Encoder-->Latent-->Regressor + enc_out = self.encoder(data) + latent_out = self.latent(enc_out) + + regressor_out = self.regressor(latent_out) # Deterministic + return regressor_out diff --git a/traja/models/predictive_models/lstm.py b/traja/models/predictive_models/lstm.py new file mode 100644 index 00000000..1df554e0 --- /dev/null +++ b/traja/models/predictive_models/lstm.py @@ -0,0 +1,94 @@ +"""Implementation of Multimodel LSTM""" +import torch + +from traja.models.utils import TimeDistributed + +device = "cuda" if torch.cuda.is_available() else "cpu" + + +class LSTM(torch.nn.Module): + """Deep LSTM network. This implementation + returns output_size outputs. + Args: + input_size: The number of expected features in the input ``x`` + hidden_size: The number of features in the hidden state ``h`` + output_size: The number of output dimensions + batch_size: Size of batch. Default is 8 + sequence_length: The number of in each sample + num_layers: Number of recurrent layers. E.g., setting ``num_layers=2`` + would mean stacking two LSTMs together to form a `stacked LSTM`, + with the second LSTM taking in outputs of the first LSTM and + computing the final results. Default: 1 + reset_state: If ``True``, will reset the hidden and cell state for each batch of data + dropout: If non-zero, introduces a `Dropout` layer on the outputs of each + LSTM layer except the last layer, with dropout probability equal to + :attr:`dropout`. Default: 0 + bidirectional: If ``True``, becomes a bidirectional LSTM. Default: ``False`` + """ + + def __init__( + self, + input_size: int, + hidden_size: int, + output_size: int, + num_future: int = 8, + batch_size: int = 8, + num_layers: int = 1, + reset_state: bool = True, + bidirectional: bool = False, + dropout: float = 0, + batch_first: bool = True, + ): + super(LSTM, self).__init__() + + self.batch_size = batch_size + self.input_size = input_size + self.num_past = num_future # num_past and num_future are equal + self.num_future = num_future + self.hidden_size = hidden_size + self.num_layers = num_layers + self.output_size = output_size + self.dropout = dropout + self.batch_first = batch_first + self.reset_state = reset_state + self.bidirectional = bidirectional + + # Let the trainer know what kind of model this is + self.model_type = "lstm" + + # RNN decoder + self.lstm = torch.nn.LSTM( + input_size=self.input_size, + hidden_size=self.hidden_size, + num_layers=self.num_layers, + dropout=self.dropout, + bidirectional=self.bidirectional, + batch_first=True, + ) + self.output = TimeDistributed( + torch.nn.Linear(self.hidden_size, self.output_size) + ) + + def _init_hidden(self): + return ( + torch.zeros(self.num_layers, self.batch_size, self.hidden_size) + .requires_grad_() + .to(device), + torch.zeros(self.num_layers, self.batch_size, self.hidden_size) + .requires_grad_() + .to(device), + ) + + def forward(self, x, training=True, classify=False, regress=False, latent=False): + assert not classify, "LSTM forecaster cannot classify!" + assert not regress, "LSTM forecaster cannot regress!" + assert not latent, "LSTM forecaster does not have a latent space!" + # To feed the latent states into lstm decoder, repeat the tensor n_future times at second dim + (h0, c0) = self._init_hidden() + + # Decoder input Shape(batch_size, num_futures, latent_size) + out, (dec_hidden, dec_cell) = self.lstm(x, (h0.detach(), c0.detach())) + + # Map the decoder output: Shape(batch_size, sequence_len, hidden_dim) to Time Distributed Linear Layer + out = self.output(out) + return out diff --git a/traja/models/train.py b/traja/models/train.py new file mode 100644 index 00000000..4c753d56 --- /dev/null +++ b/traja/models/train.py @@ -0,0 +1,456 @@ +import torch + +from . import utils +from .losses import Criterion +from .optimizers import Optimizer + +device = "cuda" if torch.cuda.is_available() else "cpu" + + +class HybridTrainer(object): + """ + Wrapper for training and testing the LSTM model + Args: + optimizer_type: Type of optimizer to use for training.Should be from ['Adam', 'Adadelta', 'Adagrad', + 'AdamW', 'SparseAdam', 'RMSprop', ' + Rprop', 'LBFGS', 'ASGD', 'Adamax'] + device: Selected device; 'cuda' or 'cpu' + input_size: The number of expected features in the input x + output_size: Output feature dimension + lstm_hidden_size: The number of features in the hidden state h + num_lstm_layers: Number of layers in the LSTM model + reset_state: If True, will reset the hidden and cell state for each batch of data + output_size: Number of sequence_ids/labels + latent_size: Latent space dimension + dropout: If non-zero, introduces a Dropout layer on the outputs of each LSTM layer except the last layer, + with dropout probability equal to dropout + num_layers: Number of layers in the classifier + batch_size: Number of samples in a batch + num_future: Number of time steps to be predicted forward + num_past: Number of past time steps otherwise, length of sequences in each batch of data. + bidirectional: If True, becomes a bidirectional LSTM + batch_first: If True, then the input and output tensors are provided as (batch, seq, feature) + loss_type: Type of reconstruction loss to apply, 'huber' or 'rmse'. Default:'huber' + lr_factor: Factor by which the learning rate will be reduced + scheduler_patience: Number of epochs with no improvement after which learning rate will be reduced. + For example, if patience = 2, then we will ignore the first 2 epochs with no + improvement, and will only decrease the LR after the 3rd epoch if the loss still + hasnā€™t improved then. + + """ + + valid_models = ["ae", "vae", "lstm"] + + def __init__( + self, + model: torch.nn.Module, + optimizer_type: str, + loss_type: str = "huber", + lr: float = 0.001, + lr_factor: float = 0.1, + scheduler_patience: int = 10, + ): + + assert ( + model.model_type in HybridTrainer.valid_models + ), "Model type is {model_type}, valid models are {}".format( + HybridTrainer.valid_models + ) + + self.model_type = model.model_type + self.loss_type = loss_type + self.optimizer_type = optimizer_type + self.lr = lr + self.lr_factor = lr_factor + self.scheduler_patience = scheduler_patience + + if model.model_type == "lstm": + self.model_hyperparameters = { + "input_size": model.input_size, + "batch_size": model.batch_size, + "hidden_size": model.hidden_size, + "num_future": model.num_future, + "num_layers": model.num_layers, + "output_size": model.output_size, + "batch_first": model.batch_first, + "reset_state": model.reset_state, + "bidirectional": model.bidirectional, + "dropout": model.dropout, + } + else: + self.model_hyperparameters = { + "input_size": model.input_size, + "num_past": model.num_past, + "batch_size": model.batch_size, + "lstm_hidden_size": model.lstm_hidden_size, + "num_lstm_layers": model.num_lstm_layers, + "classifier_hidden_size": model.classifier_hidden_size, + "num_classifier_layers": model.num_classifier_layers, + "num_future": model.num_future, + "latent_size": model.latent_size, + "output_size": model.output_size, + "num_classes": model.num_classes, + "batch_first": model.batch_first, + "reset_state": model.reset_state, + "bidirectional": model.bidirectional, + "dropout": model.dropout, + } + + self.model = model + # Classification, regression task checks + self.classify = ( + True + if model.model_type != "lstm" and model.classifier_hidden_size is not None + else False + ) + self.regress = ( + True + if model.model_type != "lstm" and model.regressor_hidden_size is not None + else False + ) + + # Model optimizer and the learning rate scheduler + optimizer = Optimizer( + self.model_type, self.model, self.optimizer_type, classify=self.classify + ) + + ( + self.forecasting_optimizers, + self.classification_optimizers, + self.regression_optimizers, + ) = optimizer.get_optimizers(lr=self.lr) + ( + self.forecasting_schedulers, + self.classification_schedulers, + self.regression_schedulers, + ) = optimizer.get_lrschedulers( + factor=self.lr_factor, patience=self.scheduler_patience + ) + + def __str__(self): + return f"Training model type {self.model_type}" + + def fit( + self, dataloaders, model_save_path=None, training_mode="forecasting", epochs=50, test_every=10, validate_every=None + ): + """ + This method implements the batch- wise training and testing protocol for both time series forecasting and + classification of the timeseriesis_classification + + Parameters: + ----------- + dataloaders: Dictionary containing train and test dataloaders + train_loader: Dataloader object of train dataset with batch data [data,target,ids] + test_loader: Dataloader object of test dataset with [data,target,ids] + model_save_path: Directory path to save the model + training_mode: Type of training ('forecasting', 'classification') + epochs: Number of epochs to train + test_every: Run evaluation on the test set in multiple of 'test_every' epochs. + validate_every: Run evaluation on the validation set in multiple of 'validate_every' epochs, + if evaluation on test-set is not required for current epoch. + """ + + assert model_save_path is not None, f"Model path {model_save_path} unknown" + assert training_mode in [ + "forecasting", + "classification", + "regression", + ], f"Training mode {training_mode} unknown" + + self.model.to(device) + + train_loader = dataloaders["train_loader"] + test_loader = dataloaders["test_loader"] + if 'validation_loader' in dataloaders: + validation_loader = dataloaders['validation_loader'] + else: + validate_every = None + + # Training + for epoch in range(epochs + 1): + eval_loss_forecasting = 0 + eval_loss_classification = 0 + eval_loss_regression = 0 + if epoch > 0: # Initial step is to test and set LR schduler + # Training + self.model.train() + total_loss = 0 + for idx, (data, target, ids, parameters, classes) in enumerate( + train_loader + ): + # Reset optimizer states + for optimizer in self.forecasting_optimizers: + optimizer.zero_grad() + if self.classify: + for optimizer in self.classification_optimizers: + optimizer.zero_grad() + if self.regress: + for optimizer in self.regression_optimizers: + optimizer.zero_grad() + + if type(ids) == list: + ids = ids[0] + data, target, ids, parameters = ( + data.float().to(device), + target.float().to(device), + ids.to(device), + parameters.float().to(device), + ) + + if training_mode == "forecasting": + if self.model_type == "ae" or self.model_type == "lstm": + decoder_out = self.model( + data, training=True, classify=False, latent=False + ) + loss = Criterion().forecasting_criterion( + decoder_out, target, loss_type=self.loss_type + ) + else: # vae + decoder_out, latent_out, mu, logvar = self.model( + data, training=True, classify=False + ) + loss = Criterion().forecasting_criterion( + decoder_out, + target, + mu=mu, + logvar=logvar, + loss_type=self.loss_type, + ) + + loss.backward() + for optimizer in self.forecasting_optimizers: + optimizer.step() + + elif training_mode == "classification": + classifier_out = self.model( + data, training=True, classify=True, latent=False + ) + loss = Criterion().classifier_criterion(classifier_out, classes) + + loss.backward() + for optimizer in self.classification_optimizers: + optimizer.step() + + elif training_mode == "regression": + regressor_out = self.model( + data, training=True, regress=True, latent=False + ) + loss = Criterion().regressor_criterion( + regressor_out, parameters + ) + + loss.backward() + for optimizer in self.regression_optimizers: + optimizer.step() + + total_loss += loss + + print( + "Epoch {} | {} loss {}".format( + epoch, training_mode, total_loss / len(train_loader.dataset) + ) + ) + + # Testing & Validation + evaluate_for_this_epoch = False + data_loader_to_evaluate = test_loader + current_set = "Test" + if validate_every is not None: + if epoch % validate_every == validate_every - 1 and epoch != 0: + data_loader_to_evaluate = validation_loader + evaluate_for_this_epoch = True + current_set = "Validation" + if test_every is not None: + if epoch % test_every == test_every - 1 and epoch != 0: + data_loader_to_evaluate = test_loader + evaluate_for_this_epoch = True + current_set = "Test" + + if evaluate_for_this_epoch: + with torch.no_grad(): + if self.classify: + total = 0.0 + correct = 0.0 + self.model.eval() + for idx, (data, target, ids, parameters, classes) in enumerate( + data_loader_to_evaluate + ): + if type(ids) == list: + ids = ids[0] + data, target, ids, parameters = ( + data.float().to(device), + target.float().to(device), + ids.to(device), + parameters.float().to(device), + ) + # Time series forecasting test + if self.model_type == "ae" or self.model_type == "lstm": + out = self.model( + data, training=False, classify=False, latent=False + ) + eval_loss_forecasting += ( + Criterion() + .forecasting_criterion( + out, target, loss_type=self.loss_type + ) + .item() + ) + + else: + decoder_out, latent_out, mu, logvar = self.model( + data, training=False, classify=False, latent=True + ) + eval_loss_forecasting += Criterion().forecasting_criterion( + decoder_out, + target, + mu=mu, + logvar=logvar, + loss_type=self.loss_type, + ) + + # Classification test + if self.classify: + ids = ids.long() + classifier_out = self.model( + data, training=False, classify=True, latent=False + ) + + eval_loss_classification += ( + Criterion() + .classifier_criterion(classifier_out, classes) + .item() + ) + + # Compute number of correct samples + total += ids.size(0) + _, predicted = torch.max(classifier_out.data, 1) + + correct += (predicted.cpu() == classes.cpu().T).sum().item() + + if self.regress: + regressor_out = self.model( + data, training=False, regress=True, latent=False + ) + eval_loss_regression += Criterion().regressor_criterion( + regressor_out, parameters + ) + + eval_loss_forecasting /= len(data_loader_to_evaluate.dataset) + print( + f"====> Mean {current_set} set forecasting loss: {eval_loss_forecasting:.4f}" + ) + if self.classify: + accuracy = correct / total + if eval_loss_classification != 0: + eval_loss_classification /= len(data_loader_to_evaluate.dataset) + print( + f"====> Mean {current_set} set classifier loss: {eval_loss_classification:.4f}; accuracy: {accuracy:.2f}" + ) + + if self.regress: + print( + f"====> Mean {current_set} set regressor loss: {eval_loss_regression:.4f}" + ) + + # Scheduler metric is test set loss + if current_set == "Test" and training_mode == "forecasting": + for scheduler in self.forecasting_schedulers.values(): + scheduler.step(eval_loss_forecasting) + elif current_set == "Test" and training_mode == "classification": + for scheduler in self.classification_schedulers.values(): + scheduler.step(eval_loss_classification) + elif current_set == "Test" and training_mode == "regression": + for scheduler in self.regression_schedulers.values(): + scheduler.step(eval_loss_regression) + + # Save the model at target path + utils.save(self.model, self.model_hyperparameters, path=model_save_path) + + def validate(self, validation_loader): + # Perform model validation + validation_loss_forecasting = 0.0 + validation_loss_classification = 0.0 + validation_loss_regression = 0.0 + with torch.no_grad(): + if self.classify: + total = 0.0 + correct = 0.0 + self.model.eval() + for idx, (data, target, ids, parameters, classes) in enumerate( + validation_loader + ): + if type(ids) == list: + ids = ids[0] + data, target, ids, parameters = ( + data.float().to(device), + target.float().to(device), + ids.to(device), + parameters.float().to(device), + ) + # Time series forecasting test + if self.model_type == "ae" or self.model_type == "lstm": + out = self.model(data, training=False, classify=False, latent=False) + validation_loss_forecasting += ( + Criterion() + .forecasting_criterion(out, target, loss_type=self.loss_type) + .item() + ) + + else: + decoder_out, latent_out, mu, logvar = self.model( + data, training=False, classify=False + ) + validation_loss_forecasting += Criterion().forecasting_criterion( + decoder_out, + target, + mu=mu, + logvar=logvar, + loss_type=self.loss_type, + ) + + # Classification test + if self.classify: + ids = ids.long() + classifier_out = self.model( + data, training=False, classify=True, latent=False + ) + + validation_loss_classification += ( + Criterion().classifier_criterion(classifier_out, classes).item() + ) + + # Compute number of correct samples + total += ids.size(0) + _, predicted = torch.max(classifier_out.data, 1) + correct += (predicted.cpu() == classes.cpu().T).sum().item() + + if self.regress: + regressor_out = self.model( + data, training=True, regress=True, latent=False + ) + validation_loss_regression += Criterion().regressor_criterion( + regressor_out, parameters + ) + + validation_loss_forecasting /= len(validation_loader.dataset) + print( + f"====> Mean Validation set generator loss: {validation_loss_forecasting:.4f}" + ) + if self.classify: + accuracy = correct / total + if validation_loss_classification != 0: + validation_loss_classification /= len(validation_loader.dataset) + print( + f"====> Mean Validation set classifier loss: {validation_loss_classification:.4f}; accuracy: {accuracy:.4f}" + ) + + if self.regress: + print( + f"====> Mean Validation set regressor loss: {validation_loss_regression:.4f}" + ) + + return ( + validation_loss_forecasting, + validation_loss_regression, + validation_loss_classification, + ) diff --git a/traja/models/utils.py b/traja/models/utils.py new file mode 100644 index 00000000..2680f2ab --- /dev/null +++ b/traja/models/utils.py @@ -0,0 +1,100 @@ +import json +import os + +import torch + + +class TimeDistributed(torch.nn.Module): + """ Time distributed wrapper compatible with linear/dense pytorch layer modules""" + + def __init__(self, module, batch_first=True): + super(TimeDistributed, self).__init__() + self.module = module + self.batch_first = batch_first + + def forward(self, x): + + # Linear layer accept 2D input + if len(x.size()) <= 2: + return self.module(x) + + # Squash samples and timesteps into a single axis + x_reshape = x.contiguous().view( + -1, x.size(-1) + ) # (samples * timesteps, input_size) + out = self.module(x_reshape) + + # We have to reshape Y back to the target shape + if self.batch_first: + out = out.contiguous().view( + x.size(0), -1, out.size(-1) + ) # (samples, timesteps, output_size) + else: + out = out.view( + -1, x.size(1), out.size(-1) + ) # (timesteps, samples, output_size) + + return out + + +def save(model, hyperparameters, path:str=""): + """Save the trained model(.pth) along with its hyperparameters as a json (hyper.json) at the user defined Path + Parameters: + ----------- + model (torch.nn.Module): Trained Model + hyperparameters(dict): Hyperparameters of the model + path (str): Directory path to save the trained model and its hyperparameters + Returns: + --------- + None + """ + + if hyperparameters is not None and not isinstance(hyperparameters, dict): + raise Exception("Invalid argument, hyperparameters must be dict") + # Save + if path == "": + path = os.path.join(os.getcwd(), "model.pt") + torch.save(model.state_dict(), path) + + hyperdir, _ = os.path.split(path) + if hyperparameters is not None: + with open(os.path.join(hyperdir, "hypers.json"), "w") as fp: + json.dump(hyperparameters, fp, sort_keys=False) + if hyperdir == "": + hyperdir = "." + print(f"Model and hyperparameters saved at {os.path.abspath(hyperdir)}") + + +def load(model, path: str=""): + """Load trained model from path using the model_hyperparameters saved in the + Parameters: + ----------- + model (torch.nn.Module): Type of the model ['ae','vae','vaegan','irl','lstm','custom'] + path (str): Directory path of the model: Defaults to None: Means Current working directory + Returns: + --------- + model(torch.nn.module): Model + """ + # Hyperparameters + if path == "": + path = os.path.join(os.getcwd(), "/model.pt") + print(f"Model loaded from {path}") + else: + raise Exception(f"Model state dict not found at {path}") + + # Load state of the model + model.load_state_dict(torch.load(path)) + return model + + +def read_hyperparameters(hyperparameter_json): + """Read the json file and return the hyperparameters as dict + + Args: + hyperparameter_json (json): Json file containing the hyperparameters of the trained model + + Returns: + [dict]: Python dictionary of the hyperparameters + """ + with open(hyperparameter_json) as f_in: + return json.load(f_in) diff --git a/traja/parsers.py b/traja/parsers.py new file mode 100644 index 00000000..4135464a --- /dev/null +++ b/traja/parsers.py @@ -0,0 +1,178 @@ +from typing import Optional, Union + +import numpy as np +import pandas as pd +from pandas.core.dtypes.common import is_datetime64_any_dtype, is_timedelta64_dtype + +from traja import TrajaDataFrame + + +def from_df(df: pd.DataFrame, xcol=None, ycol=None, time_col=None, **kwargs): + """Returns a :class:`traja.frame.TrajaDataFrame` from a :class:`pandas DataFrame`. + + Args: + df (:class:`pandas.DataFrame`): Trajectory as pandas ``DataFrame`` + xcol (str) + ycol (str) + timecol (str) + + Returns: + traj_df (:class:`~traja.frame.TrajaDataFrame`): Trajectory + + .. doctest:: + + >>> df = pd.DataFrame({'x':[0,1,2],'y':[1,2,3]}) + >>> traja.from_df(df) + x y + 0 0 1 + 1 1 2 + 2 2 3 + + """ + traj_df = TrajaDataFrame(df) + + # Identify x and y columns if defined by user + if xcol and ycol: + traj_df["x"] = pd.to_numeric(traj_df[xcol], errors="coerce") + traj_df["y"] = pd.to_numeric(traj_df[ycol], errors="coerce") + if time_col: + traj_df[time_col] = pd.to_timedelta( + traj_df[time_col], unit=kwargs.get("time_units", "s") + ) + kwargs.update({"time_col": time_col}) + + # Initialize metadata + for var in traj_df._metadata: + if not hasattr(traj_df, var): + traj_df.__dict__[var] = None + + # Save additional metadata + for key, val in kwargs.items(): + traj_df.__dict__[key] = val + return traj_df + + +def read_file( + filepath: str, + id: Optional[str] = None, + xcol: Optional[str] = None, + ycol: Optional[str] = None, + parse_dates: Union[str, bool] = False, + xlim: Optional[tuple] = None, + ylim: Optional[tuple] = None, + spatial_units: str = "m", + fps: Optional[float] = None, + **kwargs, +): + """Convenience method wrapping pandas `read_csv` and initializing metadata. + + Args: + filepath (str): path to csv file with `x`, `y` and `time` (optional) columns + id (str): id for trajectory + xcol (str): name of column containing x coordinates + ycol (str): name of column containing y coordinates + parse_dates (Union[list,bool]): The behavior is as follows: + - boolean. if True -> try parsing the index. + - list of int or names. e.g. If [1, 2, 3] -> try parsing columns 1, 2, 3 each as a + separate date column. + xlim (tuple): x limits (min,max) for plotting + ylim (tuple): y limits (min,max) for plotting + spatial_units (str): for plotting (eg, 'cm') + fps (float): for time calculations + **kwargs: Additional arguments for :meth:`pandas.read_csv`. + + Returns: + traj_df (:class:`~traja.main.TrajaDataFrame`): Trajectory + + """ + date_parser = kwargs.pop("date_parser", None) + + # TODO: Set index to first column containing 'time' + df_test = pd.read_csv( + filepath, nrows=10, parse_dates=parse_dates, infer_datetime_format=True + ) + + if xcol is not None or ycol is not None: + if not xcol in df_test or ycol not in df_test: + raise Exception(f"{xcol} or {ycol} not found as headers.") + + # Strip whitespace + whitespace_cols = [c for c in df_test if " " in df_test[c].name] + stripped_cols = {c: lambda x: x.strip() for c in whitespace_cols} + converters = {**stripped_cols, **kwargs.pop("converters", {})} + + # Downcast to float32 # TODO: Benchmark float32 vs float64 for very big dataset + float_cols = df_test.select_dtypes(include=[np.float]).columns + float32_cols = {c: np.float32 for c in float_cols} + + # Convert string columns to sequence_ids + string_cols = [c for c in df_test if df_test[c].dtype == str] + category_cols = {c: "category" for c in string_cols} + dtype = {**float32_cols, **category_cols, **kwargs.pop("dtype", {})} + + # Parse time column if present + time_cols = [col for col in df_test.columns if "time" in col.lower()] + time_col = time_cols[0] if time_cols else None + + if parse_dates and not date_parser and time_col: + # try different parsers + format_strs = [ + "%Y-%m-%d %H:%M:%S:%f", + "%Y-%m-%d %H:%M:%S.%f", + "%Y-%m-%d %H:%M:%S", + ] + for format_str in format_strs: + date_parser = lambda x: pd.datetime.strptime(x, format_str) + try: + df_test = pd.read_csv( + filepath, date_parser=date_parser, nrows=10, parse_dates=[time_col] + ) + except ValueError: + pass + if is_datetime64_any_dtype(df_test[time_col]): + break + elif is_timedelta64_dtype(df_test[time_col]): + break + else: + # No datetime or timestamp column found + date_parser = None + + if "csv" in filepath: + trj = pd.read_csv( + filepath, + date_parser=date_parser, + parse_dates=parse_dates or [time_col] if date_parser else False, + converters=converters, + dtype=dtype, + **kwargs, + ) + + # TODO: Replace default column renaming with user option if needed + if time_col: + trj.rename(columns={time_col: "time"}) + elif fps is not None: + time = np.array([x for x in trj.index], dtype=int) / fps + trj["time"] = time + else: + # leave index as int frames + pass + if xcol and ycol: + trj.rename(columns={xcol: "x", ycol: "y"}) + else: + # TODO: Implement for HDF5 and .npy files. + raise NotImplementedError("Non-csv's not yet implemented") + + trj = TrajaDataFrame(trj) + + # Set meta properties of TrajaDataFrame + metadata = dict( + id=id, + xlim=xlim, + spatial_units=spatial_units, + title=kwargs.get("title", None), + xlabel=kwargs.get("xlabel", None), + ylabel=kwargs.get("ylabel", None), + fps=fps, + ) + trj.__dict__.update(**metadata) + return trj diff --git a/traja/plotting.py b/traja/plotting.py new file mode 100644 index 00000000..391d75bc --- /dev/null +++ b/traja/plotting.py @@ -0,0 +1,1497 @@ +import logging +from collections import OrderedDict +from datetime import timedelta +import os +from typing import Union, Optional, Tuple, List + +import matplotlib +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import torch + +from matplotlib import dates as md +from matplotlib.axes import Axes +from matplotlib.collections import PathCollection +from matplotlib.figure import Figure +from mpl_toolkits.mplot3d import Axes3D +from pandas.core.dtypes.common import ( + is_datetime_or_timedelta_dtype, + is_datetime64_any_dtype, + is_timedelta64_dtype, +) + +import traja +from traja.frame import TrajaDataFrame +from traja.trajectory import coords_to_flow + +__all__ = [ + "_get_after_plot_args", + "_label_axes", + "_polar_bar", + "_process_after_plot_args", + "animate", + "bar_plot", + "color_dark", + "fill_ci", + "find_runs", + "plot", + "plot_3d", + "plot_actogram", + "plot_autocorrelation", + "plot_collection", + "plot_contour", + "plot_clustermap", + "plot_flow", + "plot_pca", + "plot_periodogram", + "plot_quiver", + "plot_stream", + "plot_surface", + "plot_transition_graph", + "plot_transition_matrix", + "plot_xy", + "polar_bar", + "plot_prediction", + "sans_serif", + "stylize_axes", + "trip_grid", +] + +logger = logging.getLogger("traja") + + +def stylize_axes(ax): + """Add top and right border to plot, set ticks.""" + ax.spines["top"].set_visible(False) + ax.spines["right"].set_visible(False) + + ax.xaxis.set_tick_params(top="off", direction="out", width=1) + ax.yaxis.set_tick_params(right="off", direction="out", width=1) + + +def sans_serif(): + """Convenience function for changing plot text to serif font.""" + plt.rc("font", family="serif") + + +def _rolling(df, window, step): + count = 0 + df_length = len(df) + while count < (df_length - window): + yield count, df[count : window + count] + count += step + + +def plot_prediction(model, dataloader, index, scaler=None): + device = "cuda" if torch.cuda.is_available() else "cpu" + fig, ax = plt.subplots(2, 1, figsize=(10, 10)) + model = model.to(device) + batch_size = model.batch_size + num_past = model.num_past + input_size = model.input_size + + data, target, category, parameters, classes = list(iter(dataloader))[index] + data = data.float().to(device) + prediction = model(data, latent=False) + + # Send tensors to CPU so numpy can work with them + pred = prediction[batch_size - 1 : batch_size, :].cpu().squeeze().detach().numpy() + target = target.clone().detach()[batch_size - 1 : batch_size, :].squeeze() + real = target.cpu() + + data = data.cpu().reshape(batch_size * num_past, input_size).detach().numpy() + + if scaler: + data = scaler.inverse_transform(data) + real = scaler.inverse_transform(real) + pred = scaler.inverse_transform(pred) + + ax[0].plot(data[:, 0], data[:, 1], label="History") + ax[0].plot(real[:, 0], real[:, 1], label="Real") + ax[0].plot(pred[:, 0], pred[:, 1], label="Pred") + + ax[1].scatter(real[:, 0], real[:, 1], label="Real") + ax[1].scatter(pred[:, 0], pred[:, 1], label="Pred") + + for a in ax: + a.legend() + plt.show() + + +def bar_plot(trj: TrajaDataFrame, bins: Union[int, tuple] = None, **kwargs) -> Axes: + """Plot trajectory for single animal over period. + + Args: + trj (:class:`traja.TrajaDataFrame`): trajectory + bins (int or tuple): number of bins for x and y + **kwargs: additional keyword arguments to :meth:`mpl_toolkits.mplot3d.Axed3D.plot` + + Returns: + ax (:class:`~matplotlib.collections.PathCollection`): Axes of plot + + """ + # TODO: Add time component + + bins = traja.trajectory._bins_to_tuple(trj, bins) + + X, Y, U, V = coords_to_flow(trj, bins) + + hist, _ = trip_grid(trj, bins, hist_only=True) + fig = plt.figure() + ax = fig.add_subplot(111, projection="3d") + ax.set_aspect("equal") + X = X.flatten("F") + Y = Y.flatten("F") + ax.bar3d( + X, + Y, + np.zeros_like(X), + 1, + 1, + hist.flatten(), + zsort="average", + shade=True, + **kwargs, + ) + ax.set(xlabel="x", ylabel="y", zlabel="Frames") + + return ax + + +def plot_rolling_hull(trj: TrajaDataFrame, window=100, step=20, areas=False, **kwargs): + """Plot rolling convex hull of trajectory. If `areas` is True, only + areas over time is plotted. + + """ + hulls = [] + + for offset, window in _rolling(trj, window=window, step=step): + if window.dropna().empty: + continue + shape = window.traja.to_shapely() + hull = shape.convex_hull + hulls.append(hull) + + if areas: + hull_areas = [] + for idx, hull in enumerate(hulls): + hull_areas.append(hull.area) + plt.plot(hull_areas, **kwargs) + plt.title(f"Rolling Trajectory Convex Hull Area\nWindow={window},Step={step}") + plt.ylabel(f"Area {trj.__dict__.get('spatial_units', 'm')}") + plt.xlabel("Frame") + else: + xlim, ylim = traja.trajectory._get_xylim(trj) + plt.xlim = xlim + plt.ylim = ylim + for idx, hull in enumerate(hulls): + if hasattr( + hull, "exterior" + ): # Occassionally a Point object without it reaches + plt.plot(*hull.exterior.xy, alpha=idx / len(hulls), c="k", **kwargs) + ax = plt.gca() + ax.set_aspect("equal") + ax.set( + xlabel=f"x ({trj.__dict__.get('spatial_units', 'm')})", + ylabel=f"y ({trj.__dict__.get('spatial_units', 'm')})", + title="Rolling Trajectory Convex Hull\nWindow={window},Step={step}", + ) + + +def plot_period(trj: TrajaDataFrame, col="x", dark=(7, 19), **kwargs): + time_col = traja._get_time_col(trj) + _trj = trj.set_index(time_col) + if col not in _trj: + raise ValueError(f"{col} not a column in dataframe") + series = _trj[col] + fig, ax = plt.subplots() + series.plot(ax=ax) + + dates = np.unique(series.index.date) + + nights = [] + nights.append([(date, date + timedelta(hours=dark[0])) for date in dates]) + nights.append( + [(date + timedelta(hours=dark[1]), date + timedelta(days=1)) for date in dates] + ) + for interval in nights: + t0, t1 = interval + ax.axvspan(t0, t1, color="gray", alpha=0.2) + + # Format date displayed on the x axis + xfmt = md.DateFormatter("%H:%M\n%m-%d-%y") + ax.xaxis.set_major_formatter(xfmt) + + if kwargs.get("interactive"): + plt.show() + + +def plot_rolling_hull_3d(trj: TrajaDataFrame, window=100, step=20, **kwargs): + hulls = [] + + fig = plt.figure() + ax = fig.add_subplot(111, projection="3d") + + for offset, wind in _rolling(trj, window=window, step=step): + if wind.dropna().empty: + continue + shape = wind.traja.to_shapely() + hull = shape.convex_hull + hulls.append(hull) + + xlim, ylim = traja.trajectory._get_xylim(trj) + plt.xlim = xlim + plt.ylim = ylim + outlines = [] + for idx, hull in enumerate(hulls): + if hasattr(hull, "exterior"): # Occassionally a Point object without it reaches + outlines.append(np.array(hull.exterior.xy)) + + # Add plots to axes + NLINES = len(outlines) + cm = plt.get_cmap(kwargs.get("cmap", "plasma")) + ax.set_prop_cycle(color=[cm(1.0 * i / (NLINES)) for i in range(NLINES)]) + for z, xy in enumerate(outlines): + ax.plot(*xy, z) + + ax.set( + xlabel=f"{trj.__dict__.get('spatial_units', 'm')}", + ylabel=f"{trj.__dict__.get('spatial_units', 'm')}", + title=f"Rolling Trajectory Convex Hull\nWindow={window},Step={step}", + ) + + if kwargs.get("interactive"): + plt.show() + + +def plot_3d(trj: TrajaDataFrame, **kwargs) -> matplotlib.collections.PathCollection: + """Plot 3D trajectory for single identity over period. + + Args: + trj (:class:`traja.TrajaDataFrame`): trajectory + n_coords (int, optional): Number of coordinates to plot + **kwargs: additional keyword arguments to :meth:`matplotlib.axes.Axes.scatter` + + Returns: + ax (:class:`~matplotlib.collections.PathCollection`): Axes of plot + + .. note:: + Takes a while to plot large trajectories. Consider using first:: + + rt = trj.traja.rediscretize(R=1.) # Replace R with appropriate step length + rt.traja.plot_3d() + + """ + + fig = plt.figure() + ax = fig.add_subplot(111, projection="3d") + ax.set_xlabel("x", fontsize=15) + ax.set_zlabel("time", fontsize=15) + ax.set_ylabel("y", fontsize=15) + title = kwargs.pop("title", "Trajectory") + ax.set_title(f"{title}", fontsize=20) + ax.plot(trj.x, trj.y, trj.index) + cmap = kwargs.pop("cmap", "winter") + cm = plt.get_cmap(cmap) + NPOINTS = len(trj) + ax.set_prop_cycle(color=[cm(1.0 * i / (NPOINTS - 1)) for i in range(NPOINTS - 1)]) + for i in range(NPOINTS - 1): + ax.plot(trj.x[i : i + 2], trj.y[i : i + 2], trj.index[i : i + 2]) + + dist = kwargs.pop("dist", None) + if dist: + ax.dist = dist + labelpad = kwargs.pop("labelpad", None) + if labelpad: + from matplotlib import rcParams + + rcParams["axes.labelpad"] = labelpad + + return ax + + +def plot( + trj: TrajaDataFrame, + n_coords: Optional[int] = None, + show_time: bool = False, + accessor: Optional[traja.TrajaAccessor] = None, + ax=None, + **kwargs, +) -> matplotlib.collections.PathCollection: + """Plot trajectory for single animal over period. + + Args: + trj (:class:`traja.TrajaDataFrame`): trajectory + n_coords (int, optional): Number of coordinates to plot + show_time (bool): Show colormap as time + accessor (:class:`~traja.accessor.TrajaAccessor`, optional): TrajaAccessor instance + ax (:class:`~matplotlib.axes.Axes`): axes for plotting + interactive (bool): show plot immediately + **kwargs: additional keyword arguments to :meth:`matplotlib.axes.Axes.scatter` + + Returns: + collection (:class:`~matplotlib.collections.PathCollection`): collection that was plotted + + """ + import matplotlib.patches as patches + from matplotlib.path import Path + + after_plot_args, kwargs = _get_after_plot_args(**kwargs) + + GRAY = "#999999" + + xlim = kwargs.pop("xlim", None) + ylim = kwargs.pop("ylim", None) + if not xlim or not ylim: + xlim, ylim = traja.trajectory._get_xylim(trj) + + title = kwargs.pop("title", None) + time_units = kwargs.pop("time_units", "s") + fps = kwargs.pop("fps", None) + figsize = kwargs.pop("figsize", None) + + coords = trj[["x", "y"]] + time_col = traja.trajectory._get_time_col(trj) + + if time_col == "index": + is_datetime = True + else: + is_datetime = is_datetime64_any_dtype(trj[time_col]) if time_col else False + + if n_coords is None: + # Plot all coords + start, end = 0, len(coords) + verts = coords.iloc[start:end].values + else: + # Plot first `n_coords` + verts = coords.iloc[:n_coords].values + + n_coords = len(verts) + + codes = [Path.MOVETO] + [Path.LINETO] * (len(verts) - 1) + path = Path(verts, codes) + + if not ax: + fig, ax = plt.subplots(figsize=figsize) + fig.canvas.draw() + + patch = patches.PathPatch(path, edgecolor=GRAY, facecolor="none", lw=3, alpha=0.3) + ax.add_patch(patch) + + xs, ys = zip(*verts) + + if time_col == "index": + # DatetimeIndex determines color + colors = [ind for ind, x in enumerate(trj.index[:n_coords])] + elif time_col and time_col != "index": + # `time_col` determines color + colors = [ind for ind, x in enumerate(trj[time_col].iloc[:n_coords])] + else: + # Frame count determines color + colors = trj.index[:n_coords] + + if time_col: + # TODO: Calculate fps if not in datetime + vmin = min(colors) + vmax = max(colors) + if is_datetime: + # Show timestamps without units + time_units = "" + else: + # Index/frame count is our only reference + vmin = trj.index[0] + vmax = trj.index[n_coords - 1] + if not show_time: + time_units = "" + label = f"Time ({time_units})" if time_units else "" + + collection = ax.scatter( + xs, + ys, + c=colors, + s=kwargs.pop("s", 1), + cmap=plt.cm.viridis, + alpha=0.7, + vmin=vmin, + vmax=vmax, + **kwargs, + ) + + ax.set_xlim(xlim) + ax.set_ylim(ylim) + + if kwargs.pop("invert_yaxis", None): + plt.gca().invert_yaxis() + + _label_axes(trj, ax) + ax.set_title(title) + ax.set_aspect("equal") + + # Number of color bar ticks + CBAR_TICKS = 10 if n_coords > 20 else n_coords + indices = np.linspace(0, n_coords - 1, CBAR_TICKS, endpoint=True, dtype=int) + cbar = plt.colorbar( + collection, fraction=0.046, pad=0.04, orientation="vertical", label=label + ) + + # Get colorbar labels from time + if time_col == "index": + if is_datetime64_any_dtype(trj.index): + cbar_labels = ( + trj.index[indices].strftime("%Y-%m-%d %H:%M:%S").values.astype(str) + ) + elif is_timedelta64_dtype(trj.index): + if time_units in ("s", "", None): + cbar_labels = [round(x, 2) for x in trj.index[indices].total_seconds()] + else: + logger.error("Time unit {} not yet implemented".format(time_units)) + else: + raise NotImplementedError( + "Indexing on {} is not yet implemented".format(type(trj.index)) + ) + elif time_col and is_timedelta64_dtype(trj[time_col]): + cbar_labels = trj[time_col].iloc[indices].dt.total_seconds().values + cbar_labels = ["%.2f" % number for number in cbar_labels] + elif time_col and is_datetime: + cbar_labels = ( + trj[time_col] + .iloc[indices] + .dt.strftime("%Y-%m-%d %H:%M:%S") + .values.astype(str) + ) + else: + # Convert frames to time + if time_col: + cbar_labels = trj[time_col].iloc[indices].values + else: + cbar_labels = trj.index[indices].values + cbar_labels = np.round(cbar_labels, 6) + if fps is not None and fps > 0 and fps != 1 and show_time: + cbar_labels = cbar_labels / fps + + cbar.set_ticks(indices) + cbar.set_ticklabels(cbar_labels) + plt.tight_layout() + + _process_after_plot_args(**after_plot_args) + return collection + + +def plot_periodogram(trj, coord: str = "y", fs: int = 1, interactive: bool = True): + """Plot power spectral density of ``coord`` timeseries using a periodogram. + + Args: + trj - Trajectory + coord - choice of 'x' or 'y' + fs - Sampling frequency + interactive - Plot immediately + + Returns: + Figure + + .. plot:: + + import matplotlib.pyplot as plt + + trj = traja.generate() + trj.traja.plot_periodogram() + + .. note:: + + Convenience wrapper for :meth:`scipy.signal.periodogram`. + + """ + from scipy import signal + + vals = trj[coord].values + f, Pxx = signal.periodogram(vals, fs=fs, window="hanning", scaling="spectrum") + plt.title("Power Spectrum") + plt.plot(f, Pxx) + if interactive: + plt.show() + + return plt.gcf() + + +def plot_autocorrelation( + trj: TrajaDataFrame, + coord: str = "y", + unit: str = "Days", + xmax: int = 1000, + interactive: bool = True, +): + """Plot autocorrelation of given coordinate. + + Args: + trj - Trajectory + coord - 'x' or 'y' + unit - string, eg, 'Days' + xmax - max xaxis value + interactive - Plot immediately + + Returns: + Matplotlib Figure + + .. plot:: + + import traja + + df = traja.generate() + df.traja.plot_autocorrelation() + + .. note:: + + Convenience wrapper for pandas :meth:`~pandas.plotting.autocorrelation_plot`. + """ + pd.plotting.autocorrelation_plot(trj[coord]) + plt.xlim((0, xmax)) + plt.xlabel(f"Lags ({unit})") + plt.ylabel("Autocorrelation") + if interactive: + plt.show() + return plt.gcf() + + +def plot_pca(trj: TrajaDataFrame, id_col: str="id", bins: tuple = (8,8), three_dims: bool = False, ax = None): + """Plot PCA comparing animals ids by trip grids. + + Args: + trj - Trajectory + id_col - column representing animal IDs + bins - shape for binning trajectory into a trip grid + three_dims - 3D plot. Default: False (2D plot) + ax - Matplotlib axes (optional) + + Returns: + fig - Figure + + .. plot:: + + # Load sample jaguar dataset with trajectories for 9 animals + df = traja.dataset.example.jaguar() + + # Bin trajectory into a trip grid then perform PCA + traja.plotting.plot_pca(df, id_col="ID", bins=(8,8)) + + """ + from sklearn.decomposition import PCA + from sklearn.preprocessing import StandardScaler + + + DIMS = 3 if three_dims else 2 + + # Bin trajectories to trip grids + grids = [] + ids = trj[id_col].unique() + + for id in ids: + animal = trj[trj[id_col]==id].copy() + animal.drop(columns=[id_col],inplace=True) + grid = animal.traja.trip_grid(bins = bins, hist_only=True)[0] + grids.append(grid.flatten()) + + # Standardize the data + gridsarr = np.array(grids) + X = StandardScaler().fit_transform(gridsarr) + + # PCA projection + pca = PCA(n_components=DIMS) + X_r = pca.fit(X).transform(X) + + # Create plot axes + if DIMS == 3: + fig = plt.figure() + ax = fig.add_subplot(111, projection='3d') + if not ax: + _, ax = plt.subplots() + + # Visualize 2D projection + for idx, animal in enumerate(X_r): + if DIMS == 2: + ax.scatter(X_r[idx, 0], X_r[idx, 1], color=f'C{idx}', alpha=.8, lw=2, label=idx) + elif DIMS == 3: + ax.scatter(X_r[idx, 0], X_r[idx, 1], ax.scatter[idx,2], color=f'C{idx}', alpha=.8, lw=2, label=idx) + + plt.title("PCA") + plt.legend(title=id_col, loc='best', shadow=False, scatterpoints=1) + plt.xlabel("Principal Component 1") + plt.ylabel("Principal Component 2") + + return plt.gcf() + +def plot_collection( + trjs: Union[pd.DataFrame, TrajaDataFrame], + id_col: str = "id", + colors: Optional[Union[dict, List[str]]] = None, + **kwargs, +): + """Plot trajectories of multiple subjects identified by `id`. + + Args: + trjs: dataframe with multiple trajectories + id_col: name of id_col, default is "id" + colors (Optional): color lookup matching substrings to discreet colors. Possible values are, eg: + - {"car0":"red","car1":"blue"} + - {"car":"red","person":blue"} + - ["car", "person"] + kwargs: kwargs to :meth:`matplotlib.axes.Axes.plot` + + Returns: + lines (list of `~matplotlib.lines.Line2D` objects): lines of plot + + """ + ids = trjs[id_col].unique() + + # Get plot keyword args + colormap = kwargs.pop("cmap", "hsv") + alpha = kwargs.pop("alpha", 0.2) + linestyle = kwargs.pop("linestyle", "-") + marker = kwargs.pop("marker", "o") + + labels = [None] * len(ids) + + if not colors: + cmap = plt.cm.get_cmap(colormap, lut=len(ids) if len(ids) > 1 else None) + colors = [cmap(idx) for idx in range(len(ids))] + elif isinstance(colors, list): + cmap = plt.cm.get_cmap(colormap, len(colors)) + color_lookup = [] + for ind, id in enumerate(ids): + for idx, substring in enumerate(colors): + if substring in id: + color_lookup.append(cmap(idx)) + labels[ind] = substring + break + else: + raise Exception(f"No substring matching {id} in {colors}.") + colors = color_lookup + elif isinstance(colors, dict): + color_lookup = [colors.get(id) for id in ids] + colors = color_lookup + labels = ids + + _, ax = plt.subplots() + lines = [] + for idx, id in enumerate(ids): + trj = trjs[trjs[id_col] == id] + l = ax.plot( + trj.x, + trj.y, + linestyle=linestyle, + marker=marker, + c=colors[idx], + alpha=alpha, + label=labels[idx], + **kwargs, + ) + lines.extend(l) + + handles, labels = plt.gca().get_legend_handles_labels() + by_label = OrderedDict(zip(labels, handles)) + plt.legend( + by_label.values(), + by_label.keys(), + bbox_to_anchor=(1.05, 1), + loc=2, + borderaxespad=0.0, + ) + plt.tight_layout() + return lines + + +def _label_axes(trj: TrajaDataFrame, ax) -> Axes: + if "spatial_units" in trj.__dict__: + ax.set_xlabel(trj.__dict__.get("spatial_units", "m")) + ax.set_ylabel(trj.__dict__.get("spatial_units", "m")) + return ax + + +def plot_quiver( + trj: TrajaDataFrame, + bins: Optional[Union[int, tuple]] = None, + quiverplot_kws: dict = {}, + **kwargs, +) -> Axes: + """Plot average flow from each grid cell to neighbor. + + Args: + bins (int or tuple): Tuple of x,y bin counts; if `bins` is int, bin count of x, + with y inferred from aspect ratio + quiverplot_kws: Additional keyword arguments for :meth:`~matplotlib.axes.Axes.quiver` + + Returns: + ax (:class:`~matplotlib.axes.Axes`): Axes of quiver plot + """ + + after_plot_args, _ = _get_after_plot_args(**kwargs) + + X, Y, U, V = coords_to_flow(trj, bins) + Z = np.sqrt(U * U + V * V) + + fig, ax = plt.subplots() + + ax.quiver(X, Y, U, V, units="width", **quiverplot_kws) + ax = _label_axes(trj, ax) + ax.set_aspect("equal") + + _process_after_plot_args(**after_plot_args) + return ax + + +def plot_contour( + trj: TrajaDataFrame, + bins: Optional[Union[int, tuple]] = None, + filled: bool = True, + quiver: bool = True, + contourplot_kws: dict = {}, + contourfplot_kws: dict = {}, + quiverplot_kws: dict = {}, + ax: Axes = None, + **kwargs, +) -> Axes: + """Plot average flow from each grid cell to neighbor. + + Args: + trj: Traja DataFrame + bins (int or tuple): Tuple of x,y bin counts; if `bins` is int, bin count of x, + with y inferred from aspect ratio + filled (bool): Contours filled + quiver (bool): Quiver plot + contourplot_kws: Additional keyword arguments for :meth:`~matplotlib.axes.Axes.contour` + contourfplot_kws: Additional keyword arguments for :meth:`~matplotlib.axes.Axes.contourf` + quiverplot_kws: Additional keyword arguments for :meth:`~matplotlib.axes.Axes.quiver` + ax (optional): Matplotlib Axes + + Returns: + ax (:class:`~matplotlib.axes.Axes`): Axes of quiver plot + """ + + after_plot_args, _ = _get_after_plot_args(**kwargs) + + X, Y, U, V = coords_to_flow(trj, bins) + Z = np.sqrt(U * U + V * V) + + if not ax: + _, ax = plt.subplots() + + if filled: + cfp = plt.contourf(X, Y, Z, **contourfplot_kws) + plt.colorbar(cfp, ax=ax) + plt.contour( + X, Y, Z, colors="k", linewidths=1, linestyles="solid", **contourplot_kws + ) + if quiver: + ax.quiver(X, Y, U, V, units="width", **quiverplot_kws) + + ax = _label_axes(trj, ax) + ax.set_aspect("equal") + + _process_after_plot_args(**after_plot_args) + return ax + + +def plot_surface( + trj: TrajaDataFrame, + bins: Optional[Union[int, tuple]] = None, + cmap: str = "viridis", + **surfaceplot_kws: dict, +) -> Figure: + """Plot surface of flow from each grid cell to neighbor in 3D. + + Args: + bins (int or tuple): Tuple of x,y bin counts; if `bins` is int, bin count of x, + with y inferred from aspect ratio + cmap (str): color map + surfaceplot_kws: Additional keyword arguments for :meth:`~mpl_toolkits.mplot3D.Axes3D.plot_surface` + + Returns: + ax (:class:`~matplotlib.axes.Axes`): Axes of quiver plot + """ + + after_plot_args, surfaceplot_kws = _get_after_plot_args(**surfaceplot_kws) + + X, Y, U, V = coords_to_flow(trj, bins) + Z = np.sqrt(U * U + V * V) + + fig = plt.figure() + ax = fig.gca(projection="3d") + ax.plot_surface( + X, Y, Z, cmap= cmap, linewidth=0, **surfaceplot_kws + ) + + ax = _label_axes(trj, ax) + try: + ax.set_aspect("equal") + except NotImplementedError: + # 3D + pass + + _process_after_plot_args(**after_plot_args) + return ax + + +def plot_stream( + trj: TrajaDataFrame, + bins: Optional[Union[int, tuple]] = None, + cmap: str = "viridis", + contourfplot_kws: dict = {}, + contourplot_kws: dict = {}, + streamplot_kws: dict = {}, + **kwargs, +) -> Figure: + """Plot average flow from each grid cell to neighbor. + + Args: + bins (int or tuple): Tuple of x,y bin counts; if `bins` is int, bin count of x, + with y inferred from aspect ratio + contourplot_kws: Additional keyword arguments for :meth:`~matplotlib.axes.Axes.contour` + contourfplot_kws: Additional keyword arguments for :meth:`~matplotlib.axes.Axes.contourf` + streamplot_kws: Additional keyword arguments for :meth:`~matplotlib.axes.Axes.streamplot` + + Returns: + ax (:class:`~matplotlib.axes.Axes`): Axes of stream plot + + """ + + after_plot_args, _ = _get_after_plot_args(**kwargs) + X, Y, U, V = coords_to_flow(trj, bins) + Z = np.sqrt(U * U + V * V) + + fig, ax = plt.subplots() + + plt.contourf(X, Y, Z, **contourfplot_kws) + plt.contour( + X, Y, Z, colors="k", linewidths=1, linestyles="solid", **contourplot_kws + ) + ax.streamplot(X, Y, U, V, color=Z, cmap=cmap, **streamplot_kws) + + ax = _label_axes(trj, ax) + ax.set_aspect("equal") + + _process_after_plot_args(**after_plot_args) + return ax + + +def plot_flow( + trj: TrajaDataFrame, + kind: str = "quiver", + *args, + contourplot_kws: dict = {}, + contourfplot_kws: dict = {}, + streamplot_kws: dict = {}, + quiverplot_kws: dict = {}, + surfaceplot_kws: dict = {}, + **kwargs, +) -> Figure: + """Plot average flow from each grid cell to neighbor. + + Args: + bins (int or tuple): Tuple of x,y bin counts; if `bins` is int, bin count of x, + with y inferred from aspect ratio + kind (str): Choice of 'quiver','contourf','stream','surface'. Default is 'quiver'. + contourplot_kws: Additional keyword arguments for :meth:`~matplotlib.axes.Axes.contour` + contourfplot_kws: Additional keyword arguments for :meth:`~matplotlib.axes.Axes.contourf` + streamplot_kws: Additional keyword arguments for :meth:`~matplotlib.axes.Axes.streamplot` + quiverplot_kws: Additional keyword arguments for :meth:`~matplotlib.axes.Axes.quiver` + surfaceplot_kws: Additional keyword arguments for :meth:`~matplotlib.axes.Axes.plot_surface` + + Returns: + ax (:class:`~matplotlib.axes.Axes`): Axes of plot + """ + if kind == "quiver": + return plot_quiver(trj, *args, **quiverplot_kws, **kwargs) + elif kind == "contour": + return plot_contour(trj, filled=False, *args, **quiverplot_kws, **kwargs) + elif kind == "contourf": + return plot_contour(trj, *args, **quiverplot_kws, **kwargs) + elif kind == "stream": + return plot_stream( + trj, + *args, + contourplot_kws=contourplot_kws, + contourfplot_kws=contourfplot_kws, + streamplot_kws=streamplot_kws, + **kwargs, + ) + elif kind == "surface": + return plot_surface(trj, *args, **surfaceplot_kws, **kwargs) + else: + raise NotImplementedError(f"Kind {kind} is not implemented.") + + +def _get_after_plot_args(**kwargs: dict) -> (dict, dict): + after_plot_args = dict( + interactive=kwargs.pop("interactive", True), + filepath=kwargs.pop("filepath", None), + ) + return after_plot_args, kwargs + + +def trip_grid( + trj: TrajaDataFrame, + bins: Union[tuple, int] = 10, + log: bool = False, + spatial_units: str = None, + normalize: bool = False, + hist_only: bool = False, + **kwargs, +) -> Tuple[np.ndarray, PathCollection]: + """Generate a heatmap of time spent by point-to-cell gridding. + + Args: + bins (int, optional): Number of bins (Default value = 10) + log (bool): log scale histogram (Default value = False) + spatial_units (str): units for plotting + normalize (bool): normalize histogram into density plot + hist_only (bool): return histogram without plotting + + Returns: + hist (:class:`numpy.ndarray`): 2D histogram as array + image (:class:`matplotlib.collections.PathCollection`: image of histogram + + """ + after_plot_args, kwargs = _get_after_plot_args(**kwargs) + + bins = traja.trajectory._bins_to_tuple(trj, bins) + # TODO: Add kde-based method for line-to-cell gridding + df = trj[["x", "y"]].dropna() + + # Set aspect if `xlim` and `ylim` set. + if "xlim" in kwargs and "ylim" in kwargs: + xlim, ylim = kwargs.pop("xlim"), kwargs.pop("ylim") + else: + xlim, ylim = traja.trajectory._get_xylim(df) + xmin, xmax = xlim + ymin, ymax = ylim + + x, y = zip(*df.values) + + hist, x_edges, y_edges = np.histogram2d( + x, y, bins, range=((xmin, xmax), (ymin, ymax)), normed=normalize + ) + + # rotate to keep y as first dimension + hist = np.rot90(hist) + + if log: + hist = np.log(hist + np.e) + if hist_only: # TODO: Evaluate potential use cases or remove + return (hist, None) + fig, ax = plt.subplots() + + image = ax.imshow( + hist, interpolation="bilinear", aspect="equal", extent=[xmin, xmax, ymin, ymax] + ) + # TODO: Adjust colorbar ytick_labels to correspond with time + label = "Frames" if not log else "$ln(frames)$" + plt.colorbar(image, ax=ax, label=label) + + _label_axes(trj, ax) + + plt.title("Time spent{}".format(" (Logarithmic)" if log else "")) + + _process_after_plot_args(**after_plot_args) + # TODO: Add method for most common locations in grid + # peak_index = unravel_index(hist.argmax(), hist.shape) + return hist, image + + +def _process_after_plot_args(**after_plot_args): + filepath = after_plot_args.get("filepath") + if filepath: + plt.savefig(filepath) + + +def color_dark( + series: pd.Series, ax: matplotlib.axes.Axes = None, start: int = 19, end: int = 7 +): + """Color dark phase in plot. + Args: + + series (pd.Series) - Time-series variable + ax (:class: `~matplotlib.axes.Axes`): axis to plot on (eg, `plt.gca()`) + start (int): start of dark period/night + end (hour): end of dark period/day + Returns: + + ax (:class:`~matplotlib.axes._subplots.AxesSubplot`): Axes of plot + """ + assert is_datetime_or_timedelta_dtype( + series.index + ), f"Series must have datetime index but has {type(series.index)}" + + pd.plotting.register_matplotlib_converters() # prevents type error with axvspan + + if not ax: + ax = plt.gca() + + # get boundaries for dark times + dark_mask = (series.index.hour >= start) | (series.index.hour < end) + run_values, run_starts, run_lengths = find_runs(dark_mask) + for idx, is_dark in enumerate(run_values): + if is_dark: + start = run_starts[idx] + end = run_starts[idx] + run_lengths[idx] - 1 + ax.axvspan(series.index[start], series.index[end], alpha=0.5, color="gray") + + fig = plt.gcf() + fig.autofmt_xdate() + return ax + + +def find_runs(x: pd.Series) -> (np.ndarray, np.ndarray, np.ndarray): + """Find runs of consecutive items in an array. + From https://gist.github.com/alimanfoo/c5977e87111abe8127453b21204c1065.""" + + # ensure array + x = np.asanyarray(x) + if x.ndim != 1: + raise ValueError("only 1D array supported") + n = x.shape[0] + + # handle empty array + if n == 0: + return np.array([]), np.array([]), np.array([]) + else: + # find run starts + loc_run_start = np.empty(n, dtype=bool) + loc_run_start[0] = True + np.not_equal(x[:-1], x[1:], out=loc_run_start[1:]) + run_starts = np.nonzero(loc_run_start)[0] + + # find run values + run_values = x[loc_run_start] + + # find run lengths + run_lengths = np.diff(np.append(run_starts, n)) + + return run_values, run_starts, run_lengths + + +def fill_ci(series: pd.Series, window: Union[int, str]) -> Figure: + """Fill confidence interval defined by SEM over mean of `window`. Window can be interval or offset, eg, '30s'.""" + assert is_datetime_or_timedelta_dtype( + series.index + ), f"Series index must be datetime but is {type(series.index)}" + smooth_path = series.rolling(window).mean() + path_deviation = series.rolling(window).std() + + fig, ax = plt.subplots() + + plt.plot(smooth_path.index, smooth_path, "b") + plt.fill_between( + path_deviation.index, + (smooth_path - 2 * path_deviation), + (smooth_path + 2 * path_deviation), + color="b", + alpha=0.2, + ) + + plt.gcf().autofmt_xdate() + return ax + + +def plot_xy(xy: np.ndarray, *args: Optional, **kwargs: Optional): + """Plot trajectory from xy values. + + Args: + + xy (np.ndarray) : xy values of dimensions N x 2 + *args : Plot args + **kwargs : Plot kwargs + """ + trj = traja.from_xy(xy) + trj.traja.plot(*args, **kwargs) + + +def plot_actogram( + series: pd.Series, dark=(19, 7), ax: matplotlib.axes.Axes = None, **kwargs +): + """Plot activity or displacement as an actogram. + + .. note:: + + For published example see Eckel-Mahan K, Sassone-Corsi P. Phenotyping Circadian Rhythms in Mice. + Curr Protoc Mouse Biol. 2015;5(3):271-281. Published 2015 Sep 1. doi:10.1002/9780470942390.mo140229 + + """ + assert isinstance(series, pd.Series) + assert is_datetime_or_timedelta_dtype( + series.index + ), f"Series must have datetime index but has {type(series.index)}" + + after_plot_args, _ = _get_after_plot_args(**kwargs) + + ax = series.plot(ax=ax) + ax.set_ylabel(series.name) + + color_dark(series, ax, start=dark[0], end=dark[1]) + + _process_after_plot_args(**after_plot_args) + + +def _polar_bar( + radii: np.ndarray, + theta: np.ndarray, + bin_size: int = 2, + ax: Optional[matplotlib.axes.Axes] = None, + overlap: bool = True, + **kwargs: str, +) -> Axes: + after_plot_args, kwargs = _get_after_plot_args(**kwargs) + + title = kwargs.pop("title", None) + ax = ax or plt.subplot(111, projection="polar") + + hist, bin_edges = np.histogram( + theta, bins=np.arange(-180, 180 + bin_size, bin_size) + ) + centers = np.deg2rad(np.ediff1d(bin_edges) // 2 + bin_edges[:-1]) + + radians = np.deg2rad(theta) + + width = np.deg2rad(bin_size) + angle = radians if overlap else centers + height = radii if overlap else hist + max_height = max(height) + bars = ax.bar(angle, height, width=width, bottom=0.0, **kwargs) + for h, bar in zip(height, bars): + bar.set_facecolor(plt.cm.viridis(h / max_height)) + bar.set_alpha(0.5) + if isinstance(ax, matplotlib.axes.Axes): + ax.set_theta_zero_location("N") + ax.set_xticklabels(["0", "45", "90", "135", "180", "-135", "-90", "-45"]) + if title: + plt.title(title + "\n", y=1.08) + plt.tight_layout() + + _process_after_plot_args(**after_plot_args) + return ax + + +def polar_bar( + trj: TrajaDataFrame, + feature: str = "turn_angle", + bin_size: int = 2, + threshold: float = 0.001, + overlap: bool = True, + ax: Optional[matplotlib.axes.Axes] = None, + **plot_kws: str, +) -> Axes: + """Plot polar bar chart. + + Args: + trj (:class:`traja.TrajaDataFrame`): trajectory + feature (str): Options: 'turn_angle', 'heading' + bin_size (int): width of bins + threshold (float): filter for step distance + overlap (bool): Overlapping shows all values, if set to false is a histogram + + Returns: + ax (:class:`~matplotlib.collections.PathCollection`): Axes of plot + + """ + # Get displacement + displacement = traja.trajectory.calc_displacement(trj) + trj["displacement"] = displacement + trj = trj.loc[trj.displacement > threshold] + if feature == "turn_angle": + feature_series = traja.trajectory.calc_turn_angle(trj) + trj["turn_angle"] = feature_series + trj.turn_angle = trj.turn_angle.shift(-1) + elif feature == "heading": + feature_series = traja.trajectory.calc_heading(trj) + trj[feature] = feature_series + + trj = trj[pd.notnull(trj[feature])] + trj = trj[pd.notnull(trj.displacement)] + + assert ( + len(trj) > 0 + ), f"Dataframe is empty after filtering for step distance threshold {threshold}" + + ax = _polar_bar( + trj.displacement, + trj[feature], + bin_size=bin_size, + overlap=overlap, + ax=ax, + **plot_kws, + ) + return ax + + +def plot_clustermap( + displacements: List[pd.Series], + rule: Optional[str] = None, + nr_steps=None, + colors: Optional[List[Union[int, str]]] = None, + **kwargs, +): + """Plot cluster map / dendrogram of trajectories with DatetimeIndex. + + Args: + displacements: list of pd.Series, outputs of :func:`traja.calc_displacement()` + rule: how to resample series, eg '30s' for 30-seconds + nr_steps: select first N samples for clustering + colors: list of colors (eg, 'b','r') to map to each trajectory + kwargs: keyword arguments for :func:`seaborn.clustermap` + + Returns: + cg: a :func:`seaborn.matrix.ClusterGrid` instance + + .. note:: + + Requires seaborn to be installed. Install it with 'pip install seaborn'. + + """ + try: + import seaborn as sns + except ImportError: + logging.error("seaborn is not installed. Install it with 'pip install seaborn'") + return + + after_plot_args, _ = _get_after_plot_args(**kwargs) + + series_lst = [] + for disp in displacements: + if rule: + disp = disp.resample(rule).sum() + series_lst.append(disp) + + df = pd.DataFrame(series_lst) + df.columns = range(len(df.columns)) + df.reset_index(drop=True, inplace=True) + + if not nr_steps: + nr_steps = df.shape[1] + + cg = sns.clustermap( + df.fillna(0).iloc[:, :nr_steps], + xticklabels=False, + col_cluster=False, + figsize=(16, 6), + cmap="Greys", + row_colors=colors, + **kwargs, + ) + plt.setp(cg.ax_heatmap.yaxis.get_majorticklabels(), rotation=0) + + _process_after_plot_args(**after_plot_args) + return cg + + +def _get_markov_edges(Q: pd.DataFrame, greater_than=0.1): + """Select edges greater than a threshold of weight.""" + edges = {} + for col in Q.columns: + for idx in Q.index: + if greater_than and Q.loc[idx, col] > greater_than: + edges[(idx, col)] = Q.loc[idx, col] + return edges + + +def plot_transition_graph( + data: Union[pd.DataFrame, traja.TrajaDataFrame, np.ndarray], + outpath="markov.dot", + interactive=True, +): + """Plot transition graph with networkx. + + Args: + data (trajectory or transition_matrix) + + .. note:: + Modified from http://www.blackarbs.com/blog/introduction-hidden-markov-models-python-networkx-sklearn/2/9/2017 + + """ + try: + import networkx as nx + import pydot + import graphviz + except ImportError as e: + raise ImportError(f"{e} - please install it with pip") + + if ( + isinstance(data, (traja.TrajaDataFrame)) + or isinstance(data, pd.DataFrame) + and "x" in data + ): + transition_matrix = traja.transitions(data) + edges_wts = _get_markov_edges(pd.DataFrame(transition_matrix)) + states_ = list(range(transition_matrix.shape[0])) + + # create graph object + G = nx.MultiDiGraph() + + # nodes correspond to states + G.add_nodes_from(states_) + + # edges represent transition probabilities + for k, v in edges_wts.items(): + tmp_origin, tmp_destination = k[0], k[1] + G.add_edge(tmp_origin, tmp_destination, weight=v.round(4), label=v.round(4)) + + pos = nx.drawing.nx_pydot.graphviz_layout(G, prog="dot") + nx.draw_networkx(G, pos) + + # create edge labels for jupyter plot but is not necessary + edge_labels = {(n1, n2): d["label"] for n1, n2, d in G.edges(data=True)} + nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels) + if os.exists(outpath): + logging.info(f"Overwriting {outpath}") + nx.drawing.nx_pydot.write_dot(G, outpath) + + if interactive: + # Plot + from graphviz import Source + + s = Source.from_file(outpath) + s.view() + + +def plot_transition_matrix( + data: Union[pd.DataFrame, traja.TrajaDataFrame, np.ndarray], + interactive=True, + **kwargs, +) -> matplotlib.image.AxesImage: + """Plot transition matrix. + + Args: + data (trajectory or square transition matrix) + interactive (bool): show plot + kwargs: kwargs to :func:`traja.grid_coordinates` + + Returns: + axesimage (matplotlib.image.AxesImage) + + """ + if isinstance(data, np.ndarray): + if data.shape[0] != data.shape[1]: + raise ValueError( + f"Ndarray input must be square transition matrix, shape is {data.shape}" + ) + transition_matrix = data + elif isinstance(data, (pd.DataFrame, traja.TrajaDataFrame)): + transition_matrix = traja.transitions(data, **kwargs) + img = plt.imshow(transition_matrix) + if interactive: + plt.show() + return img + + +def animate(trj: TrajaDataFrame, polar: bool = True, save: bool = False): + """Animate trajectory. + + Args: + polar (bool): include polar bar chart with turn angle + save (bool): save video to ``trajectory.mp4`` + + Returns: + anim (matplotlib.animation.FuncAnimation): animation + + """ + from matplotlib import animation + from matplotlib.animation import FuncAnimation + + displacement = traja.trajectory.calc_displacement(trj).reset_index(drop=True) + # heading = traja.calc_heading(trj) + turn_angle = traja.trajectory.calc_turn_angle(trj).reset_index(drop=True) + xy = trj[["x", "y"]].reset_index(drop=True) + + POLAR_STEPS = XY_STEPS = 20 + DISPLACEMENT_THRESH = 0.025 + bin_size = 2 + overlap = True + + fig = plt.figure(figsize=(8, 6)) + ax1 = plt.subplot(211) + + fig.add_subplot(ax1) + if polar: + ax2 = plt.subplot(212, polar="projection") + ax2.set_theta_zero_location("N") + ax2.set_xticklabels(["0", "45", "90", "135", "180", "-135", "-90", "-45"]) + fig.add_subplot(ax2) + ax2.bar( + np.zeros(XY_STEPS), np.zeros(XY_STEPS), width=np.zeros(XY_STEPS), bottom=0.0 + ) + + xlim, ylim = traja.trajectory._get_xylim(trj) + ax1.set( + xlim=xlim, + ylim=ylim, + ylabel=trj.__dict__.get("spatial_units", "m"), + xlabel=trj.__dict__.get("spatial_units", "m"), + aspect="equal", + ) + + alphas = np.linspace(0.1, 1, XY_STEPS) + rgba_colors = np.zeros((XY_STEPS, 4)) + rgba_colors[:, 0] = 1.0 # red + rgba_colors[:, 3] = alphas + scat = ax1.scatter( + range(XY_STEPS), range(XY_STEPS), marker=".", color=rgba_colors[:XY_STEPS] + ) + + def update(frame_number): + if frame_number < (XY_STEPS+2): + pass + else: + ind = frame_number % len(xy) + if ind < XY_STEPS: + scat.set_offsets(xy[:ind]) + else: + prev_steps = max(ind - XY_STEPS, 0) + scat.set_offsets(xy[prev_steps:ind]) + + displacement_str = ( + rf"$\bf{displacement[ind]:.2f}$" + if displacement[ind] >= DISPLACEMENT_THRESH + else f"{displacement[ind]:.2f}" + ) + + x, y = xy.iloc[ind] + ax1.set_title( + f"frame {ind} - distance (cm/0.25s): {displacement_str}\n" + f"x: {x:.2f}, y: {y:.2f}\n" + f"turn_angle: {turn_angle[ind]:.2f}" + ) + + if polar and ind > 1: + ax2.clear() + start_index = max(ind - POLAR_STEPS, 0) + + theta = turn_angle[start_index:ind] + radii = displacement[start_index:ind] + + hist, bin_edges = np.histogram( + theta, bins=np.arange(-180, 180 + bin_size, bin_size) + ) + centers = np.deg2rad(np.ediff1d(bin_edges) // 2 + bin_edges[:-1]) + + radians = np.deg2rad(theta) + + width = np.deg2rad(bin_size) + angle = radians if overlap else centers + height = radii if overlap else hist + max_height = displacement.max() if overlap else max(hist) + + bars = ax2.bar(angle, height, width=width, bottom=0.0) + for idx, (h, bar) in enumerate(zip(height, bars)): + bar.set_facecolor(plt.cm.viridis(h / max_height)) + bar.set_alpha(0.8 * (idx / POLAR_STEPS)) + ax2.set_theta_zero_location("N") + ax2.set_xticklabels(["0", "45", "90", "135", "180", "-135", "-90", "-45"]) + + anim = FuncAnimation(fig, update, interval=10, frames=len(xy)) + if save: + try: + anim.save("trajectory.mp4", writer=animation.FFMpegWriter(fps=10)) + except FileNotFoundError: + raise Exception("FFmpeg not installed, please install it.") + else: + plt.show() + + return anim diff --git a/traja/stats/brownian.py b/traja/stats/brownian.py new file mode 100644 index 00000000..c198ad6d --- /dev/null +++ b/traja/stats/brownian.py @@ -0,0 +1,63 @@ +from scipy.stats import norm +import numpy as np + + +class Brownian: + """ + Brownian: Generate brownian motion. Remembers the last position. + + This class caches a large number of samples drawn from a normal + distribution to compute noise faster. + + Usage: brownian = Brownian(x0=0); + Brownian() # Yields x0 + x1 where x1 ~ N(0, 1) + Brownian() # Yields x0 + x1 + x2 where x2 ~ N(0, 1) + + Parameters: + ----------- + x0: Initial x position. + mean_value: Bias (drift) of the random walk. + variance: Size of random walk steps. + length: Number of samples to generate. + dt: delta-time between every step. + """ + + def __init__(self, x0=0, mean_value=0, variance=1, dt=1., length=100000): + assert (type(x0) == float or type(x0) == int or x0 is None), "Expect a float or None for the initial value" + + self._x0 = float(x0) + + # DO NOT modify these values once the class is initialised. The behaviour would + # be unpredictable + self._mean_value = mean_value + self._variance = variance + self._dt = dt + self._length = length + + self._index = 0 + + self._generate_noise() + + def _generate_noise(self): + x0 = np.asarray(self._x0) + + # Generate self._length samples of noise + r = norm.rvs(loc=self._mean_value, scale=self._variance * np.sqrt(self._dt), size=self._length) + out = np.empty(r.shape) + + # This computes the Brownian motion by forming the cumulative sum of + # the random samples. + np.cumsum(r, axis=-1, out=out) + + self._random_walk = out + + def __call__(self): + assert self._index < self._length, "Random walk is out of samples!" + + sample = self._random_walk[self._index] + self._index += 1 + + return sample + + def __len__(self): + return len(self._random_walk) diff --git a/traja/tests/.gitignore b/traja/tests/.gitignore new file mode 100644 index 00000000..333c1e91 --- /dev/null +++ b/traja/tests/.gitignore @@ -0,0 +1 @@ +logs/ diff --git a/traja/tests/__init__.py b/traja/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/traja/tests/data/3527.csv b/traja/tests/data/3527.csv new file mode 100644 index 00000000..52c86150 --- /dev/null +++ b/traja/tests/data/3527.csv @@ -0,0 +1,116 @@ +Frame,Time,TrackId,x,y,ValueChanged +8,0.16,8,195.1955313,0,TRUE +9,0.18,8,193.1863869,1.136555263,TRUE +10,0.2,8,190.9926649,4.221957615,TRUE +11,0.22,8,186.7667566,7.61793954,TRUE +12,0.24,8,182.5553267,10.96757289,TRUE +13,0.26,8,178.6316884,13.89066696,TRUE +14,0.28,8,176.1203793,17.61484092,TRUE +15,0.3,8,174.0618075,21.54559708,TRUE +16,0.32,8,171.8296272,24.65823473,TRUE +17,0.34,8,170.0685139,27.2345532,TRUE +18,0.36,8,168.1284399,30.15305655,TRUE +19,0.38,8,166.8313531,33.50317546,TRUE +20,0.4,8,165.1225695,38.39506858,TRUE +21,0.42,8,163.9299104,42.93793488,TRUE +22,0.44,8,163.1885319,46.61214066,TRUE +23,0.46,8,162.5733539,49.28071485,TRUE +24,0.48,8,161.7131465,52.2716544,TRUE +25,0.5,8,160.7311196,56.76693617,TRUE +26,0.52,8,159.3286228,62.25747626,TRUE +27,0.54,8,157.5739983,67.41585159,TRUE +28,0.56,8,156.0172381,71.4216483,TRUE +29,0.58,8,154.1291959,76.39189257,TRUE +30,0.6,8,151.3423887,82.96645955,TRUE +31,0.62,8,148.451529,87.44571795,TRUE +32,0.64,8,146.388234,91.99860437,TRUE +33,0.66,8,144.7179308,96.31219973,TRUE +34,0.68,8,143.4674353,100.9680241,TRUE +35,0.7,8,141.7446258,105.76594,TRUE +36,0.72,8,139.9582635,110.4479403,TRUE +37,0.74,8,139.0669584,114.5926503,TRUE +38,0.76,8,137.4684734,118.89137,TRUE +39,0.78,8,135.9287077,124.7252426,TRUE +40,0.8,8,134.4333151,130.623606,TRUE +41,0.82,8,133.1268703,135.6793524,TRUE +42,0.84,8,130.0078763,140.6348975,TRUE +43,0.86,8,127.9284476,145.2325875,TRUE +44,0.88,8,127.2109938,148.5914906,TRUE +45,0.9,8,126.5339073,150.6168791,TRUE +46,0.92,8,125.3223777,153.0521213,TRUE +47,0.94,8,122.5305605,155.5876972,TRUE +48,0.96,8,121.378026,157.6171025,TRUE +49,0.98,8,120.3359446,158.9986872,TRUE +50,1,8,119.0702975,161.6172049,TRUE +51,1.02,8,118.5533564,162.788632,TRUE +52,1.04,8,115.8251912,167.4142636,TRUE +53,1.06,8,113.6337645,171.8507489,TRUE +54,1.08,8,111.4660308,175.9492427,TRUE +55,1.1,8,109.7098282,181.0273688,TRUE +56,1.12,8,107.606828,185.3344754,TRUE +57,1.14,8,105.4908502,188.3730436,TRUE +58,1.16,8,103.1728146,191.6863485,TRUE +59,1.18,8,100.3809201,194.3041158,TRUE +60,1.2,8,97.21696799,198.0050714,TRUE +61,1.22,8,93.4727869,202.5212762,TRUE +62,1.24,8,90.79096474,206.5896655,TRUE +63,1.26,8,88.41670949,210.9734459,TRUE +64,1.28,8,85.35937561,215.5769626,TRUE +65,1.3,8,82.23553153,221.793542,TRUE +66,1.32,8,80.05120059,227.3931116,TRUE +67,1.34,8,78.46941764,231.1202431,TRUE +68,1.36,8,75.6055118,234.0811223,TRUE +69,1.38,8,73.20263631,236.7896004,TRUE +70,1.4,8,71.24597618,241.060555,TRUE +71,1.42,8,68.14508568,245.528116,TRUE +72,1.44,8,66.43572828,249.5646351,TRUE +73,1.46,8,64.1633185,252.9969897,TRUE +74,1.48,8,62.43480921,257.0862579,TRUE +75,1.5,8,61.28187193,261.4370204,TRUE +76,1.52,8,60.67954465,264.9693113,TRUE +77,1.54,8,61.01516349,267.5071384,TRUE +78,1.56,8,61.0214371,270.0911816,TRUE +79,1.58,8,60.61678648,273.1371215,TRUE +80,1.6,8,60.64566054,277.6957463,TRUE +81,1.62,8,59.78961897,282.2445275,TRUE +82,1.64,8,59.70785236,286.2286949,TRUE +83,1.66,8,59.32728093,290.0116653,TRUE +84,1.68,8,58.51426077,294.291978,TRUE +85,1.7,8,58.83859042,298.470986,TRUE +86,1.72,8,59.06069939,303.7087718,TRUE +87,1.74,8,59.43152659,308.2443548,TRUE +88,1.76,8,59.91277926,312.1868526,TRUE +89,1.78,8,60.28320919,316.0744384,TRUE +90,1.8,8,61.33781576,319.6056257,TRUE +91,1.82,8,62.35933828,323.6002987,TRUE +92,1.84,8,63.13215658,327.2610414,TRUE +93,1.86,8,63.33545024,331.3871237,TRUE +94,1.88,8,62.96120759,335.1735813,TRUE +95,1.9,8,62.01944324,338.639704,TRUE +96,1.92,8,61.35536752,342.9537849,TRUE +97,1.94,8,60.37688848,347.1259509,TRUE +98,1.96,8,59.45999786,350.7071506,TRUE +99,1.98,8,58.68717957,353.906438,TRUE +100,2,8,57.38225208,357.2298513,TRUE +101,2.02,8,56.41150331,360.2947279,TRUE +102,2.04,8,55.70298815,363.9807636,TRUE +103,2.06,8,54.70898785,367.0785255,TRUE +104,2.08,8,53.96807834,368.7679531,TRUE +105,2.1,8,53.14203092,370.2357461,TRUE +106,2.12,8,52.44340897,372.5409034,TRUE +107,2.14,8,51.14388881,374.6292376,TRUE +108,2.16,8,49.20671715,377.2650588,TRUE +109,2.18,8,47.10257476,381.007706,TRUE +110,2.2,8,45.24333767,384.5887953,TRUE +111,2.22,8,44.69228349,386.923417,TRUE +112,2.24,8,43.31672134,389.4708669,TRUE +113,2.26,8,42.02495629,392.095741,TRUE +114,2.28,8,40.30187641,394.2168503,TRUE +115,2.3,8,37.23321748,396.5922146,TRUE +116,2.32,8,32.80634952,398.3257174,TRUE +117,2.34,8,29.44663259,400.0773844,TRUE +118,2.36,8,27.47948057,402.0311974,TRUE +119,2.38,8,25.77367105,403.7357875,TRUE +120,2.4,8,23.89154659,405.0904459,TRUE +121,2.42,8,22.40849299,407.0894378,TRUE +122,2.44,8,19.49078143,409.7471531,TRUE diff --git a/traja/tests/test_accessor.py b/traja/tests/test_accessor.py new file mode 100644 index 00000000..1b7c45a5 --- /dev/null +++ b/traja/tests/test_accessor.py @@ -0,0 +1,81 @@ +import pandas as pd +import shapely + +import traja + +df = traja.generate(n=20) + + +def test_center(): + xy = df.traja.center + + +def test_night(): + df["time"] = pd.DatetimeIndex(range(20)) + df.traja.night() + + +def test_between(): + df["time"] = pd.DatetimeIndex(range(20)) + df.traja.between("8:00", "10:00") + + +def test_day(): + df["time"] = pd.DatetimeIndex(range(20)) + df.traja.day() + + +def test_xy(): + xy = df.traja.xy + assert xy.shape == (20, 2) + + +# def test_calc_derivatives(): +# df.traja.calc_derivatives() + + +# def test_get_derivatives(): +# df.traja.get_derivatives() + + +# def test_speed_intervals(): +# si = df.traja.speed_intervals(faster_than=100) +# assert isinstance(si, traja.TrajaDataFrame) + + +def test_to_shapely(): + shape = df.traja.to_shapely() + assert isinstance(shape, shapely.geometry.linestring.LineString) + + +def test_calc_displacement(): + disp = df.traja.calc_displacement() + assert isinstance(disp, pd.Series) + + +def test_calc_angle(): + angle = df.traja.calc_angle() + assert isinstance(angle, pd.Series) + + +def test_scale(): + df_copy = df.copy() + df_copy.traja.scale(0.1) + assert isinstance(df_copy, traja.TrajaDataFrame) + + +def test_rediscretize(R=0.1): + df_copy = df.copy() + r_df = df_copy.traja.rediscretize(R) + assert isinstance(r_df, traja.TrajaDataFrame) + assert r_df.shape == (382, 2) + + +def test_calc_heading(): + heading = df.traja.calc_heading() + assert isinstance(heading, pd.Series) + + +def test_calc_turn_angle(): + turn_angle = df.traja.calc_turn_angle() + assert isinstance(turn_angle, pd.Series) diff --git a/traja/tests/test_dataset.py b/traja/tests/test_dataset.py new file mode 100644 index 00000000..7b2daa00 --- /dev/null +++ b/traja/tests/test_dataset.py @@ -0,0 +1,655 @@ +import os +import pandas as pd +import pytest + +from traja.dataset import dataset +from traja.dataset.pituitary_gland import create_latin_hypercube_sampled_pituitary_df + + +@pytest.mark.skipif(os.name == 'nt', reason="hangs on Windows for unknown reason") +def test_time_based_sampling_dataloaders_do_not_overlap(): + data = list() + num_ids = 140 + sequence_length = 2000 + + # Hyperparameters + batch_size = 10 + num_past = 10 + num_future = 5 + train_split_ratio = 0.501 + validation_split_ratio = 0.25 + + split_by_id = False # The test condition + + # The train[0] column should contain only 1s, the test column should contain 2s and the + # validation column set should contain 3s. + # When scaled, this translates to -1., 0 and 1. respectively. + for sample_id in range(num_ids): + for element in range(round(sequence_length * train_split_ratio)): + data.append([1, element, sample_id]) + for element in range( + round(sequence_length * (1 - train_split_ratio - validation_split_ratio)) + ): + data.append([2, element, sample_id]) + for element in range(round(sequence_length * validation_split_ratio)): + data.append([3, element, sample_id]) + + df = pd.DataFrame(data, columns=["x", "y", "ID"]) + + dataloaders = dataset.MultiModalDataLoader( + df, + batch_size=batch_size, + n_past=num_past, + n_future=num_future, + num_workers=1, + train_split_ratio=train_split_ratio, + validation_split_ratio=validation_split_ratio, + split_by_id=split_by_id, + ) + + for data, target, ids, parameters, classes in dataloaders["train_loader"]: + for sequence in data: + assert all(sample == -1.0 for sample in sequence[:,0]) + for sequence in target: + assert all(sample == -1.0 for sample in sequence[:,0]) + + for data, target, ids, parameters, classes in dataloaders["test_loader"]: + for sequence in data: + assert all(sample == 0 for sample in sequence[:,0]) + for sequence in target: + assert all(sample == 0 for sample in sequence[:,0]) + + for data, target, ids, parameters, classes in dataloaders["validation_loader"]: + for sequence in data: + assert all(sample == 1 for sample in sequence[:,0]) + for sequence in target: + assert all(sample == 1 for sample in sequence[:,0]) + + +def test_time_based_sampling_dataloaders_do_not_overlap(): + data = list() + num_ids = 140 + sequence_length = 2000 + + # Hyperparameters + batch_size = 15 + num_past = 10 + num_future = 5 + train_split_ratio = 0.498 + validation_split_ratio = 0.25 + + stride = 5 + + split_by_id = False # The test condition + + # The train[0] column should contain only 1s, the test column should contain 2s and the + # validation column set should contain 3s. + # When scaled, this translates to -1., 0 and 1. respectively. + for sample_id in range(num_ids): + for element in range(round(sequence_length * train_split_ratio) - 6): + data.append([1, element, sample_id]) + for element in range( + round(sequence_length * (1 - train_split_ratio - validation_split_ratio)) + + -4 + ): + data.append([2, element, sample_id]) + for element in range(round(sequence_length * validation_split_ratio) + 10): + data.append([3, element, sample_id]) + + df = pd.DataFrame(data, columns=["x", "y", "ID"]) + + dataloaders = dataset.MultiModalDataLoader( + df, + batch_size=batch_size, + n_past=num_past, + n_future=num_future, + num_workers=1, + train_split_ratio=train_split_ratio, + validation_split_ratio=validation_split_ratio, + split_by_id=split_by_id, + stride=stride, + ) + + for data, target, ids, parameters, classes in dataloaders["train_loader"]: + for sequence in data: + assert all(sample == -1. for sample in sequence[:,0]) + for sequence in target: + assert all(sample == -1. for sample in sequence[:,0]) + + for data, target, ids, parameters, classes in dataloaders["test_loader"]: + for sequence in data: + assert all(sample == 0 for sample in sequence[:,0]) + for sequence in target: + assert all(sample == 0 for sample in sequence[:,0]) + + for data, target, ids, parameters, classes in dataloaders["validation_loader"]: + for sequence in data: + assert all(sample == 1 for sample in sequence[:,0]) + for sequence in target: + assert all(sample == 1 for sample in sequence[:,0]) + +def test_time_based_sampling_dataloaders_with_stride_one_do_not_overlap(): + data = list() + num_ids = 2 + sequence_length = 200 + + # Hyperparameters + batch_size = 15 + num_past = 10 + num_future = 5 + train_split_ratio = 0.5 + validation_split_ratio = 0.25 + + stride = 1 + + split_by_id = False # The test condition + + # The train[0] column should contain only 1s, the test column should contain 2s and the + # validation column set should contain 3s. + # When scaled, this translates to -1., 0 and 1. respectively. + for sample_id in range(num_ids): + for element in range(round(sequence_length * train_split_ratio) - 8): + data.append([1, element, sample_id]) + for element in range( + round(sequence_length * (1 - train_split_ratio - validation_split_ratio)) + - 4 + ): + data.append([2, element, sample_id]) + for element in range(round(sequence_length * validation_split_ratio) + 12): + data.append([3, element, sample_id]) + + df = pd.DataFrame(data, columns=["x", "y", "ID"]) + + dataloaders = dataset.MultiModalDataLoader( + df, + batch_size=batch_size, + n_past=num_past, + n_future=num_future, + num_workers=4, + train_split_ratio=train_split_ratio, + validation_split_ratio=validation_split_ratio, + split_by_id=split_by_id, + stride=stride, + ) + + for data, target, ids, parameters, classes in dataloaders["train_loader"]: + for sequence in data: + assert all(sample == -1. for sample in sequence[:,0]) + for sequence in target: + assert all(sample == -1. for sample in sequence[:,0]) + + for data, target, ids, parameters, classes in dataloaders["test_loader"]: + for sequence in data: + assert all(sample == 0 for sample in sequence[:,0]) + for sequence in target: + assert all(sample == 0 for sample in sequence[:,0]) + + for data, target, ids, parameters, classes in dataloaders["validation_loader"]: + for sequence in data: + assert all(sample == 1 for sample in sequence[:,0]) + for sequence in target: + assert all(sample == 1 for sample in sequence[:,0]) + + +def test_time_based_weighted_sampling_dataloaders_do_not_overlap(): + data = list() + num_ids = 232 + sample_id = 0 + + for sequence_id in range(num_ids): + for sequence in range(40 + (int(sequence_id * 2.234) % 117)): + data.append([sequence, sample_id, sequence_id]) + sample_id += 1 + + df = pd.DataFrame(data, columns=["x", "y", "ID"]) + + # Hyperparameters + batch_size = 10 + num_past = 10 + num_future = 5 + train_split_ratio = 0.333 + validation_split_ratio = 0.333 + + dataloaders = dataset.MultiModalDataLoader( + df, + batch_size=batch_size, + n_past=num_past, + n_future=num_future, + num_workers=1, + train_split_ratio=train_split_ratio, + validation_split_ratio=validation_split_ratio, + scale=False, + split_by_id=False, + weighted_sampling=True, + stride=1, + ) + + train_ids = extract_sample_ids_from_dataloader(dataloaders["train_loader"]) + test_ids = extract_sample_ids_from_dataloader(dataloaders["test_loader"]) + validation_ids = extract_sample_ids_from_dataloader( + dataloaders["validation_loader"] + ) + sequential_train_ids = extract_sample_ids_from_dataloader( + dataloaders["sequential_train_loader"] + ) + sequential_test_ids = extract_sample_ids_from_dataloader( + dataloaders["sequential_test_loader"] + ) + sequential_validation_ids = extract_sample_ids_from_dataloader( + dataloaders["sequential_validation_loader"] + ) + + verify_that_indices_belong_to_precisely_one_loader( + train_ids, test_ids, validation_ids + ) + verify_that_indices_belong_to_precisely_one_loader( + sequential_train_ids, sequential_test_ids, sequential_validation_ids + ) + + +def test_id_wise_sampling_with_few_ids_does_not_put_id_in_multiple_dataloaders(): + data = list() + num_ids = 5 + sample_id = 0 + + for sequence_id in range(num_ids): + for sequence in range(40 + int(sequence_id / 14)): + data.append([sequence, sample_id, sequence_id]) + sample_id += 1 + + df = pd.DataFrame(data, columns=["x", "y", "ID"]) + + # Hyperparameters + batch_size = 1 + num_past = 10 + num_future = 5 + train_split_ratio = 0.5 + validation_split_ratio = 0.2 + + dataloaders = dataset.MultiModalDataLoader( + df, + batch_size=batch_size, + n_past=num_past, + n_future=num_future, + num_workers=1, + train_split_ratio=train_split_ratio, + validation_split_ratio=validation_split_ratio, + scale=False, + ) + + verify_sequential_id_sampled_sequential_dataloaders_equal_dataloaders( + dataloaders, train_split_ratio, validation_split_ratio, num_ids + ) + + +def test_id_wise_sampling_with_short_sequences_does_not_divide_by_zero(): + data = list() + num_ids = 283 + sample_id = 0 + + for sequence_id in range(num_ids): + for sequence in range( + 1 + (sequence_id % 74) + ): # Some sequences will generate zero time series + data.append([sequence, sample_id, sequence_id]) + sample_id += 1 + + df = pd.DataFrame(data, columns=["x", "y", "ID"]) + + # Hyperparameters + batch_size = 1 + num_past = 10 + num_future = 5 + train_split_ratio = 0.333 + validation_split_ratio = 0.333 + + dataloaders = dataset.MultiModalDataLoader( + df, + batch_size=batch_size, + n_past=num_past, + n_future=num_future, + num_workers=1, + train_split_ratio=train_split_ratio, + validation_split_ratio=validation_split_ratio, + scale=False, + ) + + verify_sequential_id_sampled_sequential_dataloaders_equal_dataloaders( + dataloaders, + train_split_ratio, + validation_split_ratio, + num_ids, + expect_all_ids=False, + ) + + +def test_id_wise_sampling_does_not_put_id_in_multiple_dataloaders(): + data = list() + num_ids = 150 + sample_id = 0 + + for sequence_id in range(num_ids): + for sequence in range(40): + data.append([sequence, sample_id, sequence_id]) + sample_id += 1 + + df = pd.DataFrame(data, columns=["x", "y", "ID"]) + + # Hyperparameters + batch_size = 10 + num_past = 10 + num_future = 5 + train_split_ratio = 0.333 + validation_split_ratio = 0.333 + + dataloaders = dataset.MultiModalDataLoader( + df, + batch_size=batch_size, + n_past=num_past, + n_future=num_future, + num_workers=1, + train_split_ratio=train_split_ratio, + validation_split_ratio=validation_split_ratio, + scale=False, + ) + + verify_sequential_id_sampled_sequential_dataloaders_equal_dataloaders( + dataloaders, train_split_ratio, validation_split_ratio, num_ids + ) + + +def test_id_wise_weighted_sampling_does_not_put_id_in_multiple_dataloaders(): + data = list() + num_ids = 150 + sample_id = 0 + + for sequence_id in range(num_ids): + for sequence in range(40 + (int(sequence_id * 2.234) % 117)): + data.append([sequence, sample_id, sequence_id]) + sample_id += 1 + + df = pd.DataFrame(data, columns=["x", "y", "ID"]) + + # Hyperparameters + batch_size = 10 + num_past = 10 + num_future = 5 + train_split_ratio = 0.333 + validation_split_ratio = 0.333 + + dataloaders = dataset.MultiModalDataLoader( + df, + batch_size=batch_size, + n_past=num_past, + n_future=num_future, + num_workers=1, + train_split_ratio=train_split_ratio, + validation_split_ratio=validation_split_ratio, + scale=False, + weighted_sampling=True, + stride=1, + ) + + verify_id_wise_sampled_dataloaders_do_not_overlap( + dataloaders, train_split_ratio, validation_split_ratio, num_ids + ) + + +def extract_sample_ids_from_dataloader(dataloader): + sample_ids = list() + for data, target, ids, parameters, classes in dataloader: + for index, sequence_id in enumerate(ids): + sample_ids.append(int(data[index][0][1])) + return sample_ids + + +def verify_id_wise_sampled_dataloaders_do_not_overlap( + dataloaders, train_split_ratio, validation_split_ratio, num_ids, expect_all_ids=True +): + train_ids = [] # We check that the sequence IDs are not mixed + train_sample_ids = [] # We also check that the sample IDs do not overlap + for data, target, ids, parameters, classes in dataloaders["train_loader"]: + for index, sequence_id in enumerate(ids): + sequence_id = int(sequence_id) + if sequence_id not in train_ids: + train_ids.append(sequence_id) + train_sample_ids.append(int(data[index][0][1])) + + test_ids = [] + test_sample_ids = [] + for data, target, ids, parameters, classes in dataloaders["test_loader"]: + for index, sequence_id in enumerate(ids): + sequence_id = int(sequence_id) + if sequence_id not in test_ids: + test_ids.append(sequence_id) + test_sample_ids.append(int(data[index][0][1])) + + assert sequence_id not in train_ids, "Found test data in train loader!" + + validation_ids = [] + validation_sample_ids = [] + for data, target, ids, parameters, classes in dataloaders["validation_loader"]: + for index, sequence_id in enumerate(ids): + sequence_id = int(sequence_id) + if sequence_id not in validation_ids: + validation_ids.append(sequence_id) + validation_sample_ids.append(int(data[index][0][1])) + + assert ( + sequence_id not in train_ids + ), "Found validation data in train loader!" + assert sequence_id not in test_ids, "Found validation data in test loader!" + + if expect_all_ids: + assert len(train_ids) == round( + train_split_ratio * num_ids + ), "Wrong number of training ids!" + assert len(validation_ids) == round( + validation_split_ratio * num_ids + ), "Wrong number of validation ids!" + assert ( + len(train_ids) + len(test_ids) + len(validation_ids) == num_ids + ), "Wrong number of ids!" + + return ( + train_ids, + train_sample_ids, + test_ids, + test_sample_ids, + validation_ids, + validation_sample_ids, + ) + + +def verify_sequential_id_sampled_sequential_dataloaders_equal_dataloaders( + dataloaders, train_split_ratio, validation_split_ratio, num_ids, expect_all_ids=True +): + ( + train_ids, + train_sample_ids, + test_ids, + test_sample_ids, + validation_ids, + validation_sample_ids, + ) = verify_id_wise_sampled_dataloaders_do_not_overlap( + dataloaders, train_split_ratio, validation_split_ratio, num_ids, expect_all_ids + ) + + # We check that all sample IDs are present in the sequential samplers and vice versa + train_sequential_sample_ids = [] + for data, target, ids, parameters, classes in dataloaders[ + "sequential_train_loader" + ]: + for index, sequence_id in enumerate(ids): + sequence_id = int(sequence_id) + train_sequential_sample_ids.append(int(data[index][0][1])) + assert sequence_id in train_ids, f"train_ids missing id {sequence_id}!" + + train_sample_ids = sorted(train_sample_ids) + assert len(train_sample_ids) == len( + train_sequential_sample_ids + ), "train and sequential_train loaders have different lengths!" + for index in range(len(train_sample_ids)): + assert ( + train_sample_ids[index] == train_sequential_sample_ids[index] + ), f"Index {train_sample_ids[index]} is not equal to {train_sequential_sample_ids[index]}!" + + test_sequential_sample_ids = [] + for data, target, ids, parameters, classes in dataloaders["sequential_test_loader"]: + for index, sequence_id in enumerate(ids): + sequence_id = int(sequence_id) + test_sequential_sample_ids.append(int(data[index][0][1])) + assert sequence_id in test_ids, f"test_ids missing id {sequence_id}!" + + test_sample_ids = sorted(test_sample_ids) + assert len(test_sample_ids) == len( + test_sequential_sample_ids + ), "test and sequential_test loaders have different lengths!" + for index in range(len(test_sample_ids)): + assert ( + test_sample_ids[index] == test_sequential_sample_ids[index] + ), f"Index {test_sample_ids[index]} is not equal to {test_sequential_sample_ids[index]}!" + + validation_sequential_sample_ids = [] + for data, target, ids, parameters, classes in dataloaders[ + "sequential_validation_loader" + ]: + for index, sequence_id in enumerate(ids): + sequence_id = int(sequence_id) + validation_sequential_sample_ids.append(int(data[index][0][1])) + assert ( + sequence_id in validation_ids + ), f"validation_ids missing id {sequence_id}!" + + validation_sample_ids = sorted(validation_sample_ids) + assert len(validation_sample_ids) == len( + validation_sequential_sample_ids + ), "validation and sequential_validation loaders have different lengths!" + for index in range(len(validation_sample_ids)): + assert ( + validation_sample_ids[index] == validation_sequential_sample_ids[index] + ), f"Index {validation_sample_ids[index]} is not equal to {validation_sequential_sample_ids[index]}!" + + verify_that_indices_belong_to_precisely_one_loader( + train_sample_ids, test_sample_ids, validation_sample_ids + ) + # Check that all indices belong to precisely one loader + # Note that (because some samples are dropped and because we only check the first value in data) + # not all indices are in a loader. + train_index = 0 + test_index = 0 + validation_index = 0 + for index in range( + len(train_sample_ids) + len(test_sample_ids) + len(validation_sample_ids) + ): + if train_sample_ids[train_index] < index: + train_index += 1 + if test_sample_ids[test_index] < index: + test_index += 1 + if validation_sample_ids[validation_index] < index: + validation_index += 1 + index_is_in_train = train_sample_ids[train_index] == index + index_is_in_test = test_sample_ids[test_index] == index + index_is_in_validation = validation_sample_ids[validation_index] == index + + assert not ( + index_is_in_train and index_is_in_test + ), f"Index {index} is in both the train and test loaders!" + assert not ( + index_is_in_train and index_is_in_validation + ), f"Index {index} is in both the train and validation loaders!" + assert not ( + index_is_in_test and index_is_in_validation + ), f"Index {index} is in both the test and validation loaders!" + + +def verify_that_indices_belong_to_precisely_one_loader( + train_sample_ids, test_sample_ids, validation_sample_ids +): + # Check that all indices belong to precisely one loader + # Note that (because some samples are dropped and because we only check the first value in data) + # not all indices are in a loader. + train_index = 0 + test_index = 0 + validation_index = 0 + for index in range( + len(train_sample_ids) + len(test_sample_ids) + len(validation_sample_ids) + ): + if train_sample_ids[train_index] < index: + train_index += 1 + if test_sample_ids[test_index] < index: + test_index += 1 + if validation_sample_ids[validation_index] < index: + validation_index += 1 + index_is_in_train = train_sample_ids[train_index] == index + index_is_in_test = test_sample_ids[test_index] == index + index_is_in_validation = validation_sample_ids[validation_index] == index + + assert not ( + index_is_in_train and index_is_in_test + ), f"Index {index} is in both the train and test loaders!" + assert not ( + index_is_in_train and index_is_in_validation + ), f"Index {index} is in both the train and validation loaders!" + assert not ( + index_is_in_test and index_is_in_validation + ), f"Index {index} is in both the test and validation loaders!" + + +def test_sequential_data_loader_indices_are_sequential(): + data = list() + num_ids = 46 + + for sample_id in range(num_ids): + for sequence in range(40 + int(sample_id / 14)): + data.append([sequence, sequence, sample_id]) + + df = pd.DataFrame(data, columns=["x", "y", "ID"]) + + # Hyperparameters + batch_size = 18 + num_past = 13 + num_future = 8 + train_split_ratio = 0.5 + validation_split_ratio = 0.2 + stride = 1 + + dataloaders = dataset.MultiModalDataLoader( + df, + batch_size=batch_size, + n_past=num_past, + n_future=num_future, + num_workers=1, + train_split_ratio=train_split_ratio, + validation_split_ratio=validation_split_ratio, + stride=stride, + ) + + current_id = 0 + for data, target, ids, parameters, classes in dataloaders[ + "sequential_train_loader" + ]: + for id in ids: + id = int(id) + if id > current_id: + current_id = id + assert ( + id == current_id + ), "IDs in sequential train loader should increase monotonically!" + + current_id = 0 + for data, target, ids, parameters, classes in dataloaders["sequential_test_loader"]: + for id in ids: + id = int(id) + if id > current_id: + current_id = id + assert ( + id == current_id + ), "IDs in sequential test loader should increase monotonically!" + + +def test_pituitary_gland_latin_hypercube_generator_gives_correct_number_of_samples(): + num_samples = 30 + _, num_samples_out = create_latin_hypercube_sampled_pituitary_df(samples=num_samples) + + assert num_samples == num_samples_out, "Hypercube sampler returned the wrong number of samples!" diff --git a/traja/tests/test_losses.py b/traja/tests/test_losses.py new file mode 100644 index 00000000..fc39db00 --- /dev/null +++ b/traja/tests/test_losses.py @@ -0,0 +1,32 @@ +import torch + +from traja.models.losses import Criterion + + +def test_forecasting_loss_yields_correct_value(): + criterion = Criterion() + + predicted = torch.ones((1, 8)) + target = torch.zeros((1, 8)) + + manhattan_loss = criterion.forecasting_criterion( + predicted, target, loss_type="manhattan" + ) # 8 + huber_low_loss = criterion.forecasting_criterion( + predicted * 0.5, target, loss_type="huber" + ) # ~1 + huber_high_loss = criterion.forecasting_criterion( + predicted * 2, target, loss_type="huber" + ) # ~12 + mse_low_loss = criterion.forecasting_criterion( + predicted * 0.5, target, loss_type="mse" + ) # 0.25 + mse_high_loss = criterion.forecasting_criterion( + predicted * 2, target, loss_type="mse" + ) # 4 + + assert manhattan_loss == 8 + assert huber_low_loss == 1 + assert huber_high_loss == 12 + assert mse_low_loss == 0.25 + assert mse_high_loss == 4 diff --git a/traja/tests/test_models.py b/traja/tests/test_models.py new file mode 100644 index 00000000..61a9f157 --- /dev/null +++ b/traja/tests/test_models.py @@ -0,0 +1,560 @@ +import numpy as np +import pandas as pd + +import traja +from traja.dataset import dataset +from traja.dataset.example import jaguar +from traja.models import LSTM +from traja.models import MultiModelAE +from traja.models import MultiModelVAE +from traja.models.train import HybridTrainer + + +def test_aevae_jaguar(): + """ + Test variational autoencoder forecasting with the Jaguar dataset + """ + + # Sample data + df = jaguar() + + # Hyperparameters + batch_size = 10 + num_past = 10 + num_future = 5 + # Prepare the dataloader + data_loaders = dataset.MultiModalDataLoader( + df, + batch_size=batch_size, + n_past=num_past, + n_future=num_future, + train_split_ratio=0.5, + num_workers=1, + split_by_id=False, + ) + + model_save_path = "./model.pt" + + model = MultiModelVAE( + input_size=2, + output_size=2, + lstm_hidden_size=32, + num_lstm_layers=2, + latent_size=10, + dropout=0.1, + batch_size=batch_size, + num_future=num_future, + num_past=num_past, + bidirectional=False, + batch_first=True, + reset_state=True, + ) + + # Test that we can run functions on our network. + model.disable_latent_output() + model.enable_latent_output() + + # Model Trainer + # Model types; "ae" or "vae" + trainer = HybridTrainer(model=model, optimizer_type="Adam", loss_type="huber") + + # Train the model + trainer.fit(data_loaders, model_save_path, epochs=1, training_mode="forecasting", validate_every=5, test_every=10) + + scaler = data_loaders["train_loader"].dataset.scaler + + # Load the trained model given the path + model_path = "./model.pt" + hyperparams = "./hypers.json" + model_hyperparameters = traja.models.read_hyperparameters(hyperparams) + + # For prebuild traja generative models + generator = traja.models.inference.Generator( + model_type="vae", + model_hyperparameters=model_hyperparameters, + model_path=model_path, + model=None, + ) + out = generator.generate(num_future, classify=False, scaler=scaler, plot_data=False) + + trainer.validate(data_loaders["validation_loader"]) + + +def test_ae_jaguar(): + """ + Test autoencoder forecasting with the Jaguar dataset + """ + + # Sample data + df = jaguar() + + # Hyperparameters + batch_size = 10 + num_past = 10 + num_future = 5 + # Prepare the dataloader + data_loaders = dataset.MultiModalDataLoader( + df, + batch_size=batch_size, + n_past=num_past, + n_future=num_future, + num_workers=1, + train_split_ratio=0.5, + validation_split_ratio=0.2, + ) + + model_save_path = "./model.pt" + + model = MultiModelAE( + input_size=2, + num_past=num_past, + batch_size=batch_size, + num_future=num_future, + lstm_hidden_size=32, + num_lstm_layers=2, + output_size=2, + latent_size=10, + batch_first=True, + dropout=0.1, + reset_state=True, + bidirectional=False, + ) + + # Model Trainer + # Model types; "ae" or "vae" + trainer = HybridTrainer(model=model, optimizer_type="Adam", loss_type="huber") + + # Train the model + trainer.fit(data_loaders, model_save_path, epochs=1, training_mode="forecasting", validate_every=2, test_every=5) + trainer.fit(data_loaders, model_save_path, epochs=1, training_mode="forecasting", validate_every=None, test_every=5) + trainer.fit(data_loaders, model_save_path, epochs=1, training_mode="forecasting", validate_every=2, test_every=None) + + trainer.validate(data_loaders["sequential_validation_loader"]) + + +def test_lstm_jaguar(): + """ + Testing method for lstm model used for forecasting. + """ + + # Sample data + df = jaguar() + + # Hyperparameters + batch_size = 10 + num_past = 10 + num_future = 10 + + # For timeseries prediction + assert num_past == num_future + + # Prepare the dataloader + data_loaders = dataset.MultiModalDataLoader( + df, batch_size=batch_size, n_past=num_past, n_future=num_future, num_workers=1 + ) + + model_save_path = "./model.pt" + + # Model init + model = LSTM( + input_size=2, + hidden_size=32, + num_layers=2, + output_size=2, + dropout=0.1, + batch_size=batch_size, + num_future=num_future, + bidirectional=False, + batch_first=True, + reset_state=True, + ) + + # Model Trainer + trainer = HybridTrainer(model=model, + optimizer_type='Adam', + loss_type='huber') + + forecasting_loss_pre_training, _, _ = trainer.validate(data_loaders['train_loader']) + print(f'Loss pre training: {forecasting_loss_pre_training}') + + # Train the model + trainer.fit(data_loaders, model_save_path, epochs=2, training_mode="forecasting", validate_every=1, test_every=2) + + forecasting_loss_post_training, _, _ = trainer.validate(data_loaders['train_loader']) + + print(f'Loss post training: {forecasting_loss_post_training}') + assert forecasting_loss_post_training < forecasting_loss_pre_training + + +def test_aevae_regression_network_converges(): + """ + Test Autoencoder and variational auto encoder models for training/testing/generative network and + classification networks + + """ + + data = list() + num_ids = 3 + + for sample_id in range(num_ids): + for sequence in range(70 + sample_id * 4): + parameter_one = 0.2 * sample_id + parameter_two = 91.235 * sample_id + data.append([sequence, sequence, sample_id, parameter_one, parameter_two]) + # Sample data + df = pd.DataFrame(data, columns=["x", "y", "ID", "parameter_one", "parameter_two"]) + + parameter_columns = ["parameter_one", "parameter_two"] + + # Hyperparameters + batch_size = 1 + num_past = 10 + num_future = 5 + # Prepare the dataloader + data_loaders = dataset.MultiModalDataLoader( + df, + batch_size=batch_size, + n_past=num_past, + n_future=num_future, + train_split_ratio=0.333, + validation_split_ratio=0.333, + num_workers=1, + parameter_columns=parameter_columns, + split_by_id=False, + stride=1, + ) + + model_save_path = "./model.pt" + + model = MultiModelVAE( + input_size=2, + output_size=2, + lstm_hidden_size=32, + num_lstm_layers=2, + num_regressor_parameters=len(parameter_columns), + latent_size=10, + dropout=0.1, + num_regressor_layers=4, + regressor_hidden_size=32, + batch_size=batch_size, + num_future=num_future, + num_past=num_past, + bidirectional=False, + batch_first=True, + reset_state=True, + ) + + # Test resetting the regressor, to make sure this function works + model.reset_regressor(regressor_hidden_size=32, num_regressor_layers=4) + + # Model Trainer + # Model types; "ae" or "vae" + trainer = HybridTrainer(model=model, optimizer_type="Adam", loss_type="mse") + + _, regression_lost_pre_training, _ = trainer.validate(data_loaders['train_loader']) + + print(f'Loss pre training: {regression_lost_pre_training}') + + # Train the model + trainer.fit(data_loaders, model_save_path, epochs=2, training_mode="forecasting", validate_every=1, test_every=2) + trainer.fit(data_loaders, model_save_path, epochs=2, training_mode="regression", validate_every=1, test_every=2) + + _, regression_lost_post_training, _ = trainer.validate(data_loaders['train_loader']) + + print(f'Loss post training: {regression_lost_post_training}') + assert regression_lost_post_training < regression_lost_pre_training + + +def test_ae_regression_network_converges(): + """ + Test that Autoencoder and variational auto encoder models for regression networks converge + """ + + data = list() + num_ids = 3 + + for sample_id in range(num_ids): + for sequence in range(70 + sample_id * 4): + parameter_one = 0.2 * sample_id + parameter_two = 91.235 * sample_id + data.append([sequence, sequence, sample_id, parameter_one, parameter_two]) + # Sample data + df = pd.DataFrame(data, columns=["x", "y", "ID", "parameter_one", "parameter_two"]) + + parameter_columns = ["parameter_one", "parameter_two"] + + # Hyperparameters + batch_size = 1 + num_past = 10 + num_future = 5 + # Prepare the dataloader + data_loaders = dataset.MultiModalDataLoader(df, + batch_size=batch_size, + n_past=num_past, + n_future=num_future, + train_split_ratio=0.333, + validation_split_ratio=0.333, + num_workers=1, + parameter_columns=parameter_columns, + split_by_id=False, + stride=1) + + model_save_path = './model.pt' + + model = MultiModelAE(input_size=2, + output_size=2, + lstm_hidden_size=32, + num_lstm_layers=2, + num_regressor_parameters=len(parameter_columns), + latent_size=10, + dropout=0.1, + num_regressor_layers=4, + regressor_hidden_size=32, + batch_size=batch_size, + num_future=num_future, + num_past=num_past, + bidirectional=False, + batch_first=True, + reset_state=True) + + # Test resetting the regressor, to make sure this function works + model.reset_regressor(regressor_hidden_size=32, num_regressor_layers=4) + + # Model Trainer + # Model types; "ae" or "vae" + trainer = HybridTrainer(model=model, + optimizer_type='Adam', + loss_type='mse') + + _, regression_lost_pre_training, _ = trainer.validate(data_loaders['train_loader']) + + print(f'Loss pre training: {regression_lost_pre_training}') + + # Train the model + trainer.fit(data_loaders, model_save_path, epochs=2, training_mode='forecasting', validate_every=1, test_every=2) + trainer.fit(data_loaders, model_save_path, epochs=2, training_mode='regression', validate_every=1, test_every=2) + + _, regression_lost_post_training, _ = trainer.validate(data_loaders['train_loader']) + + print(f'Loss post training: {regression_lost_post_training}') + assert regression_lost_post_training < regression_lost_pre_training + + +def test_vae_regression_network_converges(): + """ + Test that Autoencoder and variational auto encoder models for regression networks converge + """ + + data = list() + num_ids = 3 + + for sample_id in range(num_ids): + for sequence in range(70 + sample_id * 4): + parameter_one = 0.2 * sample_id + parameter_two = 91.235 * sample_id + data.append([sequence, sequence, sample_id, parameter_one, parameter_two]) + # Sample data + df = pd.DataFrame(data, columns=['x', 'y', 'ID', 'parameter_one', 'parameter_two']) + + parameter_columns = ['parameter_one', 'parameter_two'] + + # Hyperparameters + batch_size = 1 + num_past = 10 + num_future = 5 + # Prepare the dataloader + data_loaders = dataset.MultiModalDataLoader(df, + batch_size=batch_size, + n_past=num_past, + n_future=num_future, + train_split_ratio=0.333, + validation_split_ratio=0.333, + num_workers=1, + parameter_columns=parameter_columns, + split_by_id=False, + stride=1) + + model_save_path = './model.pt' + + model = MultiModelVAE(input_size=2, + output_size=2, + lstm_hidden_size=32, + num_lstm_layers=2, + num_regressor_parameters=len(parameter_columns), + latent_size=10, + dropout=0.1, + num_regressor_layers=4, + regressor_hidden_size=32, + batch_size=batch_size, + num_future=num_future, + num_past=num_past, + bidirectional=False, + batch_first=True, + reset_state=True) + + # Test resetting the regressor, to make sure this function works + model.reset_regressor(regressor_hidden_size=32, num_regressor_layers=4) + + # Model Trainer + # Model types; "ae" or "vae" + trainer = HybridTrainer(model=model, optimizer_type="Adam", loss_type="mse") + + _, regression_lost_pre_training, _ = trainer.validate(data_loaders['train_loader']) + + print(f'Loss pre training: {regression_lost_pre_training}') + + # Train the model + trainer.fit(data_loaders, model_save_path, epochs=2, training_mode="forecasting", validate_every=1, test_every=2) + trainer.fit(data_loaders, model_save_path, epochs=2, training_mode="regression", validate_every=1, test_every=2) + + _, regression_lost_post_training, _ = trainer.validate(data_loaders['train_loader']) + + print(f'Loss post training: {regression_lost_post_training}') + assert regression_lost_post_training < regression_lost_pre_training + + +def test_ae_classification_network_converges(): + """ + Test that Autoencoder and variational auto encoder models for classification networks converge + """ + + data = list() + num_ids = 8 + + for sample_id in range(num_ids): + sample_class = sample_id % 2 + for sequence in range(70 + sample_id * 4): + xx = sample_class * np.sin(sequence / 20.0) + (sample_class - 1) * sequence + yy = sample_class * np.cos(sequence / 20.0) + (sample_class - 1) * sequence + data.append([xx, yy, sample_id, sample_class]) + # Sample data + df = pd.DataFrame(data, columns=['x', 'y', 'ID', 'class']) + # Hyperparameters + batch_size = 2 + num_past = 10 + num_future = 5 + # Prepare the dataloader + data_loaders = dataset.MultiModalDataLoader( + df, + batch_size=batch_size, + n_past=num_past, + n_future=num_future, + train_split_ratio=0.333, + validation_split_ratio=0.333, + num_workers=1, + split_by_id=False, + stride=1, + ) + + model_save_path = "./model.pt" + + model = MultiModelAE( + input_size=2, + output_size=2, + lstm_hidden_size=32, + num_lstm_layers=2, + num_classes=2, + latent_size=10, + dropout=0.1, + num_classifier_layers=4, + classifier_hidden_size=32, + batch_size=batch_size, + num_future=num_future, + num_past=num_past, + bidirectional=False, + batch_first=True, + reset_state=True, + ) + + # Test resetting the classifier, to make sure this function works + model.reset_classifier(classifier_hidden_size=32, num_classifier_layers=4) + + # Model Trainer + # Model types; "ae" or "vae" + trainer = HybridTrainer(model=model, optimizer_type="Adam", loss_type="mse") + + _, _, classification_loss_pre_training = trainer.validate(data_loaders['train_loader']) + + print(f'Loss pre training: {classification_loss_pre_training}') + + # Train the model + trainer.fit(data_loaders, model_save_path, epochs=2, training_mode='forecasting', validate_every=1, test_every=2) + trainer.fit(data_loaders, model_save_path, epochs=2, training_mode='classification', validate_every=1, test_every=2) + + _, _, classification_loss_post_training = trainer.validate(data_loaders['train_loader']) + + print(f'Loss post training: {classification_loss_post_training}') + assert classification_loss_post_training < classification_loss_pre_training + + +def test_vae_classification_network_converges(): + """ + Test that Autoencoder and variational auto encoder models for classification networks converge + """ + + data = list() + num_ids = 8 + + for sample_id in range(num_ids): + sample_class = sample_id % 2 + for sequence in range(70 + sample_id * 4): + xx = sample_class * np.sin(sequence / 20.0) + (sample_class - 1) * sequence + yy = sample_class * np.cos(sequence / 20.0) + (sample_class - 1) * sequence + data.append([xx, yy, sample_id, sample_class]) + # Sample data + df = pd.DataFrame(data, columns=['x', 'y', 'ID', 'class']) + + # Hyperparameters + batch_size = 2 + num_past = 10 + num_future = 5 + # Prepare the dataloader + data_loaders = dataset.MultiModalDataLoader(df, + batch_size=batch_size, + n_past=num_past, + n_future=num_future, + train_split_ratio=0.333, + validation_split_ratio=0.333, + num_workers=1, + split_by_id=False, + stride=1) + + model_save_path = './model.pt' + + model = MultiModelVAE(input_size=2, + output_size=2, + lstm_hidden_size=32, + num_lstm_layers=2, + num_classes=2, + latent_size=10, + dropout=0.1, + num_classifier_layers=4, + classifier_hidden_size=32, + batch_size=batch_size, + num_future=num_future, + num_past=num_past, + bidirectional=False, + batch_first=True, + reset_state=True) + + # Test resetting the classifier, to make sure this function works + model.reset_classifier(classifier_hidden_size=32, num_classifier_layers=4) + + # Model Trainer + # Model types; "ae" or "vae" + trainer = HybridTrainer(model=model, + optimizer_type='Adam', + loss_type='mse') + + _, _, classification_loss_pre_training = trainer.validate(data_loaders['train_loader']) + + print(f'Loss pre training: {classification_loss_pre_training}') + + # Train the model + trainer.fit(data_loaders, model_save_path, epochs=2, training_mode="forecasting", validate_every=1, test_every=2) + trainer.fit(data_loaders, model_save_path, epochs=2, training_mode="classification", validate_every=1, test_every=2) + + _, _, classification_loss_post_training = trainer.validate(data_loaders['train_loader']) + + print(f'Loss post training: {classification_loss_post_training}') + assert classification_loss_post_training < classification_loss_pre_training diff --git a/traja/tests/test_optimizers.py b/traja/tests/test_optimizers.py new file mode 100644 index 00000000..2ca3f5d9 --- /dev/null +++ b/traja/tests/test_optimizers.py @@ -0,0 +1,34 @@ +from traja.models.optimizers import Optimizer +from traja.models.predictive_models.ae import MultiModelAE + + +def test_get_optimizers(): + # Test + model_type = "custom" + model = MultiModelAE( + input_size=2, + num_past=10, + batch_size=5, + num_future=5, + lstm_hidden_size=32, + num_lstm_layers=2, + output_size=2, + latent_size=10, + batch_first=True, + dropout=0.2, + reset_state=True, + bidirectional=True, + num_classifier_layers=4, + classifier_hidden_size=32, + num_classes=10, + num_regressor_layers=2, + regressor_hidden_size=32, + num_regressor_parameters=3, + ) + + # Get the optimizers + opt = Optimizer(model_type, model, optimizer_type="RMSprop") + model_optimizers = opt.get_optimizers(lr=0.1) + model_schedulers = opt.get_lrschedulers(factor=0.1, patience=10) + + print(model_optimizers, model_schedulers) diff --git a/traja/tests/test_parsers.py b/traja/tests/test_parsers.py new file mode 100644 index 00000000..7d468f17 --- /dev/null +++ b/traja/tests/test_parsers.py @@ -0,0 +1,27 @@ +import os + +import numpy as np +import pandas as pd + +import traja + +df = traja.generate(n=20) + + +def test_from_df(): + df = pd.DataFrame({"x": [1, 2, 3], "y": [2, 3, 4]}) + trj = traja.parsers.from_df(df) + np.testing.assert_allclose(df, trj) + assert isinstance(trj, traja.TrajaDataFrame) + + +def test_read_file(): + datapath = os.path.join(traja.__path__[0], "tests", "data", "3527.csv") + trj = traja.parsers.read_file(datapath) + assert isinstance(trj, traja.TrajaDataFrame) + assert "Frame" in trj + assert "Time" in trj + assert "TrackId" in trj + assert "x" in trj + assert "y" in trj + assert "ValueChanged" in trj diff --git a/traja/tests/test_plotting.py b/traja/tests/test_plotting.py new file mode 100644 index 00000000..a7469d89 --- /dev/null +++ b/traja/tests/test_plotting.py @@ -0,0 +1,188 @@ +import warnings + +import matplotlib +import numpy as np +import numpy.testing as npt + +from traja.dataset import dataset +from traja.dataset.example import jaguar +from traja.models.generative_models.vae import MultiModelVAE +from traja.models.train import HybridTrainer +from traja.plotting import plot_prediction + +matplotlib.use("Agg") +import matplotlib.pyplot as plt +import pandas as pd + +import traja + +warnings.filterwarnings("ignore", category=UserWarning, module="matplotlib") + +df = traja.generate(n=10) + + +def test_stylize_axes(): + collection = traja.plot(df, interactive=False) + traja.plotting.stylize_axes(collection.axes) + + +def test_color_dark(): + df = traja.generate(n=10) + index = pd.DatetimeIndex(range(10)) + df.index = index + ax = plt.gca() + try: + traja.color_dark(df.x, ax) + except ValueError as e: + # catch unexplained datetime value error in travis + if "view limit minimum" in str(e): + pass + + +def test_sans_serif(): + traja.plotting.sans_serif() + + +def test_plot_3d(): + traja.plot_3d(df, interactive=False) + + +def test_plot_flow(): + traja.plot_flow(df, interactive=False) + + +def test_plot_contour(): + ax = traja.plot_contour(df, interactive=False) + + +def test_plot_surface(): + ax = traja.plot_surface(df, interactive=False) + + +def test_plot_stream(): + ax = traja.plot_stream(df, interactive=False) + + +def test_trip_grid(): + traja.plotting.trip_grid(df, interactive=False) + + +def test_label_axes(): + df.traja.plot(interactive=False) + ax = plt.gca() + traja.plotting._label_axes(df, ax) + + +def test_plot_actogram(): + df = traja.generate(n=1000) + index = pd.date_range("2018-01-01", periods=1000, freq="T") + df.index = index + activity = traja.calc_displacement(df) + activity.name = "activity" + traja.plotting.plot_actogram(df.x, interactive=False) + + +def test_plot_xy(): + traja.plotting.plot_xy(df, interactive=False) + + +def test_polar_bar(): + traja.plotting.polar_bar(df, interactive=False) + + +def test_find_runs(): + actual = traja.find_runs(df.x) + expected = ( + np.array( + [ + 0.0, + 1.323_370_69, + 2.275_837_54, + 2.274_285_61, + 0.336_029_88, + -1.455_690_92, + -3.544_442_11, + -5.386_597_93, + -7.508_544_4, + -9.353_255_17, + ] + ), + np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), + np.array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1]), + ) + for i in range(len(actual)): + npt.assert_allclose(actual[i], expected[i]) + + +def test_plot_clustermap(): + trjs = [traja.generate(seed=i) for i in range(20)] + + # Calculate displacement + displacements = [trj.traja.calc_displacement() for trj in trjs] + + traja.plot_clustermap(displacements) + + +def test_plot(): + ax = traja.plotting.plot(df, interactive=False) + path = ax.get_paths()[0] + npt.assert_allclose( + path._vertices[:5], + np.array( + [ + [0.0, -0.5], + [0.132_601_55, -0.5], + [0.259_789_94, -0.447_316_85], + [0.353_553_39, -0.353_553_39], + [0.447_316_85, -0.259_789_94], + ] + ), + ) + + +def test_plot_prediction(): + # Hyperparameters + batch_size = 10 + num_past = 10 + num_future = 10 + + input_size = 2 + lstm_hidden_size = 512 + lstm_num_layers = 4 + batch_first = True + reset_state = True + output_size = 2 + num_classes = 9 + latent_size = 20 + dropout = 0.1 + bidirectional = False + + # Prepare the dataloader + df = jaguar() + data_loaders = dataset.MultiModalDataLoader( + df, batch_size=batch_size, n_past=num_past, n_future=num_future, num_workers=1 + ) + + model = MultiModelVAE( + input_size=input_size, + output_size=output_size, + lstm_hidden_size=lstm_hidden_size, + num_lstm_layers=lstm_num_layers, + num_classes=num_classes, + latent_size=latent_size, + dropout=dropout, + num_classifier_layers=4, + classifier_hidden_size=32, + batch_size=batch_size, + num_future=num_future, + num_past=num_past, + bidirectional=bidirectional, + batch_first=batch_first, + reset_state=reset_state, + ) + + trainer = HybridTrainer(model=model, optimizer_type="Adam", loss_type="huber") + + model_save_path = "./model.pt" + + plot_prediction(model, data_loaders["sequential_test_loader"], 1) diff --git a/traja/tests/test_stats.py b/traja/tests/test_stats.py new file mode 100644 index 00000000..84d60141 --- /dev/null +++ b/traja/tests/test_stats.py @@ -0,0 +1,73 @@ +from traja.stats.brownian import Brownian +import numpy as np + +def test_brownian_walk_generates_correct_number_of_samples(): + length = 1000000 + brownian = Brownian(length=length) + assert(len(brownian) == length) + + +def test_brownian_motion_with_drift_approximately_sums_to_the_drift(): + length = 1000000 + mean_drift = 0.1 + drift = 0 + + brownian = Brownian(length=length, mean_value=mean_drift) + + for i in range(length): + drift = brownian() + + drift /= length + + np.testing.assert_approx_equal(drift, mean_drift, significant=1) + + +def test_brownians_with_different_variances_drift_approximately_equally(): + length = 1000000 + mean_drift = -0.9 + variance1 = 0.8 + variance2 = 3.5 + + drift1 = 0 + drift2 = 0 + + brownian1 = Brownian(length=length, mean_value=mean_drift, variance=variance1) + brownian2 = Brownian(length=length, mean_value=mean_drift, variance=variance2) + + for i in range(length): + drift1 = brownian1() + drift2 = brownian2() + + drift1 /= length + drift2 /= length + + np.testing.assert_approx_equal(drift1, drift2, significant=1) + + +def test_brownians_with_different_time_steps_walk_approximately_equally(): + mean_drift = 0.23 + variance = 0.52 + + time_step_ratio = 7 + dt1 = 0.1 + dt2 = dt1 * time_step_ratio + + length2 = 200000 + length1 = length2 * time_step_ratio + + drift1 = 0 + drift2 = 0 + + brownian1 = Brownian(length=length1, mean_value=mean_drift, variance=variance, dt=dt1) + brownian2 = Brownian(length=length2, mean_value=mean_drift, variance=variance, dt=dt2) + + for i in range(length1): + drift1 = brownian1() + + for i in range(length2): + drift2 = brownian2() + + drift1 /= length1 + drift2 /= length2 + + np.testing.assert_approx_equal(drift1, drift2, significant=1) diff --git a/traja/tests/test_trajadataframe.py b/traja/tests/test_trajadataframe.py new file mode 100644 index 00000000..41949a1c --- /dev/null +++ b/traja/tests/test_trajadataframe.py @@ -0,0 +1,108 @@ +import os +import shutil +import tempfile + +import pandas as pd +from pandas import DataFrame + +import traja +from traja import TrajaDataFrame, read_file, TrajaCollection + + +class TestDataFrame: + def setup_method(self): + dirname = os.path.dirname(traja.__file__) + data_filename = os.path.join(dirname, "tests/data/3527.csv") + df = read_file(data_filename) + self.df = read_file(data_filename, xlim=(df.x.min(), df.x.max())) + self.tempdir = tempfile.mkdtemp() + + def teardown_method(self): + shutil.rmtree(self.tempdir) + + def test_df_init(self): + assert isinstance(self.df, TrajaDataFrame) + + # def test_copy(self): + # df2 = self.df.copy() + # assert (df2, TrajaDataFrame) + # assert df2.xlim == self.df.xlim + + def test_dataframe_to_trajadataframe(self): + df = DataFrame( + {"x": range(len(self.df)), "y": range(len(self.df))}, index=self.df.index + ) + + tf = TrajaDataFrame(df) + assert isinstance(df, DataFrame) + assert isinstance(tf, TrajaDataFrame) + + def test_construct_dataframe(self): + df = traja.TrajaDataFrame( + {"x": range(len(self.df)), "y": range(len(self.df))}, + index=self.df.index, + xlim=(0, 2), + ylim=(0, 2), + spatial_units="m", + title="Serious title", + fps=2.0, + time_units="s", + id=42, + ) + + assert df.title == "Serious title" + + # Test 'merge' + df2 = df.copy() + assert df2.title == "Serious title" + + assert df._get_time_col() == None + assert self.df._get_time_col() == "Time" + + # Modify metavar + df.set("title", "New title") + assert df.title == "New title" + + # Test __finalize__ + df_copy = df.copy() + df2_copy = df2.copy() + assert isinstance(df_copy, traja.TrajaDataFrame) + + +class TestTrajaCollection: + def setup_method(self): + dirname = os.path.dirname(traja.__file__) + data_filename = os.path.join(dirname, "tests/data/3527.csv") + df = read_file(data_filename) + df = read_file(data_filename, xlim=(df.x.min(), df.x.max())) + df2 = df.copy() + df2["TrackId"] = 2 + df2["x"] += 10 + self.coll = TrajaCollection({1: df, 2: df2}, id_col="TrackId") + self.tempdir = tempfile.mkdtemp() + + def teardown_method(self): + shutil.rmtree(self.tempdir) + + def test_collection_init(self): + assert isinstance(self.coll, TrajaCollection) + + # def test_copy(self): + # trjs = self.trjs.copy() + # assert (trjs, TrajaCollection) + # assert trjs.xlim == self.trjs.xlim + + def test_plot_collection(self): + self.coll.plot() + # Test with colors + self.coll.plot(colors={1: "red", 2: "blue"}) + + def test_apply_all(self): + angles = self.coll.apply_all(traja.calc_angle) + assert isinstance(angles, pd.DataFrame) + + # Test with multiple ids + coll_copy = self.coll.copy() + coll_copy.loc[coll_copy.index[:5], "TrackId"] = 1 + angles = coll_copy.apply_all(traja.calc_angle) + assert isinstance(angles, pd.Series) diff --git a/traja/tests/test_trajectory.py b/traja/tests/test_trajectory.py new file mode 100644 index 00000000..864889bd --- /dev/null +++ b/traja/tests/test_trajectory.py @@ -0,0 +1,668 @@ +import numpy as np +import numpy.testing as npt +import pytest +from pandas.util.testing import assert_series_equal + +import traja + +df = traja.generate(n=20, convex_hull=True) + + +def test_polar_to_z(): + df_copy = df.copy() + polar = traja.cartesian_to_polar(df_copy.traja.xy) + z = traja.polar_to_z(*polar) + z_actual = z[:10] + z_expected = np.array( + [ + 0.0 + 0.0j, + 1.162_605_74 + 1.412_179_34j, + 1.861_836_8 + 2.727_243_73j, + 1.860_393_36 + 4.857_966_96j, + -0.096_486_29 + 5.802_456_77j, + -1.735_291_68 + 4.940_704_34j, + -4.189_217_4 + 4.951_826_17j, + -5.712_624_22 + 4.177_006j, + -7.567_193_14 + 3.404_176_98j, + -9.415_289_13 + 2.743_725_89j, + ] + ) + + npt.assert_allclose(z_actual, z_expected) + + +def test_cartesian_to_polar(): + df_copy = df.copy() + xy = df_copy.traja.xy + + r_actual, theta_actual = traja.cartesian_to_polar(xy) + r_expected = np.array( + [ + 0.0, + 1.829_180_85, + 3.302_165_14, + 5.202_009_84, + 5.803_258_93, + 5.236_582_53, + 6.486_148_69, + 7.076_825_18, + 8.297_640_2, + 9.806_921_08, + ] + ) + theta_expected = np.array( + [ + 0.0, + 0.882_026_17, + 0.971_788_83, + 1.205_067_81, + 1.587_423_32, + 1.908_560_74, + 2.272_960_35, + 2.510_239_91, + 2.718_855_22, + 2.858_033_49, + ] + ) + + npt.assert_allclose(r_actual[:10], r_expected) + npt.assert_allclose(theta_actual[:10], theta_expected) + + +@pytest.mark.parametrize("eqn1", [True]) +def test_expected_sq_displacement(eqn1): + df_copy = df.copy() + disp = traja.expected_sq_displacement(df_copy, eqn1=eqn1) + if eqn1: + npt.assert_allclose(disp, 0.757_882_272_948_632_8) + + +def test_step_lengths(): + df_copy = df.copy() + step_lengths = traja.step_lengths(df_copy) + actual = step_lengths.to_numpy()[:5] + expected = np.array( + [np.nan, 1.829_180_85, 1.489_402_04, 2.130_723_72, 2.172_887_24] + ) + npt.assert_allclose(actual, expected) + assert len(step_lengths == len(df_copy)) + + +@pytest.mark.parametrize("w", [None, 6]) +def test_smooth_sg(w): + df_copy = df.copy() + if w == 6: + with pytest.raises(Exception): + _ = traja.trajectory.smooth_sg(df_copy, w=w) + else: + trj = traja.trajectory.smooth_sg(df_copy, w=w) + actual = trj.to_numpy()[:5] + if w is None: # 5 with default settings + expected = np.array( + [ + [0.014_535_17, 0.041_638_09, 0.0], + [1.104_465_06, 1.245_626_99, 0.02], + [1.949_047_82, 2.977_072_25, 0.04], + [1.557_970_03, 4.739_519_81, 0.06], + [0.195_517, 5.519_674_6, 0.08], + ] + ) + npt.assert_allclose(actual, expected) + else: + raise Exception(f"Not tested w=={w}") + assert trj.shape == df_copy.shape + + +@pytest.mark.parametrize("lag", [1, 2]) +def test_calc_angle(lag): + df_copy = df.copy() + angles = traja.calc_angle(df_copy, lag=lag) + actual = angles.to_numpy() + if lag == 1: + expected = np.array( + [ + np.nan, + 50.536_377_13, + 62.000_036_72, + 89.961_185_41, + 25.764_324_08, + 27.737_271_33, + 0.259_677_63, + 26.958_350_61, + 22.622_286, + 19.665_283_71, + 31.428_064_33, + 35.554_608_67, + 77.216_475_78, + 80.981_399_37, + 77.495_666_91, + 64.779_921_95, + 55.220_856_61, + 12.418_644_03, + 18.295_995_36, + 9.327_266_35, + ] + ) + elif lag == 2: + expected = np.array( + [ + np.nan, + np.nan, + 55.679_398_79, + 78.552_154_19, + 57.510_652_27, + 1.318_153_96, + 11.741_160_75, + 10.869_226_84, + 24.615_298_57, + 21.161_131_62, + 26.022_239_16, + 33.485_645_28, + 55.060_685_9, + 88.237_494_22, + 79.351_771_4, + 71.545_102_77, + 59.557_726_58, + 33.248_128_63, + 15.505_016_09, + 13.817_221_74, + ] + ) + + npt.assert_allclose(actual, expected) + + +def test_traj_from_coords(): + df_copy = df.copy() + coords = df_copy.traja.xy + trj = traja.traj_from_coords(coords, fps=50) + assert "dt" in trj + assert_series_equal(trj.x, df_copy.x) + assert_series_equal(trj.y, df_copy.y) + assert_series_equal(trj.time, df_copy.time) + + +@pytest.mark.parametrize("method", ["dtw", "hausdorff"]) +def test_distance(method): + df_copy = df.copy() + rotated = traja.trajectory.rotate(df_copy, 10).traja.xy[:10] + _ = traja.distance_between(rotated, df_copy.traja.xy, method=method) + + +@pytest.mark.parametrize("ndarray_type", [True, False]) +def test_grid_coords1D(ndarray_type): + df_copy = df.copy() + xlim, ylim = traja.trajectory._get_xylim(df_copy) + bins = traja.trajectory._bins_to_tuple(df_copy, None) + grid_indices = traja.grid_coordinates(df_copy, bins=bins, xlim=xlim, ylim=ylim) + if ndarray_type: + grid_indices = grid_indices.values + grid_indices1D = traja._grid_coords1D(grid_indices) + assert isinstance(grid_indices1D, np.ndarray) + + +def test_to_shapely(): + df_copy = df.copy() + actual = traja.to_shapely(df_copy).bounds + expected = ( + -13.699_062_135_959_585, + -10.144_216_927_960_029, + 1.861_836_800_674_031_3, + 5.802_456_768_595_229, + ) + npt.assert_allclose(actual, expected, rtol=1e-1) + + +def test_transition_matrix(): + df_copy = df.copy() + grid_indices = traja.grid_coordinates(df_copy) + assert grid_indices.shape[1] == 2 + grid_indices1D = traja._grid_coords1D(grid_indices) + _ = traja.transition_matrix(grid_indices1D) + + +def test_calc_laterality(): + df_copy = df.copy() + right_turns, left_turns = traja.calc_laterality(df_copy, dist_thresh=1) + assert left_turns == 4 + assert right_turns == 0 + + +def test_calc_flow_angles(): + df_copy = df.copy() + grid_indices = traja.grid_coordinates(df_copy) + U, V = traja.calc_flow_angles(grid_indices.values) + actual = U.sum() + expected = -2.707_106_781_186_548_3 + npt.assert_allclose(actual, expected) + + +def test_resample_time(): + df_copy = df.copy() + trj = traja.resample_time(df_copy, "3s") + assert isinstance(trj, traja.TrajaDataFrame) + + +def test_transitions(): + df_copy = df.copy() + transitions = traja.transitions(df_copy) + assert isinstance(transitions, np.ndarray) + + # Check when bins set + bins = traja._bins_to_tuple(df_copy, bins=None) + xmin = df_copy.x.min() + xmax = df_copy.x.max() + ymin = df_copy.y.min() + ymax = df_copy.y.max() + xbins = np.linspace(xmin, xmax, bins[0]) + ybins = np.linspace(ymin, ymax, bins[1]) + xbin = np.digitize(df_copy.x, xbins) + ybin = np.digitize(df_copy.y, ybins) + + df_copy.set("xbin", xbin) + df_copy.set("ybin", ybin) + transitions = traja.transitions(df_copy) + assert isinstance(transitions, np.ndarray) + + +def test_grid_coordinates(): + df_copy = df.copy() + grid_indices = traja.trajectory.grid_coordinates(df_copy) + assert "xbin" in grid_indices + assert "ybin" in grid_indices + actual = grid_indices.xbin.mean() + npt.assert_allclose(actual, 3.95) + + actual = grid_indices[:10].to_numpy() + expected = np.array( + [[8, 6], [9, 7], [9, 8], [9, 9], [8, 9], [7, 9], [6, 9], [5, 8], [3, 8], [2, 8]] + ) + npt.assert_equal(actual, expected) + + +def test_generate(): + df = traja.generate(n=20) + actual = df.traja.xy[:3] + expected = np.array( + [[0.0, 0.0], [1.162_605_74, 1.412_179_34], [1.861_836_8, 2.727_243_73]] + ) + npt.assert_allclose(actual, expected, rtol=1e-1) + + +def test_rotate(): + df_copy = df.copy() + actual = traja.trajectory.rotate(df_copy, 10).traja.xy[:10] + expected = np.array( + [ + [18.646_466_67, 10.430_808_03], + [16.902_701_92, 9.878_370_62], + [15.600_574_26, 9.155_333_99], + [14.442_626_99, 7.366_719_52], + [15.570_766_59, 5.509_641_17], + [17.414_653_05, 5.341_168_38], + [19.467_621_74, 3.996_848_97], + [21.167_387_56, 3.818_213_04], + [23.143_938_84, 3.457_747_23], + [25.053_922_91, 3.006_509_7], + ] + ) + npt.assert_allclose(actual, expected, rtol=1e-1) + + +def test_rediscretize_points(): + df_copy = df.copy() + actual = traja.rediscretize_points(df_copy, R=0.1)[:10].to_numpy() + expected = np.array( + [ + [0.0, 0.0], + [0.063_558_82, 0.077_202_83], + [0.127_117_64, 0.154_405_65], + [0.190_676_46, 0.231_608_48], + [0.254_235_27, 0.308_811_31], + [0.317_794_09, 0.386_014_14], + [0.381_352_91, 0.463_216_96], + [0.444_911_73, 0.540_419_79], + [0.508_470_55, 0.617_622_62], + [0.572_029_37, 0.694_825_45], + ] + ) + + npt.assert_allclose(actual, expected, rtol=1e-1) + + +def test_calc_turn_angle(): + df_copy = df.copy() + actual = traja.trajectory.calc_turn_angle(df_copy).values[:10] + npt.assert_allclose( + actual, + np.array( + [ + np.nan, + np.nan, + 11.463_659_59, + 28.038_777_87, + 64.196_861_33, + 53.501_595_42, + -27.996_948_96, + 27.218_028_24, + -4.336_064_62, + -2.957_002_29, + ] + ), + rtol=1e-1, + ) + + +def test_calc_displacement(): + df_copy = df.copy() + displacement = traja.calc_displacement(df_copy) + actual = displacement.values[:10] + expected = np.array( + [ + np.nan, + 1.829_180_85, + 1.489_402_04, + 2.130_723_72, + 2.172_887_24, + 1.851_567, + 2.453_950_92, + 1.709_126_87, + 2.009_151_7, + 1.962_563_23, + ] + ) + + npt.assert_allclose(actual, expected, rtol=1e-1) + + +def test_calc_derivatives(): + df_copy = df.copy() + derivs = traja.calc_derivatives(df_copy) + assert "displacement" in derivs + assert "displacement_time" in derivs + actual = derivs.to_numpy()[:10] + expected = np.array( + [ + [np.nan, 0.0], + [1.829_180_85, 0.02], + [1.489_402_04, 0.04], + [2.130_723_72, 0.06], + [2.172_887_24, 0.08], + [1.851_567, 0.1], + [2.453_950_92, 0.12], + [1.709_126_87, 0.14], + [2.009_151_7, 0.16], + [1.962_563_23, 0.18], + ] + ) + + npt.assert_allclose(actual, expected, rtol=1e-1) + + +def test_calc_heading(): + df_copy = df.copy() + actual = traja.calc_heading(df_copy)[:10].values + expected = np.array( + [ + np.nan, + 50.536_377_13, + 62.000_036_72, + 90.038_814_59, + 154.235_675_92, + -152.262_728_67, + 179.740_322_37, + -153.041_649_39, + -157.377_714, + -160.334_716_29, + ] + ) + + npt.assert_allclose(actual, expected, rtol=1e-1) + + +def test_get_derivatives(): + df_copy = df.copy() + actual = traja.get_derivatives(df_copy)[:10].to_numpy() + expected = np.array( + [ + [np.nan, 0.000_000_00e00, np.nan, np.nan, np.nan, np.nan], + [ + 1.829_180_85e00, + 2.000_000_00e-02, + 9.145_904_26e01, + 2.000_000_00e-02, + np.nan, + np.nan, + ], + [ + 1.489_402_04e00, + 4.000_000_00e-02, + 7.447_010_18e01, + 4.000_000_00e-02, + -8.494_470_38e02, + 4.000_000_00e-02, + ], + [ + 2.130_723_72e00, + 6.000_000_00e-02, + 1.065_361_86e02, + 6.000_000_00e-02, + 1.603_304_21e03, + 6.000_000_00e-02, + ], + [ + 2.172_887_24e00, + 8.000_000_00e-02, + 1.086_443_62e02, + 8.000_000_00e-02, + 1.054_088_02e02, + 8.000_000_00e-02, + ], + [ + 1.851_567_00e00, + 1.000_000_00e-01, + 9.257_834_98e01, + 1.000_000_00e-01, + -8.033_006_10e02, + 1.000_000_00e-01, + ], + [ + 2.453_950_92e00, + 1.200_000_00e-01, + 1.226_975_46e02, + 1.200_000_00e-01, + 1.505_959_82e03, + 1.200_000_00e-01, + ], + [ + 1.709_126_87e00, + 1.400_000_00e-01, + 8.545_634_33e01, + 1.400_000_00e-01, + -1.862_060_15e03, + 1.400_000_00e-01, + ], + [ + 2.009_151_70e00, + 1.600_000_00e-01, + 1.004_575_85e02, + 1.600_000_00e-01, + 7.500_620_96e02, + 1.600_000_00e-01, + ], + [ + 1.962_563_23e00, + 1.800_000_00e-01, + 9.812_816_15e01, + 1.800_000_00e-01, + -1.164_711_84e02, + 1.800_000_00e-01, + ], + ] + ) + + npt.assert_allclose(actual, expected, rtol=1e-1) + + +def test_coords_to_flow(): + df_copy = df.copy() + grid_flow = traja.coords_to_flow(df_copy)[:10] + actual = grid_flow[0] + expected = np.array( + [ + [ + -13.699_062_14, + -11.970_073_37, + -10.241_084_59, + -8.512_095_82, + -6.783_107_05, + -5.054_118_28, + -3.325_129_51, + -1.596_140_74, + 0.132_848_03, + 1.861_836_8, + ], + [ + -13.699_062_14, + -11.970_073_37, + -10.241_084_59, + -8.512_095_82, + -6.783_107_05, + -5.054_118_28, + -3.325_129_51, + -1.596_140_74, + 0.132_848_03, + 1.861_836_8, + ], + [ + -13.699_062_14, + -11.970_073_37, + -10.241_084_59, + -8.512_095_82, + -6.783_107_05, + -5.054_118_28, + -3.325_129_51, + -1.596_140_74, + 0.132_848_03, + 1.861_836_8, + ], + [ + -13.699_062_14, + -11.970_073_37, + -10.241_084_59, + -8.512_095_82, + -6.783_107_05, + -5.054_118_28, + -3.325_129_51, + -1.596_140_74, + 0.132_848_03, + 1.861_836_8, + ], + [ + -13.699_062_14, + -11.970_073_37, + -10.241_084_59, + -8.512_095_82, + -6.783_107_05, + -5.054_118_28, + -3.325_129_51, + -1.596_140_74, + 0.132_848_03, + 1.861_836_8, + ], + [ + -13.699_062_14, + -11.970_073_37, + -10.241_084_59, + -8.512_095_82, + -6.783_107_05, + -5.054_118_28, + -3.325_129_51, + -1.596_140_74, + 0.132_848_03, + 1.861_836_8, + ], + [ + -13.699_062_14, + -11.970_073_37, + -10.241_084_59, + -8.512_095_82, + -6.783_107_05, + -5.054_118_28, + -3.325_129_51, + -1.596_140_74, + 0.132_848_03, + 1.861_836_8, + ], + [ + -13.699_062_14, + -11.970_073_37, + -10.241_084_59, + -8.512_095_82, + -6.783_107_05, + -5.054_118_28, + -3.325_129_51, + -1.596_140_74, + 0.132_848_03, + 1.861_836_8, + ], + [ + -13.699_062_14, + -11.970_073_37, + -10.241_084_59, + -8.512_095_82, + -6.783_107_05, + -5.054_118_28, + -3.325_129_51, + -1.596_140_74, + 0.132_848_03, + 1.861_836_8, + ], + [ + -13.699_062_14, + -11.970_073_37, + -10.241_084_59, + -8.512_095_82, + -6.783_107_05, + -5.054_118_28, + -3.325_129_51, + -1.596_140_74, + 0.132_848_03, + 1.861_836_8, + ], + ] + ) + + npt.assert_allclose(actual, expected, rtol=1e-1) + + +def test_from_xy(): + df_copy = df.copy() + expected = traja.from_xy(df_copy.traja.xy).values + actual = df_copy.traja.xy + npt.assert_allclose(expected, actual) + + +def test_calc_convex_hull(): + df_copy = df.copy() + expected = np.array( + [ + [-4.86747278, -10.14421693], + [1.8618368, 2.72724373], + [1.86039336, 4.85796696], + [-0.09648629, 5.80245677], + [-4.1892174, 4.95182617], + [-9.41528913, 2.74372589], + [-11.38346284, 1.54102389], + [-13.249669, 0.20718649], + [-13.69906214, -1.7734609], + [-13.37369615, -3.8234334], + [-12.97911277, -5.60264725], + [-12.29572211, -7.05360631], + [-11.19458371, -8.63916811], + [-7.07832674, -9.78109529], + [-4.86747278, -10.14421693], + ] + ) + actual = df_copy.convex_hull + npt.assert_allclose(expected, actual) diff --git a/traja/trajectory.py b/traja/trajectory.py new file mode 100644 index 00000000..a28c2305 --- /dev/null +++ b/traja/trajectory.py @@ -0,0 +1,1587 @@ +import logging +import math +from collections import OrderedDict +from typing import Callable, Optional, Union, Tuple + +import numpy as np +import pandas as pd +from pandas.core.dtypes.common import ( + is_datetime_or_timedelta_dtype, + is_datetime64_any_dtype, + is_timedelta64_dtype, +) +from scipy import signal +from scipy.spatial.distance import directed_hausdorff, euclidean + +import traja +from traja import TrajaDataFrame + +__all__ = [ + "_bins_to_tuple", + "_get_time_col", + "_get_xylim", + "_grid_coords1D", + "_has_cols", + "_rediscretize_points", + "_resample_time", + "calc_angle", + "calc_convex_hull", + "calc_derivatives", + "calc_displacement", + "calc_heading", + "calc_laterality", + "calc_turn_angle", + "calc_flow_angles", + "cartesian_to_polar", + "coords_to_flow", + "determine_colinearity", + "distance_between", + "distance", + "euclidean", + "expected_sq_displacement", + "fill_in_traj", + "from_xy", + "inside", + "generate", + "get_derivatives", + "grid_coordinates", + "length", + "polar_to_z", + "rediscretize_points", + "resample_time", + "return_angle_to_point", + "rotate", + "smooth_sg", + "speed_intervals", + "step_lengths", + "to_shapely", + "traj_from_coords", + "transition_matrix", + "transitions", +] + +logger = logging.getLogger("traja") + + +def smooth_sg(trj: TrajaDataFrame, w: int = None, p: int = 3): + """Returns ``DataFrame`` of trajectory after Savitzky-Golay filtering. + + Args: + trj (:class:`~traja.frame.TrajaDataFrame`): Trajectory + w (int): window size (Default value = None) + p (int): polynomial order (Default value = 3) + + Returns: + trj (:class:`~traja.frame.TrajaDataFrame`): Trajectory + + .. doctest:: + + >> df = traja.generate() + >> traja.smooth_sg(df, w=101).head() + x y time + 0 -11.194803 12.312742 0.00 + 1 -10.236337 10.613720 0.02 + 2 -9.309282 8.954952 0.04 + 3 -8.412910 7.335925 0.06 + 4 -7.546492 5.756128 0.08 + + """ + if w is None: + w = p + 3 - p % 2 + + if w % 2 != 1: + raise Exception(f"Invalid smoothing parameter w ({w}): n must be odd") + _trj = trj.copy() + _trj.x = signal.savgol_filter(_trj.x, window_length=w, polyorder=p, axis=0) + _trj.y = signal.savgol_filter(_trj.y, window_length=w, polyorder=p, axis=0) + _trj = fill_in_traj(_trj) + return _trj + + +def apply_all(trj: TrajaDataFrame, method: Callable, id_col: str, **kwargs): + """Applies method to all trajectories""" + return trj.groupby(by=id_col).apply(method, **kwargs) + + +def step_lengths(trj: TrajaDataFrame): + """Length of the steps of ``trj``. + + Args: + trj (:class:`~traja.frame.TrajaDataFrame`): Trajectory + + """ + displacement = traja.trajectory.calc_displacement(trj) + return displacement + + +def polar_to_z(r: float, theta: float) -> complex: + """Converts polar coordinates ``r`` and ``theta`` to complex number ``z``. + + Args: + r (float): step size + theta (float): angle + + Returns: + z (complex): complex number z + + """ + return r * np.exp(1j * theta) + + +def cartesian_to_polar(xy: np.ndarray) -> (float, float): + """Convert :class:`numpy.ndarray` ``xy`` to polar coordinates ``r`` and ``theta``. + + Args: + xy (:class:`numpy.ndarray`): x,y coordinates + + Returns: + r, theta (tuple of float): step-length and angle + + """ + assert xy.ndim == 2, f"Dimensions are {xy.ndim}, expecting 2" + x, y = np.split(xy, [-1], axis=1) + x, y = np.squeeze(x), np.squeeze(y) + r = np.sqrt(x * x + y * y) + theta = np.arctan2(y, x) + return r, theta + + +def distance(trj: TrajaDataFrame) -> float: + """Calculates the distance from start to end of trajectory, also called net distance, displacement, or bee-line + from start to finish. + + Args: + trj (:class:`~traja.frame.TrajaDataFrame`): Trajectory + + Returns: + distance (float) + + .. doctest:: + + >> df = traja.generate() + >> traja.distance(df) + 117.01507823153617 + + """ + start = trj.iloc[0][["x", "y"]].values + end = trj.iloc[-1][["x", "y"]].values + return np.linalg.norm(end - start) + + +def length(trj: TrajaDataFrame) -> float: + """Calculates the cumulative length of a trajectory. + + Args: + trj (:class:`~traja.frame.TrajaDataFrame`): Trajectory + + Returns: + length (float) + + .. doctest:: + + >> df = traja.generate() + >> traja.length(df) + 2001.142339606066 + + """ + displacement = trj.traja.calc_displacement() + return displacement.sum() + + +def expected_sq_displacement( + trj: TrajaDataFrame, n: int = 0, eqn1: bool = True +) -> float: + """Expected displacement. + + .. note:: + + This method is experimental and needs testing. + + """ + sl = traja.step_lengths(trj) + ta = traja.calc_angle(trj) + l1 = np.mean(sl) + l2 = np.mean(sl ** 2) + c = np.mean(np.cos(ta)) + s = np.mean(np.sin(ta)) + s2 = s ** 2 + + if eqn1: + # Eqn 1 + alpha = np.arctan2(s, c) + gamma = ((1 - c) ** 2 - s2) * np.cos((n + 1) * alpha) - 2 * s * ( + 1 - c + ) * np.sin((n + 1) * alpha) + esd = ( + n * l2 + + 2 * l1 ** 2 * ((c - c ** 2 - s2) * n - c) / ((1 - c) ** 2 + s2) + + 2 + * l1 ** 2 + * ((2 * s2 + (c + s2) ** ((n + 1) / 2)) / ((1 - c) ** 2 + s2) ** 2) + * gamma + ) + return abs(esd) + else: + logger.info("This method is experimental and requires testing.") + # Eqn 2 + esd = n * l2 + 2 * l1 ** 2 * c / (1 - c) * (n - (1 - c ** n) / (1 - c)) + return esd + + +def traj_from_coords( + track: Union[np.ndarray, pd.DataFrame], + x_col=1, + y_col=2, + time_col: Optional[str] = None, + fps: Union[float, int] = 4, + spatial_units: str = "m", + time_units: str = "s", +) -> TrajaDataFrame: + """Create TrajaDataFrame from coordinates. + + Args: + track: N x 2 numpy array or pandas DataFrame with x and y columns + x_col: column index or x column name + y_col: column index or y column name + time_col: name of time column + fps: Frames per seconds + spatial_units: default m, optional + time_units: default s, optional + + Returns: + trj: TrajaDataFrame + + .. doctest:: + + >> xy = np.random.random((1000, 2)) + >> trj = traja.traj_from_coord(xy) + >> assert trj.shape == (1000,4) # columns x, y, time, dt + + """ + if not isinstance(track, traja.TrajaDataFrame): + if isinstance(track, np.ndarray) and track.shape[1] == 2: + trj = traja.from_xy(track) + elif isinstance(track, pd.DataFrame): + trj = traja.TrajaDataFrame(track) + else: + trj = track + trj.traja.spatial_units = spatial_units + trj.traja.time_units = time_units + + def rename(col, name, trj): + if isinstance(col, int): + trj.rename(columns={col: name}) + else: + if col not in trj: + raise Exception(f"Missing column {col}") + trj.rename(columns={col: name}) + return trj + + # Ensure column names are as expected + trj = rename(x_col, "x", trj) + trj = rename(y_col, "y", trj) + if time_col is not None: + trj = rename(time_col, "time", trj) + + # Allocate times if they aren't already known + if "time" not in trj: + if fps is None: + raise Exception( + ( + "Cannot create a trajectory without times: either fps or a time column must be specified" + ) + ) + # Assign times to each frame, starting at 0 + trj["time"] = pd.Series(np.arange(0, len(trj)) / fps) + + # Get displacement time for each coordinate, with the first point at time 0 + trj["dt"] = trj.time - trj.time.iloc[0] + + return trj + + +def distance_between(A: traja.TrajaDataFrame, B: traja.TrajaDataFrame, method="dtw"): + """Returns distance between two trajectories. + + Args: + A (:class:`~traja.frame.TrajaDataFrame`) : Trajectory 1 + B (:class:`~traja.frame.TrajaDataFrame`) : Trajectory 2 + method (str): ``dtw`` for dynamic time warping, ``hausdorff`` for Hausdorff + + Returns: + distance (float): Distance + + """ + if method == "hausdorff": + dist0 = directed_hausdorff(A, B)[0] + dist1 = directed_hausdorff(B, A)[0] + symmetric_dist = max(dist0, dist1) + return symmetric_dist + elif method == "dtw": + try: + from fastdtw import fastdtw + except ImportError: + raise ImportError( + """ + Missing optional dependency 'fastdtw'. Install fastdtw for dynamic time warping distance with pip install + fastdtw. + """ + ) + distance, path = fastdtw(A, B, dist=euclidean) + return distance + + +def to_shapely(trj): + """Returns shapely object for area, bounds, etc. functions. + + Args: + trj (:class:`~traja.frame.TrajaDataFrame`): Trajectory + + Returns: + shapely.geometry.linestring.LineString -- Shapely shape. + + .. doctest:: + + >>> df = traja.TrajaDataFrame({'x':[0,1,2],'y':[1,2,3]}) + >>> shape = traja.to_shapely(df) + >>> shape.is_closed + False + + """ + from shapely.geometry import shape + + coords = trj[["x", "y"]].values + tracks_obj = {"type": "LineString", "coordinates": coords} + tracks_shape = shape(tracks_obj) + return tracks_shape + + +def transition_matrix(grid_indices1D: np.ndarray): + """Returns ``np.ndarray`` of Markov transition probability matrix for grid cell transitions. + + Args: + grid_indices1D (:class:`np.ndarray`) + + Returns: + M (:class:`numpy.ndarray`) + + """ + if not isinstance(grid_indices1D, np.ndarray): + raise TypeError(f"Expected np.ndarray, got {type(grid_indices1D)}") + + n = 1 + max(grid_indices1D.flatten()) # number of states + + M = [[0] * n for _ in range(n)] + + for (i, j) in zip(grid_indices1D, grid_indices1D[1:]): + M[i][j] += 1 + + # Convert to probabilities + for row in M: + s = sum(row) + if s > 0: + row[:] = [f / s for f in row] + return np.array(M) + + +def _bins_to_tuple(trj, bins: Union[int, Tuple[int, int]] = 10): + """Returns tuple of x, y bins + + Args: + trj: Trajectory + bins: The bin specification: + If int, the number of bins for the smallest of the two dimensions such that (min(nx,ny)=bins). + If [int, int], the number of bins in each dimension (nx, ny = bins). + + Returns: + bins (Sequence[int,int]): Bins (nx, ny) + + """ + if bins is None: + bins = 10 + if isinstance(bins, int): + # make aspect equal + xlim, ylim = _get_xylim(trj) + aspect = (ylim[1] - ylim[0]) / (xlim[1] - xlim[0]) + if aspect >= 1: + bins = (bins, int(bins * aspect)) + else: + bins = (int(bins / aspect), bins) + + assert len(bins) == 2, f"bins should be length 2 but is {len(bins)}" + return bins + + +def calc_laterality( + trj: TrajaDataFrame, + dist_thresh: float, + angle_thresh: float = 30, +): + """Calculate laterality of a trajectory. + + Laterality is the preference for left or right turning. It is calculated + with the number of left and right turns. + + Args: + trj: Trajectory + dist_thresh: distance for a step to count as a turn + angle_thresh: angle threshold (from angle to 90 degrees) + + Returns: + right_turns (int) + left_turns (int) + + """ + # get turn angle with regard to x axis + if "turn_angle" not in trj.columns: + turn_angle = calc_turn_angle(trj) + else: + turn_angle = trj.turn_agle + + distance = step_lengths(trj) + distance_mask = distance > dist_thresh + angle_mask = ((turn_angle > angle_thresh) & (turn_angle < 90)) | ( + (turn_angle < -angle_thresh) & (turn_angle > -90) + ) + + turns = turn_angle[distance_mask & angle_mask].dropna() + left_turns = turns[turn_angle > 0].shape[0] + right_turns = turns[turn_angle < 0].shape[0] + + return right_turns, left_turns + + +def calc_flow_angles(grid_indices: np.ndarray): + """Calculate average flow between grid indices.""" + + bins = (grid_indices[:, 0].max(), grid_indices[:, 1].max()) + + M = np.empty((bins[1], bins[0]), dtype=np.ndarray) + + for (i, j) in zip(grid_indices, grid_indices[1:]): + # Account for fact that grid indices uses 1-base indexing + ix = i[0] - 1 + iy = i[1] - 1 + jx = j[0] - 1 + jy = j[1] - 1 + + if np.array_equal(i, j): + angle = None + elif ix == jx and iy > jy: # move towards y origin (down by default) + angle = 3 * np.pi / 2 + elif ix == jx and iy < jy: # move towards y origin (up by default) + angle = np.pi / 2 + elif ix < jx and iy == jy: # move right + angle = 0 + elif ix > jx and iy == jy: # move left + angle = np.pi + elif ix > jx and iy > jy: # move towards y origin (top left) + angle = 3 * np.pi / 4 + elif ix > jx and iy < jy: # move away from y origin (bottom left) + angle = 5 * np.pi / 4 + elif ix < jx and iy < jy: # move away from y origin (bottom right) + angle = 7 * np.pi / 4 + elif ix < jx and iy > jy: # move towards y origin (top right) + angle = np.pi / 4 + if angle is not None: + M[iy, ix] = np.append(M[iy, ix], angle) + + U = np.ones_like(M) # x component of arrow + V = np.empty_like(M) # y component of arrow + for i, row in enumerate(M): + for j, angles in enumerate(row): + x = y = 0 + # average_angle = None + if angles is not None and len(angles) > 1: + for angle in angles: + if angle is None: + continue + x += np.cos(angle) + y += np.sin(angle) + # average_angle = np.arctan2(y, x) + U[i, j] = x + V[i, j] = y + else: + U[i, j] = 0 + V[i, j] = 0 + + return U.astype(float), V.astype(float) + + +def _grid_coords1D(grid_indices: np.ndarray): + """Convert 2D grid indices to 1D indices.""" + if isinstance(grid_indices, pd.DataFrame): + grid_indices = grid_indices.values + grid_indices1D = [] + nr_cols = int(grid_indices[:, 0].max()) + 1 + for coord in grid_indices: + grid_indices1D.append( + coord[1] * nr_cols + coord[0] + ) # nr_rows * col_length + nr_cols + + return np.array(grid_indices1D, dtype=int) + + +def transitions(trj: TrajaDataFrame, **kwargs): + """Get first-order Markov model for transitions between grid cells. + + Args: + trj (trajectory) + kwargs: kwargs to :func:`traja.grid_coordinates` + + """ + if "xbin" not in trj.columns or "ybin" not in trj.columns: + grid_indices = grid_coordinates(trj, **kwargs) + else: + grid_indices = trj[["xbin", "ybin"]] + + # Drop nan for converting to int + grid_indices.dropna(subset=["xbin", "ybin"], inplace=True) + grid_indices1D = _grid_coords1D(grid_indices) + transitions_matrix = transition_matrix(grid_indices1D) + return transitions_matrix + + +def grid_coordinates( + trj: TrajaDataFrame, + bins: Union[int, tuple] = None, + xlim: tuple = None, + ylim: tuple = None, + assign: bool = False, +): + """Returns ``DataFrame`` of trajectory discretized into 2D lattice grid coordinates. + Args: + trj (~`traja.frame.TrajaDataFrame`): Trajectory + bins (tuple or int) + xlim (tuple) + ylim (tuple) + assign (bool): Return updated original dataframe + + Returns: + trj (~`traja.frame.TrajaDataFrame`): Trajectory is assign=True otherwise pd.DataFrame + + """ + # Drop nan for converting to int + trj.dropna(subset=["x", "y"], inplace=True) + + xmin = trj.x.min() if xlim is None else xlim[0] + xmax = trj.x.max() if xlim is None else xlim[1] + ymin = trj.y.min() if ylim is None else ylim[0] + ymax = trj.y.max() if ylim is None else ylim[1] + + bins = _bins_to_tuple(trj, bins) + + if not xlim: + xbin = pd.cut(trj.x, bins[0], labels=False) + else: + xmin, xmax = xlim + xbinarray = np.linspace(xmin, xmax, bins[0]) + xbin = np.digitize(trj.x, xbinarray) + if not ylim: + ybin = pd.cut(trj.y, bins[1], labels=False) + else: + ymin, ymax = ylim + ybinarray = np.linspace(ymin, ymax, bins[1]) + ybin = np.digitize(trj.y, ybinarray) + + if assign: + trj["xbin"] = xbin + trj["ybin"] = ybin + return trj + return pd.DataFrame({"xbin": xbin, "ybin": ybin}) + + +def generate( + n: int = 1000, + random: bool = True, + step_length: int = 2, + angular_error_sd: float = 0.5, + angular_error_dist: Callable = None, + linear_error_sd: float = 0.2, + linear_error_dist: Callable = None, + fps: float = 50, + spatial_units: str = "m", + seed: int = None, + convex_hull: bool = False, + **kwargs, +): + """Generates a trajectory. + + If ``random`` is ``True``, the trajectory will + be a correlated random walk/idiothetic directed walk (Kareiva & Shigesada, + 1983), corresponding to an animal navigating without a compass (Cheung, + Zhang, Stricker, & Srinivasan, 2008). If ``random`` is ``False``, it + will be(np.ndarray) a directed walk/allothetic directed walk/oriented path, corresponding + to an animal navigating with a compass (Cheung, Zhang, Stricker, & + Srinivasan, 2007, 2008). + + By default, for both random and directed walks, errors are normally + distributed, unbiased, and independent of each other, so are **simple + directed walks** in the terminology of Cheung, Zhang, Stricker, & Srinivasan, + (2008). This behaviour may be modified by specifying alternative values for + the ``angular_error_dist`` and/or ``linear_error_dist`` parameters. + + The initial angle (for a random walk) or the intended direction (for a + directed walk) is ``0`` radians. The starting position is ``(0, 0)``. + + Args: + n (int): (Default value = 1000) + random (bool): (Default value = True) + step_length: (Default value = 2) + angular_error_sd (float): (Default value = 0.5) + angular_error_dist (Callable): (Default value = None) + linear_error_sd (float): (Default value = 0.2) + linear_error_dist (Callable): (Default value = None) + fps (float): (Default value = 50) + convex_hull (bool): (Default value = False) + spatial_units: (Default value = 'm') + **kwargs: Additional arguments + + Returns: + trj (:class:`traja.frame.TrajaDataFrame`): Trajectory + + .. note:: + + Based on Jim McLean's `trajr `_, ported to Python. + + **Reference**: McLean, D. J., & Skowron Volponi, M. A. (2018). trajr: An R package for characterisation of animal + trajectories. Ethology, 124(6), 440-448. https://doi.org/10.1111/eth.12739. + + """ + if seed is None: + np.random.seed(0) + else: + np.random.seed(seed) + if angular_error_dist is None: + angular_error_dist = np.random.normal( + loc=0.0, scale=angular_error_sd, size=n - 1 + ) + if linear_error_dist is None: + linear_error_dist = np.random.normal(loc=0.0, scale=linear_error_sd, size=n - 1) + angular_errors = angular_error_dist + linear_errors = linear_error_dist + step_lengths = step_length + linear_errors + + # Don't allow negative lengths + step_lengths[step_lengths < 0] = 0 + steps = polar_to_z(step_lengths, angular_errors) + + if random: + # Accumulate angular errors + coords = np.zeros(n, dtype=np.complex) + angle = 0 + for i in range(n - 1): + angle += angular_errors[i] + length = step_length + linear_errors[i] + coords[i + 1] = coords[i] + polar_to_z(r=length, theta=angle) + else: + coords = np.append(complex(0), np.cumsum(steps)) + + x = coords.real + y = coords.imag + + df = traja.TrajaDataFrame(data={"x": x, "y": y}) + + if fps in (0, None): + raise Exception("fps must be greater than 0") + + df.fps = fps + time = df.index / fps + df["time"] = time + df.spatial_units = spatial_units + + for key, value in kwargs.items(): + df.__dict__[key] = value + + # Update metavars + metavars = dict(angular_error_sd=angular_error_sd, linear_error_sd=linear_error_sd) + df.__dict__.update(metavars) + # Attribute convex hull to dataframe + if convex_hull: + df.convex_hull = df[["x", "y"]].values + else: + del df.convex_hull + return df + + +def _resample_time( + trj: TrajaDataFrame, step_time: Union[float, int, str], errors="coerce" +): + if not is_datetime_or_timedelta_dtype(trj.index): + raise Exception(f"{trj.index.dtype} is not datetime or timedelta.") + try: + df = trj.resample(step_time).interpolate(method="spline", order=2) + except ValueError as e: + if len(e.args) > 0 and "cannot reindex from a duplicate axis" in e.args[0]: + if errors == "coerce": + logger.warning("Duplicate time indices, keeping first") + trj = trj.loc[~trj.index.duplicated(keep="first")] + df = ( + trj.resample(step_time) + .bfill(limit=1) + .interpolate(method="spline", order=2) + ) + else: + logger.error("Error: duplicate time indices") + raise ValueError("Duplicate values in indices") + return df + + +def resample_time(trj: TrajaDataFrame, step_time: str, new_fps: Optional[bool] = None): + """Returns a ``TrajaDataFrame`` resampled to consistent `step_time` intervals. + + ``step_time`` should be expressed as a number-time unit combination, eg "2S" for 2 seconds and ā€œ2100Lā€ for 2100 milliseconds. + + Args: + trj (:class:`~traja.frame.TrajaDataFrame`): Trajectory + step_time (str): step time interval / offset string (eg, '2S' (seconds), '50L' (milliseconds), '50N' (nanoseconds)) + new_fps (bool, optional): new fps + + Results: + trj (:class:`~traja.frame.TrajaDataFrame`): Trajectory + + + .. doctest:: + + >>> from traja import generate, resample_time + >>> df = generate() + >>> resampled = resample_time(df, '50L') # 50 milliseconds + >>> resampled.head() # doctest: +NORMALIZE_WHITESPACE + x y + time + 1970-01-01 00:00:00.000 0.000000 0.000000 + 1970-01-01 00:00:00.050 0.919113 4.022971 + 1970-01-01 00:00:00.100 -1.298510 5.423373 + 1970-01-01 00:00:00.150 -6.057524 4.708803 + 1970-01-01 00:00:00.200 -10.347759 2.108385 + + """ + time_col = _get_time_col(trj) + if time_col == "index" and is_datetime64_any_dtype(trj.index): + _trj = _resample_time(trj, step_time) + elif time_col == "index" and is_timedelta64_dtype(trj.index): + trj.index = pd.to_datetime(trj.index) + _trj = _resample_time(trj, step_time) + _trj.index = pd.to_timedelta(_trj.index) + elif time_col: + if isinstance(step_time, str): + try: + if "." in step_time: + raise NotImplementedError( + """Fractional step time not implemented. + For milliseconds/microseconds/nanoseconds use: + L milliseonds + U microseconds + N nanoseconds + eg, step_time='2100L'""" + ) + except Exception: + raise NotImplementedError( + f"Inferring from time format {step_time} not yet implemented." + ) + _trj = trj.set_index(time_col) + time_units = _trj.__dict__.get("time_units", "s") + _trj.index = pd.to_datetime(_trj.index, unit=time_units) + _trj = _resample_time(_trj, step_time) + else: + raise NotImplementedError( + f"Time column ({time_col}) not of expected dataset type." + ) + return _trj + + +def rotate(df, angle: Union[float, int] = 0, origin: tuple = None): + """Returns a ``TrajaDataFrame`` Rotate a trajectory `angle` in radians. + + Args: + trj (:class:`traja.frame.TrajaDataFrame`): Trajectory + angle (float): angle in radians + origin (tuple. optional): rotate around point (x,y) + + Returns: + trj (:class:`traja.frame.TrajaDataFrame`): Trajectory + + .. note:: + + Based on Lyle Scott's `implementation `_. + + """ + trj = df.copy() + # Calculate current orientation + if isinstance(trj, traja.TrajaDataFrame): + xy = df.traja.xy + elif isinstance(trj, pd.DataFrame): + trj = df[["x", "y"]] + + x, y = np.split(xy, [-1], axis=1) + if origin is None: + # Assume middle of x and y is origin + origin = ((x.max() - x.min()) / 2, (y.max() - y.min()) / 2) + + offset_x, offset_y = origin + new_coords = [] + + for x, y in xy: + adjusted_x = x - offset_x + adjusted_y = y - offset_y + cos_rad = math.cos(angle) + sin_rad = math.sin(angle) + qx = offset_x + cos_rad * adjusted_x + sin_rad * adjusted_y + qy = offset_y + -sin_rad * adjusted_x + cos_rad * adjusted_y + new_coords.append((qx, qy)) + + new_xy = np.array(new_coords) + x, y = np.split(new_xy, [-1], axis=1) + trj["x"] = x + trj["y"] = y + return trj + + +def rediscretize_points(trj: TrajaDataFrame, R: Union[float, int], time_out=False): + """Returns a ``TrajaDataFrame`` rediscretized to a constant step length `R`. + + Args: + trj (:class:`traja.frame.TrajaDataFrame`): Trajectory + R (float): Rediscretized step length (eg, 0.02) + time_out (bool): Include time corresponding to time intervals in output + + Returns: + rt (:class:`numpy.ndarray`): rediscretized trajectory + + """ + if not isinstance(R, (float, int)): + raise TypeError(f"R should be float or int, but is {type(R)}") + + results = _rediscretize_points(trj, R, time_out) + rt = results["rt"] + if len(rt) < 2: + raise RuntimeError( + f"Step length {R} is too large for path (path length {len(trj)})" + ) + rt = traja.from_xy(rt) + if time_out: + rt["time"] = results["time"] + return rt + + +def _rediscretize_points( + trj: TrajaDataFrame, R: Union[float, int], time_out=False +) -> dict: + """Helper function for :func:`traja.trajectory.rediscretize`. + + Args: + trj (:class:`traja.frame.TrajaDataFrame`): Trajectory + R (float): Rediscretized step length (eg, 0.02) + + Returns: + output (dict): Containing: + result (:class:`numpy.ndarray`): Rediscretized coordinates + time_vals (optional, list of floats or datetimes): Time points corresponding to result + + """ + # TODO: Implement with complex numbers + points = trj[["x", "y"]].dropna().values.astype("float64") + n_points = len(points) + result = np.empty((128, 2)) + p0 = points[0] + result[0] = p0 + step_nr = 0 + candidate_start = 1 # running index of candidate + + time_vals = [] + if time_out: + time_col = _get_time_col(trj) + time = trj[time_col][0] + time_vals.append(time) + + while candidate_start <= n_points: + # Find the first point `curr_ind` for which |points[curr_ind] - p_0| >= R + curr_ind = np.NaN + for i in range( + candidate_start, n_points + ): # range of search space for next point + d = np.linalg.norm(points[i] - result[step_nr]) + if d >= R: + curr_ind = i # curr_ind is in [candidate, n_points) + if time_out: + time = trj[time_col][i] + time_vals.append(time) + break + if np.isnan(curr_ind): + # End of path + break + + # The next point may lie on the same segment + candidate_start = curr_ind + + # The next point lies on the segment p[k-1], p[k] + curr_result_x = result[step_nr][0] + prev_x = points[curr_ind - 1, 0] + curr_result_y = result[step_nr][1] + prev_y = points[curr_ind - 1, 1] + + # a = 1 if points[k, 0] <= xk_1 else 0 + lambda_ = np.arctan2( + points[curr_ind, 1] - prev_y, points[curr_ind, 0] - prev_x + ) # angle + cos_l = np.cos(lambda_) + sin_l = np.sin(lambda_) + U = (curr_result_x - prev_x) * cos_l + (curr_result_y - prev_y) * sin_l + V = (curr_result_y - prev_y) * cos_l - (curr_result_x - prev_x) * sin_l + + # Compute distance H between (X_{i+1}, Y_{i+1}) and (x_{k-1}, y_{k-1}) + H = U + np.sqrt(abs(R ** 2 - V ** 2)) + XIp1 = H * cos_l + prev_x + YIp1 = H * sin_l + prev_y + + # Increase array size progressively to make the code run (significantly) faster + if len(result) <= step_nr + 1: + result = np.concatenate((result, np.empty_like(result))) + + # Save the point + result[step_nr + 1] = np.array([XIp1, YIp1]) + step_nr += 1 + + # Truncate result + result = result[: step_nr + 1] + output = {"rt": result} + if time_out: + output["time"] = time_vals + return output + + +def _has_cols(trj: TrajaDataFrame, cols: list): + """Check if `trj` has `cols`.""" + return set(cols).issubset(trj.columns) + + +def calc_turn_angle(trj: TrajaDataFrame): + """Return a ``Series`` of floats with turn angles. + + Args: + trj (:class:`traja.frame.TrajaDataFrame`): Trajectory + + Returns: + turn_angle (:class:`~pandas.Series`): Turn angle + + .. doctest:: + + >>> df = traja.TrajaDataFrame({'x':[0,1,2],'y':[1,2,3]}) + >>> traja.calc_turn_angle(df) + 0 NaN + 1 NaN + 2 0.0 + Name: turn_angle, dtype: float64 + + """ + if "heading" not in trj: + heading = calc_heading(trj) + else: + heading = trj.heading + turn_angle = heading.diff().rename("turn_angle") + # Correction for 360-degree angle range + turn_angle.loc[turn_angle >= 180] -= 360 + turn_angle.loc[turn_angle < -180] += 360 + return turn_angle + + +def calc_angle(trj: TrajaDataFrame, unit: str = "degrees", lag: int = 1): + """Returns a ``Series`` with angle between steps as a function of displacement with regard to x axis. + + Args: + trj (:class:`~traja.frame.TrajaDataFrame`): Trajectory + unit (str): return angle in radians or degrees (Default value: 'degrees') + lag (int) : time steps between angle calculation (Default value: 1) + + Returns: + angle (:class:`pandas.Series`): Angle series. + + """ + if not _has_cols(trj, ["displacement"]) or (lag != 1): + displacement = calc_displacement(trj, lag) + else: + displacement = trj.displacement + + if unit == "degrees": + angle = np.rad2deg(np.arccos(np.abs(trj.x.diff(lag)) / displacement)) + elif unit == "radians": + angle = np.arccos(np.abs(trj.x.diff()) / displacement) + else: + raise ValueError(f"The unit {unit} is not valid.") + + angle.unit = unit + angle.name = "angle" + return angle + + +def calc_displacement(trj: TrajaDataFrame, lag=1): + """Returns a ``Series`` of ``float`` displacement between consecutive indices. + + Args: + trj (:class:`~traja.frame.TrajaDataFrame`): Trajectory + lag (int) : time steps between displacement calculation + + Returns: + displacement (:class:`pandas.Series`): Displacement series. + + .. doctest:: + + >>> df = traja.TrajaDataFrame({'x':[0,1,2],'y':[1,2,3]}) + >>> traja.calc_displacement(df) + 0 NaN + 1 1.414214 + 2 1.414214 + Name: displacement, dtype: float64 + + """ + displacement = np.sqrt( + np.power(trj.x.shift(lag) - trj.x, 2) + np.power(trj.y.shift(lag) - trj.y, 2) + ) + displacement.name = "displacement" + return displacement + + +def calc_derivatives(trj: TrajaDataFrame): + """Returns derivatives ``displacement`` and ``displacement_time`` as DataFrame. + + Args: + trj (:class:`~traja.frame.TrajaDataFrame`): Trajectory + + Returns: + derivs (:class:`~pandas.DataFrame`): Derivatives. + + .. doctest:: + + >>> df = traja.TrajaDataFrame({'x':[0,1,2],'y':[1,2,3],'time':[0., 0.2, 0.4]}) + >>> traja.calc_derivatives(df) + displacement displacement_time + 0 NaN 0.0 + 1 1.414214 0.2 + 2 1.414214 0.4 + + """ + + time_col = _get_time_col(trj) + if time_col is None: + raise Exception("Missing time information in trajectory.") + + if "displacement" not in trj: + displacement = calc_displacement(trj) + else: + displacement = trj.displacement + + # get cumulative seconds + if is_datetime64_any_dtype(trj[time_col]): + displacement_time = ( + trj[time_col].astype(int).div(10 ** 9).diff().fillna(0).cumsum() + ) + else: + try: + displacement_time = trj[time_col].diff().fillna(0).cumsum() + except TypeError: + raise Exception( + f"Format (example {trj[time_col][0]}) not recognized as datetime" + ) + + # TODO: Create DataFrame directly + derivs = pd.DataFrame( + OrderedDict(displacement=displacement, displacement_time=displacement_time) + ) + + return derivs + + +def calc_heading(trj: TrajaDataFrame): + """Calculate trajectory heading. + + Args: + trj (:class:`~traja.frame.TrajaDataFrame`): Trajectory + + Returns: + heading (:class:`pandas.Series`): heading as a ``Series`` + + ..doctest:: + + >>> df = traja.TrajaDataFrame({'x':[0,1,2],'y':[1,2,3]}) + >>> traja.calc_heading(df) + 0 NaN + 1 45.0 + 2 45.0 + Name: heading, dtype: float64 + + """ + if not _has_cols(trj, ["angle"]): + angle = calc_angle(trj) + else: + angle = trj.angle + if hasattr(angle, "unit"): + if angle.unit == "radians": + angle = np.rad2deg(angle) + + dx = trj.x.diff() + dy = trj.y.diff() + # Get heading from angle + mask = (dx > 0) & (dy >= 0) + trj.loc[mask, "heading"] = angle[mask] + mask = (dx >= 0) & (dy < 0) + trj.loc[mask, "heading"] = -angle[mask] + mask = (dx < 0) & (dy <= 0) + trj.loc[mask, "heading"] = -(180 - angle[mask]) + mask = (dx <= 0) & (dy > 0) + trj.loc[mask, "heading"] = 180 - angle[mask] + return trj.heading + + +def speed_intervals( + trj: TrajaDataFrame, faster_than: float = None, slower_than: float = None +) -> pd.DataFrame: + """Calculate speed time intervals. + + Returns a dictionary of time intervals where speed is slower and/or faster than specified values. + + Args: + faster_than (float, optional): Minimum speed threshold. (Default value = None) + slower_than (float or int, optional): Maximum speed threshold. (Default value = None) + + Returns: + result (:class:`~pd.DataFrame`) -- time intervals as dataframe + + .. note:: + + Implementation ported to Python, heavily inspired by Jim McLean's trajr package. + + .. doctest:: + + >> df = traja.generate() + >> intervals = traja.speed_intervals(df, faster_than=100) + >> intervals.head() + start_frame start_time stop_frame stop_time duration + 0 1 0.02 3 0.06 0.04 + 1 4 0.08 8 0.16 0.08 + 2 10 0.20 11 0.22 0.02 + 3 12 0.24 15 0.30 0.06 + 4 17 0.34 18 0.36 0.02 + + """ + derivs = get_derivatives(trj) + + if faster_than is None and slower_than is None: + raise Exception( + "Parameters faster_than and slower_than are both None, at least one must be provided." + ) + + # Calculate trajectory speeds + speed = derivs["speed"].values + times = derivs["speed_times"].values + times[0] = 0.0 + flags = np.full(len(speed), 1) + + if faster_than is not None: + flags = flags & (speed > faster_than) + if slower_than is not None: + flags = flags & (speed < slower_than) + + changes = np.diff(flags) + stop_frames = np.where(changes == -1)[0] + start_frames = np.where(changes == 1)[0] + + # Handle situation where interval begins or ends outside of trajectory + if len(start_frames) > 0 or len(stop_frames) > 0: + # Assume interval started at beginning of trajectory, since we don't know what happened before that + if len(stop_frames) > 0 and ( + len(start_frames) == 0 or stop_frames[0] < start_frames[0] + ): + start_frames = np.append(1, start_frames) + # Similarly, assume that interval can't extend past end of trajectory + if ( + len(stop_frames) == 0 + or start_frames[len(start_frames) - 1] > stop_frames[len(stop_frames) - 1] + ): + stop_frames = np.append(stop_frames, len(speed) - 1) + + stop_times = times[stop_frames] + start_times = times[start_frames] + + durations = stop_times - start_times + result = traja.TrajaDataFrame( + OrderedDict( + start_frame=start_frames, + start_time=start_times, + stop_frame=stop_frames, + stop_time=stop_times, + duration=durations, + ) + ) + return result + + +def get_derivatives(trj: TrajaDataFrame): + """Returns derivatives ``displacement``, ``displacement_time``, ``speed``, ``speed_times``, ``acceleration``, + ``acceleration_times`` as dictionary. + + Args: + trj (:class:`~traja.frame.TrajaDataFrame`): Trajectory + + Returns: + derivs (:class:`~pd.DataFrame`) : Derivatives + + .. doctest:: + + >> df = traja.TrajaDataFrame({'x':[0,1,2],'y':[1,2,3],'time':[0.,0.2,0.4]}) + >> df.traja.get_derivatives() #doctest: +SKIP + displacement displacement_time speed speed_times acceleration acceleration_times + 0 NaN 0.0 NaN NaN NaN NaN + 1 1.414214 0.2 7.071068 0.2 NaN NaN + 2 1.414214 0.4 7.071068 0.4 0.0 0.4 + + """ + if not _has_cols(trj, ["displacement", "displacement_time"]): + derivs = calc_derivatives(trj) + d = derivs["displacement"] + t = derivs["displacement_time"] + else: + d = trj.displacement + t = trj.displacement_time + derivs = OrderedDict(displacement=d, displacement_time=t) + if is_datetime_or_timedelta_dtype(t): + # Convert to float divisible series + # TODO: Add support for other time units + t = t.dt.total_seconds() + v = d[1 : len(d)] / t.diff() + v.rename("speed") + vt = t[1 : len(t)].rename("speed_times") + # Calculate linear acceleration + a = v.diff() / vt.diff().rename("acceleration") + at = vt[1 : len(vt)].rename("accleration_times") + + data = dict(speed=v, speed_times=vt, acceleration=a, acceleration_times=at) + derivs = derivs.merge(pd.DataFrame(data), left_index=True, right_index=True) + + # Replace infinite values + derivs.replace([np.inf, -np.inf], np.nan) + return derivs + + +def _get_xylim(trj: TrajaDataFrame) -> Tuple[Tuple, Tuple]: + if ( + "xlim" in trj.__dict__ + and "ylim" in trj.__dict__ + and isinstance(trj.xlim, (list, tuple)) + ): + return trj.xlim, trj.ylim + else: + xlim = trj.x.min(), trj.x.max() + ylim = trj.y.min(), trj.y.max() + return xlim, ylim + + +def coords_to_flow(trj: TrajaDataFrame, bins: Union[int, tuple] = None): + """Calculate grid cell flow from trajectory. + + Args: + trj (trajectory) + bins (int or tuple) + + Returns: + X (:class:`~numpy.ndarray`): X coordinates of arrow locations + Y (:class:`~numpy.ndarray`): Y coordinates of arrow locations + U (:class:`~numpy.ndarray`): X component of vector dataset + V (:class:`~numpy.ndarray`): Y component of vector dataset + + """ + xlim, ylim = _get_xylim(trj) + bins = _bins_to_tuple(trj, bins) + + X, Y = np.meshgrid( + np.linspace(trj.x.min(), trj.x.max(), bins[0]), + np.linspace(trj.y.min(), trj.y.max(), bins[1]), + ) + + if "xbin" not in trj.columns or "ybin" not in trj.columns: + grid_indices = traja.grid_coordinates(trj, bins=bins, xlim=xlim, ylim=ylim) + else: + grid_indices = trj[["xbin", "ybin"]] + + U, V = traja.calc_flow_angles(grid_indices.values) + + return X, Y, U, V + + +def return_angle_to_point(p1: np.ndarray, p0: np.ndarray): + """Calculate angle of points as coordinates in relation to each other. + Designed to be broadcast across all trajectory points for a single + origin point p0. + + Args: + p1 (np.ndarray): Test point [x,y] + p0 (np.ndarray): Origin/source point [x,y] + + Returns: + r (float) + + """ + + r = math.degrees(math.atan2((p0[1] - p1[1]), (p0[0] - p1[0]))) + return r + + +def determine_colinearity(p0: np.ndarray, p1: np.ndarray, p2: np.ndarray): + """Determine whether trio of points constitute a right turn, or + whether they are left turns (or colinear/straight line). + + Args: + p0 (:class:`~numpy.ndarray`): First point [x,y] in line + p1 (:class:`~numpy.ndarray`): Second point [x,y] in line + p2 (:class:`~numpy.ndarray`): Third point [x,y] in line + + Returns: + (bool) + + """ + + cross_product = (p1[0] - p0[0]) * (p2[1] - p0[1]) - (p1[1] - p0[1]) * ( + p2[0] - p0[0] + ) + + if cross_product < 0: # Right turn + return False + else: # Points are colinear (if == 0) or left turn (if < 0) + return True + + +def inside( + pt: np.ndarray, + bounds_xs: list, + bounds_ys: list, + minx: float, + maxx: float, + miny: float, + maxy: float, +): + """Determine whether point lies inside or outside of polygon formed + by "extrema" points - minx, maxx, miny, maxy. Optimized to be run + as broadcast function in numpy along axis. + + Args: + pt (:class:`~numpy.ndarray`): Point to test whether inside or outside polygon + bounds_xs (list or tuple): x-coordinates of polygon vertices, in sequence + bounds_ys (list or tuple): y-coordinates of polygon vertices, same sequence + minx (float): minimum x coordinate value + maxx (float): maximum x coordinate value + miny (float): minimum y coordinate value + maxy (float): maximum y coordinate value + + Returns: + (bool) + + .. note:: + Ported to Python from C implementation by W. Randolph Franklin (WRF): + + + + Boolean return "True" for OUTSIDE polygon, meaning it is within + subset of possible convex hull coordinates. + """ + # Only theoretically possible, extrema polygon is actually a straight line + if maxx == maxy and minx == miny: + return True # No polygon to be within (considered outside) + if pt[0] in [minx, maxx] or pt[1] in [miny, maxy]: + return True # Extrema points are by definition part of convex hull + poly_pts = len(bounds_xs) + ct = 0 + for i in range(poly_pts): + if i == 0: + j = poly_pts - 1 + else: + j = i - 1 + # Test if horizontal trace from the point to infinity intersects the given polygon line segment + if ((bounds_ys[i] > pt[1]) != (bounds_ys[j] > pt[1])) & ( + pt[0] + < ( + (bounds_xs[j] - bounds_xs[i]) + * (pt[1] - bounds_ys[i]) + / (bounds_ys[j] - bounds_ys[i]) + + bounds_xs[i] + ) + ): + ct += 1 + if ( + ct % 2 == 0 + ): # Number of intersections between point, polygon edge(s) and infinity point are odd: + return True # Outside polygon + else: + return False # Inside polygon + + +def calc_convex_hull(point_arr: np.array) -> np.array: + """Identify containing polygonal convex hull for full Trajectory + Interior points filtered with :meth:`traja.trajectory.inside` method, takes quadrilateral using extrema points + `(minx, maxx, miny, maxy)` - convex hull points MUST all be outside such a polygon. + Returns an array with all points in the convex hull. + + Implementation of Graham Scan `technique _`. + + Returns: + point_arr (:class:`~numpy.ndarray`): n x 2 (x,y) array + + .. doctest:: + + >> #Quick visualizaation + >> import matplotlib.pyplot as plt + >> df = traja.generate(n=10000, convex_hull=True) + >> xs, ys = [*zip(*df.convex_hull)] + >> _ = plt.plot(df.x.values, df.y.values, 'o', 'blue') + >> _ = plt.plot(xs, ys, '-o', color='red') + >> _ = plt.show() + + + .. note:: + Incorporates Akl-Toussaint `method `_ for filtering interior points. + + .. note:: + Performative loss beyond ~100,000-200,000 points, algorithm has O(nlogn) complexity. + + """ + assert point_arr.shape[1] == 2, f"expected (n, 2) shape only, got {point_arr.shape}" + # Find "extrema" points to form polygon (convex hull must be outside this polygon) + minx = point_arr[:, 0].min() + maxx = point_arr[:, 0].max() + miny = point_arr[:, 1].min() + maxy = point_arr[:, 1].max() + min_x_pt = point_arr[np.where(point_arr[:, 0] == point_arr[:, 0].min())].tolist()[0] + min_y_pt = point_arr[np.where(point_arr[:, 1] == point_arr[:, 1].min())].tolist()[0] + max_x_pt = point_arr[np.where(point_arr[:, 0] == point_arr[:, 0].max())].tolist()[0] + max_y_pt = point_arr[np.where(point_arr[:, 1] == point_arr[:, 1].max())].tolist()[0] + extrema_pts = [min_x_pt, min_y_pt, max_x_pt, max_y_pt] + extrema_xys = [*zip(*extrema_pts)] + bounds_x, bounds_y = extrema_xys[0], extrema_xys[1] + + # Filter trajectory points to only include points "outside" of this extrema polygon + convex_mask = np.apply_along_axis( + inside, 1, point_arr, bounds_x, bounds_y, minx, maxx, miny, maxy + ) + point_arr = point_arr[convex_mask] + + # Find principal point (lowest y, lower x) from which to start + p0 = point_arr[point_arr[:, 1] == point_arr[:, 1].min()].min(axis=0) + point_arr = np.delete( + point_arr, np.where((point_arr[:, 0] == p0[0]) & (point_arr[:, 1] == p0[1])), 0 + ) + # Sort remaining points + point_arr = point_arr[np.lexsort((point_arr[:, 0], point_arr[:, 1]))] + # Populate array with direction of each point in the trajectory to the principal (lowest, then leftmost) point + point_arr_r_p0 = np.apply_along_axis(return_angle_to_point, 1, point_arr, p0) + # Sort point array by radius + sorted_ind = point_arr_r_p0.argsort() + point_arr_r_p0 = point_arr_r_p0[sorted_ind] + point_arr = point_arr[sorted_ind] + + # Check for points with duplicate angles from principal point, only keep furthest point + unique_r = np.unique(point_arr_r_p0, return_index=True)[1] + if ( + unique_r.shape == point_arr_r_p0.shape + ): # There are no two points at same angle from x axis + pass + else: + point_arr_d_p0 = np.apply_along_axis( + lambda x, p0=p0: np.linalg.norm(p0 - x), 1, point_arr + ) + # Identify duplicate angles + unique, counts = np.unique(point_arr_r_p0, axis=0, return_counts=True) + rep_angles = unique[counts > 1] + duplicates = point_arr_r_p0[np.where(np.in1d(point_arr_r_p0, rep_angles))] + duplicates = point_arr[np.where(np.in1d(point_arr_r_p0, rep_angles))] + # Get indices of only the furthest point from origin at each unique angle + dropped_pts = [] + for dup_pt in duplicates: + pt_idx = np.where( + (point_arr[:, 0] == dup_pt[0]) & (point_arr[:, 1] == dup_pt[1]) + )[0][0] + r_val = point_arr_r_p0[pt_idx] + ind_furthest = np.where( + point_arr_d_p0 + == point_arr_d_p0[np.where(point_arr_r_p0 == r_val)].max() + )[0][0] + if ( + not pt_idx == ind_furthest + ): # This is a "closer" point to origin, not in convex hull + dropped_pts.append(pt_idx) + point_arr = np.delete(point_arr, dropped_pts, axis=0) + + # Iterate through points. If a "right turn" is made, remove preceding point. + point_arr = np.insert(point_arr, 0, p0, axis=0) + for pt in point_arr: + idx = np.where((point_arr[:, 0] == pt[0]) & (point_arr[:, 1] == pt[1]))[0][0] + while True: + # Skip/stop at first two points (3 points form line), after working backwards + if idx <= 1: + break + # Continue working backwards until a left turn is made, or we reach the origin + elif determine_colinearity( + point_arr[idx - 2], point_arr[idx - 1], point_arr[idx] + ): + break + else: # This is a right turn + point_arr = np.delete(point_arr, idx - 1, 0) + idx -= 1 + point_arr = np.insert(point_arr, point_arr.shape[0], p0, axis=0) + return point_arr + + +def from_xy(xy: np.ndarray): + """Convenience function for initializing :class:`~traja.frame.TrajaDataFrame` with x,y coordinates. + + Args: + xy (:class:`numpy.ndarray`): x,y coordinates + + Returns: + traj_df (:class:`~traja.frame.TrajaDataFrame`): Trajectory as dataframe + + .. doctest:: + + >>> import numpy as np + >>> xy = np.array([[0,1],[1,2],[2,3]]) + >>> traja.from_xy(xy) + x y + 0 0 1 + 1 1 2 + 2 2 3 + + """ + df = traja.TrajaDataFrame.from_records(xy, columns=["x", "y"]) + return df + + +def fill_in_traj(trj: TrajaDataFrame): + # FIXME: Implement + return trj + + +def _get_time_col(trj: TrajaDataFrame): + # Check if saved in metadata + time_col = trj.__dict__.get("time_col", None) + if time_col: + return time_col + # Check if index is datetime + if is_datetime64_any_dtype(trj.index) or is_datetime_or_timedelta_dtype(trj.index): + return "index" + # Check if any column contains 'time' + time_cols = [col for col in trj if "time" in col.lower()] + if time_cols: + # Try first column + time_col = time_cols[0] + if is_datetime_or_timedelta_dtype(trj[time_col]): + return time_col + else: + # Time column is float, etc. but not datetime64. + # FIXME: Add conditional return, etc. + return time_col + else: + # No time column found + return None + + +if __name__ == "__main__": + import doctest + + doctest.testmod() diff --git a/utils.py b/utils.py deleted file mode 100644 index 29f4500c..00000000 --- a/utils.py +++ /dev/null @@ -1,17 +0,0 @@ -#! /usr/local/env python3 - -def stylize_axes(ax): - ax.spines['top'].set_visible(False) - ax.spines['right'].set_visible(False) - - ax.xaxis.set_tick_params(top='off', direction='out', width=1) - ax.yaxis.set_tick_params(right='off', direction='out', width=1) - - -def shift_xtick_labels(xtick_labels, first_index=None): - for idx, x in enumerate(xtick_labels): - label = x.get_text() - xtick_labels[idx].set_text(str(int(label) + 1)) - if first_index is not None: - xtick_labels[0] = first_index - return xtick_labels \ No newline at end of file