Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Restructure API Documentation #331

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -317,3 +317,4 @@ cython_debug/
docs/build
pedpy/_version.py
# End of https://www.toptal.com/developers/gitignore/api/python,visualstudiocode,pycharm,jupyternotebooks
.vscode
4 changes: 2 additions & 2 deletions .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ ignore-comments=yes
ignore-docstrings=yes

# Imports are removed from the similarity computation
ignore-imports=no
ignore-imports=yes

# Signatures are removed from the similarity computation
ignore-signatures=no
Expand Down Expand Up @@ -485,7 +485,7 @@ valid-metaclass-classmethod-first-arg=cls
ignored-parents=

# Maximum number of arguments for function / method.
max-args=5
max-args=10

# Maximum number of attributes for a class (see R0902).
max-attributes=7
Expand Down
37 changes: 28 additions & 9 deletions docs/source/api/methods.rst
Original file line number Diff line number Diff line change
@@ -1,41 +1,60 @@
****************
*****************
Analysis Methods
****************
*****************


Core measurements
-----------------

Density
*******
^^^^^^

.. autoapimodule:: density_calculator
:members:
:no-private-members:
:no-special-members:

Speed
*****
^^^^^^

.. autoapimodule:: speed_calculator
:members:
:no-private-members:
:no-special-members:

Flow
****
^^^^

.. autoapimodule:: flow_calculator
:members:
:no-private-members:
:no-special-members:

Profiles
********


Pedestrian Dynamics
------------------

Spatial Analysis
^^^^^^^^^^^^^^

.. autoapimodule:: spatial_analysis
:members:
:no-private-members:
:no-special-members:


Motion profiles
^^^^^^^^^^^^^

.. autoapimodule:: profile_calculator
:members:
:no-private-members:
:no-special-members:

Utils
*****

Utilities
------

.. autoapimodule:: method_utils
:members:
Expand Down
1,102 changes: 1,102 additions & 0 deletions notebooks/demo-data/single_file/n34_cam2.csv

Large diffs are not rendered by default.

2,392 changes: 2,392 additions & 0 deletions notebooks/demo-data/single_file/n56_cam1.csv

Large diffs are not rendered by default.

233 changes: 219 additions & 14 deletions notebooks/user_guide.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -2363,32 +2363,49 @@
"source": [
"#### Speed Profiles\n",
"\n",
"Currently, it is possible to compute either the Voronoi or arithmetic speed profiles.\n",
"This documentation describes the methods available for computing speed profiles within a specified area, focusing on pedestrian movements. Four distinct methods are detailed: Voronoi, Arithmetic, Mean, and Gauss speed profiles.\n",
"\n",
"**Voronoi speed profile**\n",
"\n",
"The Voronoi speed is computed as a weighted mean of the pedestrian's speed, whose Voronoi cell ($V_i$) intersects with the grid cell ($M$). The weighted is given by the proportion of the Voronoi, which lies inside the gird cell.\n",
"\n",
"The Voronoi speed profile $v_{\\text{voronoi}}$ is computed from a weighted mean of pedestrian speeds.\n",
" It utilizes the area overlap between a pedestrian's Voronoi cell ($V_i$) and the grid cell ($c$). The weight corresponds to the fraction of the Voronoi cell residing within the grid cell, thereby integrating speed across this intersection:\n",
" \n",
"$$\n",
" v_{voronoi}(t) = { \\int\\int v_{xy} dxdy \\over A(M)},\n",
" v_{\\text{voronoi}} = { \\int\\int v_{xy} dxdy \\over A(c)},\n",
"$$\n",
"\n",
"where $A(c)$ represents the area of the grid cell $c$.\n",
"\n",
"**Arithmetic Voronoi speed profile**\n",
"\n",
"The arithmetic Voronoi speed $v_{arithmetic}$ is computed as the mean of each pedestrian's speed ($v_i$), whose Voronoi cell $V_i$ intersects with grid cell $M$:\n",
"The arithmetic Voronoi speed $v_{\\text{arithmetic}}$ is computed as the mean of each pedestrian's speed ($v_i$), whose Voronoi cell $V_i$ intersects with grid cell $c$:\n",
"\n",
"$$\n",
" v_{arithmetic} = \\frac{1}{N} \\sum_{i \\in V_i \\cap P_M} v_i,\n",
" v_{\\text{arithmetic}} = \\frac{1}{N} \\sum_{i \\in V_i \\cap P_c} v_i,\n",
"$$\n",
"\n",
"with $N$ being the total number of pedestrians whose Voronoi cells overlap with grid cell $c$.\n",
"\n",
"**Mean speed profile**\n",
"\n",
"The mean speed profile is computed by the mean speed of all pedestrians $P_M$ inside the grid cell $M$:\n",
"The mean speed profile is computed by the average speed of all pedestrians $P_c$ present within a grid cell $c$:\n",
"\n",
"$$\n",
" v_{mean} = \\frac{1}{N} \\sum_{i \\in P_M} v_i\n",
"$$"
" v_{\\text{mean}} = \\frac{1}{N} \\sum_{i \\in P_c} v_i\n",
"$$\n",
"\n",
"where $N$ denotes the number of pedestrians in grid cell $c$.\n",
"\n",
"**Gauss speed profiles**\n",
"\n",
"Calculates a speed profile based on Gaussian weights for an array of pedestrian locations and velocities. The speed, weighted at a grid cell $c$ considering its distance $\\delta = \\boldsymbol{r}_i - \\boldsymbol{c}$ from an agent, is determined as follows:\n",
" \n",
"$$ \n",
" v_{\\text{gauss}} = \\frac{\\sum_{i=1}^{N}{\\big(w_i\\cdot v_i\\big)}}{\\sum_{i=1}^{N} w_i},\n",
"$$\n",
"with \n",
"$w_i = \\frac{1} {\\sigma \\cdot \\sqrt{2\\pi}} \\exp\\big(-\\frac{\\delta^2}{2\\sigma^2}\\big)\\; \\text{and}\\; \\sigma = \\frac{FWHM}{2\\sqrt{2\\ln(2)}}.\n",
"$"
]
},
{
Expand Down Expand Up @@ -2420,6 +2437,14 @@
" walkable_area=walkable_area,\n",
" grid_size=grid_size,\n",
" speed_method=SpeedMethod.MEAN,\n",
")\n",
"\n",
"gauss_speed_profile = compute_speed_profile(\n",
" data=profile_data,\n",
" walkable_area=walkable_area,\n",
" grid_size=grid_size,\n",
" gaussian_width=0.5,\n",
" speed_method=SpeedMethod.GAUSSIAN,\n",
")"
]
},
Expand All @@ -2436,8 +2461,7 @@
"from pedpy import plot_profiles\n",
"import matplotlib.pyplot as plt\n",
"\n",
"fig, (ax0, ax1, ax2) = plt.subplots(nrows=1, ncols=3, layout=\"constrained\")\n",
"fig.set_size_inches(10, 5)\n",
"fig, ((ax0, ax1), (ax2, ax3)) = plt.subplots(nrows=2, ncols=2)\n",
"fig.suptitle(\"Speed profile\")\n",
"cm = plot_profiles(\n",
" walkable_area=walkable_area,\n",
Expand All @@ -2459,14 +2483,25 @@
")\n",
"cm = plot_profiles(\n",
" walkable_area=walkable_area,\n",
" profiles=mean_speed_profile,\n",
" profiles=gauss_speed_profile,\n",
" axes=ax2,\n",
" label=\"v / m/s\",\n",
" vmin=0,\n",
" vmax=1.5,\n",
" title=\"Gauss\",\n",
")\n",
"cm = plot_profiles(\n",
" walkable_area=walkable_area,\n",
" profiles=mean_speed_profile,\n",
" axes=ax3,\n",
" label=\"v / m/s\",\n",
" vmin=0,\n",
" vmax=1.5,\n",
" title=\"Mean\",\n",
")\n",
"\n",
"plt.subplots_adjust(\n",
" left=None, bottom=None, right=None, top=None, wspace=0, hspace=0.6\n",
")\n",
"plt.show()"
]
},
Expand Down Expand Up @@ -2675,6 +2710,176 @@
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Pedestrian Dynamics : Spatial Analysis \n",
"This section corresponds to analysis method which can be used to characterise different crowds or group formations.\n",
"These methods may include measurement of the time-to-collision, pair-distribution function and measurement of crowd polarization.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Pair-distibution function (PDF)\n",
"This method is inspired from condensed matter description and used in the work of [Cordes et al. (2023)](https://doi.org/10.1093/pnasnexus/pgae120) following [Karamousas et al. (2014)](https://doi.org/10.1103/PhysRevLett.113.238701).\n",
"The pair-distribution function (PDF): \n",
"\n",
"$$g(r)=P(r)/P_{Ni}(r)$$\n",
"\n",
"\"Quantifies the probability that two interacting pedestrians are found a given distance r apart, renormalized by the probability $P_{Ni}$ of measuring this distance for pedestrians that do not interact.\"\n",
"\n",
"This probability is approximated here by randomising the time information (randomisation of the time frames).\n",
"\n",
"The pair-distribution function of a given crowd recording can be computed using the following instructions:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import pathlib\n",
"from pedpy import load_trajectory_from_txt, TrajectoryUnit\n",
"\n",
"# Load trajectories\n",
"path_to_file = \"./demo-data/bottleneck/040_c_56_h-.txt\"\n",
"traj = load_trajectory_from_txt(\n",
" trajectory_file=pathlib.Path(path_to_file),\n",
" default_unit=TrajectoryUnit.METER,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from pedpy import compute_pair_distibution_function\n",
"\n",
"# Compute pair distribution function\n",
"radius_bins, pair_distribution = compute_pair_distibution_function(\n",
" traj_data=traj, radius_bin_size=0.1, randomisation_stacking=1\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n",
"\n",
"# Plot the function\n",
"fig, ax1 = plt.subplots(figsize=(5, 5))\n",
"ax1.plot(radius_bins, pair_distribution)\n",
"ax1.set_title(\"Pair Distribution Function\")\n",
"ax1.set_xlabel(\"$r$\", fontsize=16)\n",
"ax1.set_ylabel(\"$g(r)$\", fontsize=16)\n",
"ax1.grid(True, alpha=0.3)\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Parameters of the PDF\n",
"The function `compute_pair_distibution_function` has two main parameters:\n",
"- `radius_bin_size` is the size of the radius bins for which probability will be computed. On one hand a larger bin size results in smoother pdf but decreases the accuracy of the description, as more individuals can be detected in each bin. On the other hand, a smaller bin will increase the accuracy of the description but may lead to noisy or `Nan` values as each bin may not be populated (leading to invalid divisions). We suggest using a bin size value between 0.1 and 0.3 m as these values are close to order of magniture of a chest depth.\n",
"- `randomisation_stacking` is the number of time the data stacked before being shuffled in order to compute the probability $P_{Ni}$ of measuring given pair-wise distances for pedestrians that do not interact. Stacking the data multiple times helps harmonize the random positions more effectively, ensuring that the PDF converges to results that are independent of the randomization method."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"### Variation of the two parameters\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"from matplotlib.cm import twilight\n",
"from time import time\n",
"import pathlib\n",
"from pedpy import (\n",
" compute_pair_distibution_function,\n",
" load_trajectory_from_txt,\n",
" TrajectoryUnit,\n",
")\n",
"\n",
"# Load trajectories\n",
"path_to_file = \"./demo-data/bottleneck/040_c_56_h-.txt\"\n",
"traj = load_trajectory_from_txt(\n",
" trajectory_file=pathlib.Path(path_to_file),\n",
" default_unit=TrajectoryUnit.METER,\n",
")\n",
"# Create a colormap\n",
"cmap = twilight\n",
"\n",
"\n",
"# Plot the function on the first axis\n",
"fig, (ax0, ax1) = plt.subplots(\n",
" 1, 2, figsize=(10, 5)\n",
") # create a figure with 2 axes in one row\n",
"\n",
"## Test the effect of `radius_bin_size`\n",
"param = [0.05, 0.1, 0.25, 0.5]\n",
"N_it = len(param) # number of plots per parameters\n",
"\n",
"for i, p in enumerate(param):\n",
" # compute the pdf with the given parameter\n",
" radius_bins, pair_distribution = compute_pair_distibution_function(\n",
" traj_data=traj, radius_bin_size=p, randomisation_stacking=1\n",
" )\n",
" ax0.plot(\n",
" radius_bins,\n",
" pair_distribution,\n",
" color=cmap(i / N_it),\n",
" label=\"$r_{bin}=$\" + str(p),\n",
" )\n",
"\n",
"ax0.set_title(\"Effect of `radius_bin_size`\")\n",
"ax0.set_ylim((0, 1.3))\n",
"ax0.set_xlabel(\"$r$\", fontsize=16)\n",
"ax0.set_ylabel(\"$g(r)$\", fontsize=16)\n",
"ax0.grid(True, alpha=0.3)\n",
"ax0.legend(title=\"Bin sizes\")\n",
"\n",
"## Test the effect of `randomisation_stacking`\n",
"param = [1, 3, 5]\n",
"N_it = len(param) # number of plots per parameters\n",
"\n",
"for i, p in enumerate(param):\n",
" beg_t = time()\n",
" radius_bins, pair_distribution = compute_pair_distibution_function(\n",
" traj_data=traj, radius_bin_size=0.15, randomisation_stacking=p\n",
" )\n",
" end_t = time()\n",
" ax1.plot(\n",
" radius_bins,\n",
" pair_distribution,\n",
" color=cmap(0.1 + i / N_it),\n",
" label=str(p) + \" times: \" + str(np.round(end_t - beg_t, 2)) + \"s\",\n",
" )\n",
"\n",
"\n",
"ax1.set_ylim((0, 1.3))\n",
"ax1.set_title(\"Effect of 'randomisation_stacking'\")\n",
"ax1.set_ylabel(\"$g(r)$\", fontsize=16)\n",
"ax1.set_xlabel(\"$r$\", fontsize=16)\n",
"ax1.grid(True, alpha=0.3)\n",
"\n",
"fig.tight_layout()\n",
"ax1.legend(title=\"Nb of stacks: Execution time\")\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {
Expand Down Expand Up @@ -3305,7 +3510,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.8"
"version": "3.12.2"
}
},
"nbformat": 4,
Expand Down
Loading