Repository: InsightLab/PyMove (language: python)

Issue:
ImportError: cannot import name 'FilePathOrBuffer' from 'pandas._typing'
**Describe the bug**
Importing pymove raises `ImportError: cannot import name 'FilePathOrBuffer' from 'pandas._typing'`

**To Reproduce**
Steps to reproduce the behavior:
1. Conda install pymove
2. Run import pymove 

```
(pymove) PS C:\Users\anita> python
Python 3.10.4 | packaged by conda-forge | (main, Mar 24 2022, 17:34:17) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import pymove
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "H:\miniconda3\envs\pymove\lib\site-packages\pymove\__init__.py", line 13, in <module>
    from .core.pandas import PandasMoveDataFrame
  File "H:\miniconda3\envs\pymove\lib\site-packages\pymove\core\pandas.py", line 47, in <module>
    from pymove.utils.trajectories import shift
  File "H:\miniconda3\envs\pymove\lib\site-packages\pymove\utils\trajectories.py", line 23, in <module>
    from pandas._typing import FilePathOrBuffer
ImportError: cannot import name 'FilePathOrBuffer' from 'pandas._typing' (H:\miniconda3\envs\pymove\lib\site-packages\pandas\_typing.py)
```


**Desktop (please complete the following information):**
 - OS: Win10

```
(pymove) PS C:\Users\anita> conda list
# packages in environment at H:\miniconda3\envs\pymove:
#
# Name                    Version                   Build  Channel
argon2-cffi               21.3.0             pyhd8ed1ab_0    conda-forge
argon2-cffi-bindings      21.2.0          py310he2412df_2    conda-forge
asttokens                 2.0.5              pyhd8ed1ab_0    conda-forge
attrs                     21.4.0             pyhd8ed1ab_0    conda-forge
backcall                  0.2.0              pyh9f0ad1d_0    conda-forge
backports                 1.0                        py_2    conda-forge
backports.functools_lru_cache 1.6.4              pyhd8ed1ab_0    conda-forge
beautifulsoup4            4.11.1             pyha770c72_0    conda-forge
bleach                    5.0.0              pyhd8ed1ab_0    conda-forge
bokeh                     2.4.2           py310h5588dad_1    conda-forge
branca                    0.4.2              pyhd8ed1ab_0    conda-forge
brotli                    1.0.9                h8ffe710_7    conda-forge
brotli-bin                1.0.9                h8ffe710_7    conda-forge
brotlipy                  0.7.0           py310he2412df_1004    conda-forge
bzip2                     1.0.8                h8ffe710_4    conda-forge
ca-certificates           2021.10.8            h5b45459_0    conda-forge
certifi                   2021.10.8       py310h5588dad_2    conda-forge
cffi                      1.15.0          py310hcbf9ad4_0    conda-forge
charset-normalizer        2.0.12             pyhd8ed1ab_0    conda-forge
click                     8.1.2           py310h5588dad_0    conda-forge
cloudpickle               2.0.0              pyhd8ed1ab_0    conda-forge
colorama                  0.4.4              pyh9f0ad1d_0    conda-forge
convertdate               2.4.0              pyhd8ed1ab_0    conda-forge
cryptography              36.0.2          py310ha857299_1    conda-forge
cycler                    0.11.0             pyhd8ed1ab_0    conda-forge
cytoolz                   0.11.2          py310he2412df_2    conda-forge
dask                      2022.4.1           pyhd8ed1ab_0    conda-forge
dask-core                 2022.4.1           pyhd8ed1ab_0    conda-forge
debugpy                   1.6.0           py310h8a704f9_0    conda-forge
decorator                 5.1.1              pyhd8ed1ab_0    conda-forge
defusedxml                0.7.1              pyhd8ed1ab_0    conda-forge
distributed               2022.4.1           pyhd8ed1ab_0    conda-forge
entrypoints               0.4                pyhd8ed1ab_0    conda-forge
executing                 0.8.3              pyhd8ed1ab_0    conda-forge
flit-core                 3.7.1              pyhd8ed1ab_0    conda-forge
folium                    0.12.1.post1       pyhd8ed1ab_1    conda-forge
fonttools                 4.32.0          py310he2412df_0    conda-forge
freetype                  2.10.4               h546665d_1    conda-forge
fsspec                    2022.3.0           pyhd8ed1ab_0    conda-forge
geohash2                  1.1                        py_0    conda-forge
geojson                   2.5.0                      py_0    conda-forge
geos                      3.10.2               h39d44d4_0    conda-forge
heapdict                  1.0.1                      py_0    conda-forge
hijri-converter           2.2.3              pyhd8ed1ab_0    conda-forge
holidays                  0.13               pyhd8ed1ab_0    conda-forge
idna                      3.3                pyhd8ed1ab_0    conda-forge
importlib-metadata        4.11.3          py310h5588dad_1    conda-forge
importlib_resources       5.7.1              pyhd8ed1ab_0    conda-forge
intel-openmp              2022.0.0          h57928b3_3663    conda-forge
ipykernel                 6.13.0          py310hbbfc1a7_0    conda-forge
ipython                   8.2.0           py310h5588dad_0    conda-forge
ipython_genutils          0.2.0                      py_1    conda-forge
ipywidgets                7.7.0              pyhd8ed1ab_0    conda-forge
jbig                      2.1               h8d14728_2003    conda-forge
jedi                      0.18.1          py310h5588dad_1    conda-forge
jinja2                    3.1.1              pyhd8ed1ab_0    conda-forge
joblib                    1.1.0              pyhd8ed1ab_0    conda-forge
jpeg                      9e                   h8ffe710_0    conda-forge
jsonschema                4.4.0              pyhd8ed1ab_0    conda-forge
jupyter_client            7.2.2              pyhd8ed1ab_1    conda-forge
jupyter_core              4.9.2           py310h5588dad_0    conda-forge
jupyterlab_pygments       0.2.2              pyhd8ed1ab_0    conda-forge
jupyterlab_widgets        1.1.0              pyhd8ed1ab_0    conda-forge
kiwisolver                1.4.2           py310h476a331_1    conda-forge
korean_lunar_calendar     0.2.1              pyh9f0ad1d_0    conda-forge
lcms2                     2.12                 h2a16943_0    conda-forge
lerc                      3.0                  h0e60522_0    conda-forge
libblas                   3.9.0              14_win64_mkl    conda-forge
libbrotlicommon           1.0.9                h8ffe710_7    conda-forge
libbrotlidec              1.0.9                h8ffe710_7    conda-forge
libbrotlienc              1.0.9                h8ffe710_7    conda-forge
libcblas                  3.9.0              14_win64_mkl    conda-forge
libdeflate                1.10                 h8ffe710_0    conda-forge
libffi                    3.4.2                h8ffe710_5    conda-forge
liblapack                 3.9.0              14_win64_mkl    conda-forge
libpng                    1.6.37               h1d00b33_2    conda-forge
libsodium                 1.0.18               h8d14728_1    conda-forge
libtiff                   4.3.0                hc4061b1_3    conda-forge
libwebp                   1.2.2                h57928b3_0    conda-forge
libwebp-base              1.2.2                h8ffe710_1    conda-forge
libxcb                    1.13              hcd874cb_1004    conda-forge
libzlib                   1.2.11            h8ffe710_1014    conda-forge
locket                    0.2.0                      py_2    conda-forge
lz4                       4.0.0           py310h7b86b54_1    conda-forge
lz4-c                     1.9.3                h8ffe710_1    conda-forge
m2w64-gcc-libgfortran     5.3.0                         6    conda-forge
m2w64-gcc-libs            5.3.0                         7    conda-forge
m2w64-gcc-libs-core       5.3.0                         7    conda-forge
m2w64-gmp                 6.1.0                         2    conda-forge
m2w64-libwinpthread-git   5.0.0.4634.697f757               2    conda-forge
markupsafe                2.1.1           py310he2412df_1    conda-forge
matplotlib-base           3.5.1           py310h79a7439_0    conda-forge
matplotlib-inline         0.1.3              pyhd8ed1ab_0    conda-forge
mistune                   0.8.4           py310he2412df_1005    conda-forge
mkl                       2022.0.0           h0e2418a_796    conda-forge
mplleaflet                0.0.5                      py_4    conda-forge
msgpack-python            1.0.3           py310h476a331_1    conda-forge
msys2-conda-epoch         20160418                      1    conda-forge
munkres                   1.1.4              pyh9f0ad1d_0    conda-forge
nbclient                  0.6.0              pyhd8ed1ab_0    conda-forge
nbconvert                 6.5.0              pyhd8ed1ab_0    conda-forge
nbconvert-core            6.5.0              pyhd8ed1ab_0    conda-forge
nbconvert-pandoc          6.5.0              pyhd8ed1ab_0    conda-forge
nbformat                  5.3.0              pyhd8ed1ab_0    conda-forge
nest-asyncio              1.5.5              pyhd8ed1ab_0    conda-forge
notebook                  6.4.10             pyha770c72_0    conda-forge
numpy                     1.22.3          py310hcae7c84_2    conda-forge
openjpeg                  2.4.0                hb211442_1    conda-forge
openssl                   1.1.1n               h8ffe710_0    conda-forge
packaging                 21.3               pyhd8ed1ab_0    conda-forge
pandas                    1.4.2           py310hf5e1058_1    conda-forge
pandoc                    2.18                 h57928b3_0    conda-forge
pandocfilters             1.5.0              pyhd8ed1ab_0    conda-forge
parso                     0.8.3              pyhd8ed1ab_0    conda-forge
partd                     1.2.0              pyhd8ed1ab_0    conda-forge
pickleshare               0.7.5                   py_1003    conda-forge
pillow                    9.1.0           py310h767b3fd_2    conda-forge
pip                       22.0.4             pyhd8ed1ab_0    conda-forge
prometheus_client         0.14.1             pyhd8ed1ab_0    conda-forge
prompt-toolkit            3.0.29             pyha770c72_0    conda-forge
psutil                    5.9.0           py310he2412df_1    conda-forge
pthread-stubs             0.4               hcd874cb_1001    conda-forge
pure_eval                 0.2.2              pyhd8ed1ab_0    conda-forge
pycparser                 2.21               pyhd8ed1ab_0    conda-forge
pygments                  2.11.2             pyhd8ed1ab_0    conda-forge
pymeeus                   0.5.10             pyhd8ed1ab_0    conda-forge
pymove                    3.0.0              pyhd8ed1ab_0    conda-forge
pyopenssl                 22.0.0             pyhd8ed1ab_0    conda-forge
pyparsing                 3.0.8              pyhd8ed1ab_0    conda-forge
pyrsistent                0.18.1          py310he2412df_1    conda-forge
pysocks                   1.7.1           py310h5588dad_5    conda-forge
python                    3.10.4          h9a09f29_0_cpython    conda-forge
python-dateutil           2.8.2              pyhd8ed1ab_0    conda-forge
python-fastjsonschema     2.15.3             pyhd8ed1ab_0    conda-forge
python_abi                3.10                    2_cp310    conda-forge
pytz                      2022.1             pyhd8ed1ab_0    conda-forge
pywin32                   303             py310he2412df_0    conda-forge
pywinpty                  2.0.5           py310h00ffb61_1    conda-forge
pyyaml                    6.0             py310he2412df_4    conda-forge
pyzmq                     22.3.0          py310h73ada01_2    conda-forge
requests                  2.27.1             pyhd8ed1ab_0    conda-forge
scikit-learn              1.0.2           py310h4dafddf_0    conda-forge
scipy                     1.8.0           py310h33db832_1    conda-forge
send2trash                1.8.0              pyhd8ed1ab_0    conda-forge
setuptools                62.1.0          py310h5588dad_0    conda-forge
shapely                   1.8.0           py310h3578588_6    conda-forge
six                       1.16.0             pyh6c4a22f_0    conda-forge
sortedcontainers          2.4.0              pyhd8ed1ab_0    conda-forge
soupsieve                 2.3.1              pyhd8ed1ab_0    conda-forge
sqlite                    3.38.2               h8ffe710_0    conda-forge
stack_data                0.2.0              pyhd8ed1ab_0    conda-forge
tbb                       2021.5.0             h2d74725_1    conda-forge
tblib                     1.7.0              pyhd8ed1ab_0    conda-forge
terminado                 0.13.3          py310h5588dad_1    conda-forge
threadpoolctl             3.1.0              pyh8a188c0_0    conda-forge
tinycss2                  1.1.1              pyhd8ed1ab_0    conda-forge
tk                        8.6.12               h8ffe710_0    conda-forge
toolz                     0.11.2             pyhd8ed1ab_0    conda-forge
tornado                   6.1             py310he2412df_3    conda-forge
tqdm                      4.64.0             pyhd8ed1ab_0    conda-forge
traitlets                 5.1.1              pyhd8ed1ab_0    conda-forge
typing_extensions         4.2.0              pyha770c72_0    conda-forge
tzdata                    2022a                h191b570_0    conda-forge
ucrt                      10.0.20348.0         h57928b3_0    conda-forge
unicodedata2              14.0.0          py310he2412df_1    conda-forge
urllib3                   1.26.9             pyhd8ed1ab_0    conda-forge
vc                        14.2                 hb210afc_6    conda-forge
vs2015_runtime            14.29.30037          h902a5da_6    conda-forge
wcwidth                   0.2.5              pyh9f0ad1d_2    conda-forge
webencodings              0.5.1                      py_1    conda-forge
wheel                     0.37.1             pyhd8ed1ab_0    conda-forge
widgetsnbextension        3.6.0           py310h5588dad_0    conda-forge
win_inet_pton             1.1.0           py310h5588dad_4    conda-forge
winpty                    0.4.3                         4    conda-forge
xorg-libxau               1.0.9                hcd874cb_0    conda-forge
xorg-libxdmcp             1.1.3                hcd874cb_0    conda-forge
xz                        5.2.5                h62dcd97_1    conda-forge
yaml                      0.2.5                h8ffe710_2    conda-forge
zeromq                    4.3.4                h0e60522_1    conda-forge
zict                      2.1.0              pyhd8ed1ab_0    conda-forge
zipp                      3.8.0              pyhd8ed1ab_0    conda-forge
zlib                      1.2.11            h8ffe710_1014    conda-forge
zstd                      1.5.2                h6255e5f_0    conda-forge
```


Pin pandas
## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
-   [ ] Bug fix (non-breaking change which fixes an issue)
-   [ ] New feature (non-breaking change which adds functionality)
-   [ ] Breaking change (fix or feature that would cause existing functionality to change)
-   [ ] I have read the **CONTRIBUTING** document.
-   [ ] My code follows the code style of this project (see `.code-style.md`).
-   [ ] All new and existing tests passed (see `.testing.md`).
-   [ ] I have added tests to cover my changes.
-   [ ] My change requires a change to the documentation.
-   [ ] I have updated the documentation accordingly (see `.documentation.md`).

## Description

-   What is the current behavior? (You can also link to an open issue here)
    <!--- Discuss the new functionality or bug --->

-   What is the new behavior (if this is a feature change)?
    <!--- What your implementation does, what it adds. --->



Discussion / hints:

Fix patch:
diff --git a/docs/api/pymove.utils.rst b/docs/api/pymove.utils.rst
index 90e467a0..b07889cd 100644
--- a/docs/api/pymove.utils.rst
+++ b/docs/api/pymove.utils.rst
@@ -84,6 +84,14 @@ pymove.utils.mem module
    :undoc-members:
    :show-inheritance:
 
+pymove.utils.networkx module
+----------------------------
+
+.. automodule:: pymove.utils.networkx
+   :members:
+   :undoc-members:
+   :show-inheritance:
+
 pymove.utils.trajectories module
 --------------------------------
 
diff --git a/pymove/__init__.py b/pymove/__init__.py
index 32bdb6a9..c556099e 100644
--- a/pymove/__init__.py
+++ b/pymove/__init__.py
@@ -33,4 +33,4 @@
 from .utils.trajectories import read_csv
 from .visualization import folium, matplotlib
 
-__version__ = '3.0.0'
+__version__ = '3.0.1'
diff --git a/pymove/core/dask.py b/pymove/core/dask.py
index 05c15a90..fbc0a52a 100644
--- a/pymove/core/dask.py
+++ b/pymove/core/dask.py
@@ -1,3 +1,4 @@
+# mypy: ignore-errors
 """DaskMoveDataFrame class."""
 from __future__ import annotations
 
diff --git a/pymove/query/query.py b/pymove/query/query.py
index aa02915b..2fe56f49 100644
--- a/pymove/query/query.py
+++ b/pymove/query/query.py
@@ -2,10 +2,11 @@
 Query operations.
 
 range_query,
-knn_query
+knn_query,
+query_all_points_by_range,
 
 """
-from __future__ import annotations
+from datetime import timedelta
 
 import numpy as np
 import pandas as pd
@@ -62,6 +63,25 @@ def range_query(
     ------
         ValueError: if distance measure is invalid
 
+    Examples
+    --------
+    >>> from pymove.query.query import range_query
+    >>> traj_df
+         lat      lon              datetime  id
+    0   16.4    -54.9   2014-10-11 18:00:00   1
+    1   16.4    -55.9   2014-10-12 00:00:00   1
+    2   16.4    -56.9   2014-10-12 06:00:00   1
+    >>> move_df
+         lat      lon              datetime  id
+    0   33.1    -77.0   2012-05-19 00:00:00   2
+    1   32.8    -77.1   2012-05-19 06:00:00   3
+    2   32.5    -77.3   2012-05-19 12:00:00   4
+    >>> range_query(
+    >>>    traj_df, move_df, min_dist=80.5
+    >>> )
+         lat      lon              datetime  id
+    1   32.8	-77.1	2012-05-19 06:00:00	  3
+    2	32.5	-77.3	2012-05-19 12:00:00	  4
     """
     result = traj.copy()
     result.drop(result.index, inplace=True)
@@ -136,6 +156,27 @@ def knn_query(
     ------
         ValueError: if distance measure is invalid
 
+    Examples
+    --------
+    >>> from pymove.query.query import knn_query
+    >>> traj_df
+         lat      lon              datetime  id
+    0   16.4    -54.9   2014-10-11 18:00:00   1
+    1   16.4    -55.9   2014-10-12 00:00:00   1
+    2   16.4    -56.9   2014-10-12 06:00:00   1
+    >>> move_df
+         lat      lon              datetime  id
+    0   33.1    -77.0   2012-05-19 00:00:00   2
+    1   32.8    -77.1   2012-05-19 06:00:00   3
+    2   32.5    -77.3   2012-05-19 12:00:00   4
+    >>> knn_query(
+    >>>    traj_df, move_df, k=1
+    >>> )
+         lat      lon              datetime  id
+    0	16.4	-54.9	2014-10-11 18:00:00   1
+    1	16.4	-55.9	2014-10-12 00:00:00	  1
+    2	16.4	-56.9	2014-10-12 06:00:00	  1
+    2	32.5	-77.3	2012-05-19 12:00:00	  4
     """
     k_list = pd.DataFrame([[np.Inf, 'empty']] * k, columns=['distance', TRAJ_ID])
 
@@ -176,3 +217,200 @@ def dist_measure(traj, this, latitude, longitude, datetime):
         )
 
     return result
+
+
+def _datetime_filter(
+    row: DataFrame,
+    move_df: DataFrame,
+    minimum_distance: timedelta
+) -> DataFrame:
+    """
+    Returns all the points of the DataFrame which are in a temporal distance.
+
+    Given a row referencing to a point, a DataFrame with
+    multiple points and a minimum distance, it returns
+    all the points of the DataFrame which are in a temporal
+    distance equal or smaller than the minimum distance
+    parameter.
+
+    Parameters
+    ----------
+    row: dataframe
+        The input of one point of a trajectory.
+    move_df: dataframe
+        The input trajectory data.
+    minimum_distance: datetime.timedelta
+        the minimum temporal distance between the points.
+
+    Returns
+    -------
+    DataFrame
+        dataframe with all the points of move_df which are in
+        a temporal distance equal or smaller than the minimum
+        distance parameter.
+
+    Examples
+    --------
+    >>> from pymove.query.query import _datetime_filter
+    >>>> point
+         lat      lon              datetime  id
+    0   16.4    -54.9   2014-10-11 18:00:00   1
+    >>> move_df
+         lat      lon              datetime  id
+    0   33.1    -77.0   2012-05-19 00:00:00   2
+    1   32.8    -77.1   2012-05-19 06:00:00   3
+    2   32.5    -77.3   2012-05-19 12:00:00   4
+    >>> _datetime_filter(point, move_df, timedelta(hours=21010))
+         lat      lon              datetime  id   temporal_distance\
+        target_id   target_lat  target_lon        target_datetime
+    0   32.5    -77.3   2012-05-19 12:00:00   4   875 days 06:00:00\
+                1          16.4       -54.9    2014-10-11 18:00:00
+    """
+    datetime = row['datetime']
+    move_df['temporal_distance'] = (move_df['datetime'] - datetime).abs()
+    filtered = move_df[
+        (move_df['temporal_distance'] < minimum_distance)
+        & (move_df['temporal_distance'] > -minimum_distance)
+    ]
+
+    if (filtered.shape[0] > 0):
+        filtered['target_id'] = row['id']
+        filtered['target_lat'] = row['lat']
+        filtered['target_lon'] = row['lon']
+        filtered['target_datetime'] = row['datetime']
+
+    return filtered
+
+
+def _meters_filter(
+    row: DataFrame,
+    move_df: DataFrame,
+    minimum_distance: float
+) -> DataFrame:
+    """
+    Returns all the points of the DataFrame which are in a spatial distance.
+
+    Given a row referencing to a point, a DataFrame with
+    multiple points and a minimum distance, it returns
+    all the points of the DataFrame which are in a spatial
+    distance (in meters) equal or smaller than the minimum distance
+    parameter.
+
+    Parameters
+    ----------
+    row: dataframe
+        The input of one point of a trajectory.
+    move_df: dataframe
+        The input trajectory data.
+    minimum_distance: float
+        the minimum spatial distance between the points in meters.
+
+    Returns
+    -------
+    DataFrame
+        dataframe with all the points of move_df which are in
+        a spatial distance equal or smaller than the minimum
+        distance parameter.
+
+    Examples
+    --------
+    >>> from pymove.query.query import _meters_filter
+    >>> point
+         lat      lon              datetime  id
+    0   16.4    -54.9   2014-10-11 18:00:00   1
+    >>> move_df
+         lat      lon              datetime  id
+    0   33.1    -77.0   2012-05-19 00:00:00   2
+    1   32.8    -77.1   2012-05-19 06:00:00   3
+    2   32.5    -77.3   2012-05-19 12:00:00   4
+    >>> _meters_filter(firstpoint, move_df, 3190000)
+         lat      lon              datetime  id spatial_distance\
+        target_id   target_lat  target_lon      target_datetime
+    0   32.5    -77.3   2012-05-19 12:00:00   4     3.182834e+06\
+                1         16.4       -54.9  2014-10-11 18:00:00
+    """
+    lat = row[LATITUDE]
+    lon = row[LONGITUDE]
+    move_df['spatial_distance'] = distances.euclidean_distance_in_meters(
+        lat1=lat, lon1=lon, lat2=move_df[LATITUDE], lon2=move_df[LONGITUDE]
+    )
+    filtered = move_df[move_df['spatial_distance'] < minimum_distance]
+
+    if (filtered.shape[0] > 0):
+        filtered['target_id'] = row[TRAJ_ID]
+        filtered['target_lat'] = row[LATITUDE]
+        filtered['target_lon'] = row[LONGITUDE]
+        filtered['target_datetime'] = row[DATETIME]
+
+    return filtered
+
+
+def query_all_points_by_range(
+    traj1: DataFrame,
+    move_df: DataFrame,
+    minimum_meters: float = 100,
+    minimum_time: timedelta = None
+) -> DataFrame:
+    """
+    Queries closest point within a spatial range based on meters and a temporal range.
+
+    Selects only the points between two Move Dataframes
+    that have the closest point within a spatial range
+    based on meters and a temporal range.
+
+    Parameters
+    ----------
+    traj1: dataframe
+        The input of a trajectory data.
+    move_df: dataframe
+        The input of another trajectory data.
+    minimum_meters: float, optional
+        the minimum spatial distance, based in meters, between the points, by default 100
+    minimum_time: datetime.timedelta, optional
+        the minimum temporal distance between the points, by default timedelta(minutes=2)
+    datetime_label: string, optional
+        the label that refers to the datetime label of the dataframes, by default DATETIME
+
+    Returns
+    -------
+    DataFrame
+        dataframe with all the points of move_df which are in
+        a spatial distance and temporal distance equal or smaller
+        than the minimum distance parameters.
+
+    Examples
+    --------
+    >>> from pymove.query.query import query_all_points_by_range
+    >>> traj_df
+         lat      lon              datetime  id
+    0   16.4    -54.9   2014-10-11 18:00:00   1
+    1   16.4    -55.9   2014-10-12 00:00:00   1
+    2   16.4    -56.9   2014-10-12 06:00:00   1
+    >>> move_df
+         lat      lon              datetime  id
+    0   33.1    -77.0   2012-05-19 00:00:00   2
+    1   32.8    -77.1   2012-05-19 06:00:00   3
+    2   32.5    -77.3   2012-05-19 12:00:00   4
+    >>> query_all_points_by_range(
+    >>>    traj_df, move_df, minimum_meters=3190000, minimum_time=timedelta(hours=21010)
+    >>> )
+         lat      lon              datetime  id    spatial_distance target_id\
+        target_lat  target_lon        target_datetime   temporal_distance
+    0   32.5    -77.3   2012-05-19 12:00:00   4        3.182834e+06         1\
+             16.4       -54.9    2014-10-11 18:00:00   875 days 06:00:00
+    """
+    if minimum_time is None:
+        minimum_time = timedelta(minutes=2)
+
+    result = DataFrame([])
+    total = traj1.shape[0]
+    for _, row in progress_bar(
+        traj1.iterrows(),
+        desc='Querying all points by temporal and spatial distance',
+        total=total
+    ):
+        coinc_points = _meters_filter(row, move_df, minimum_meters)
+        coinc_points = _datetime_filter(row, coinc_points, minimum_time)
+        result = coinc_points.append(result)
+
+    return result
diff --git a/pymove/utils/conversions.py b/pymove/utils/conversions.py
index fd39efbd..25ea6b50 100644
--- a/pymove/utils/conversions.py
+++ b/pymove/utils/conversions.py
@@ -199,7 +199,7 @@ def lon_to_x_spherical(lon: float | ndarray) -> float | ndarray:
     Parameters
     ----------
     lon : float
-        Represents longitude.
+        This represents longitude value.
 
     Returns
     -------
@@ -229,7 +229,7 @@ def lat_to_y_spherical(lat: float | ndarray) -> float | ndarray:
     Parameters
     ----------
     lat : float
-        Represents latitude.
+        This represents latitude value.
 
     Returns
     -------
diff --git a/pymove/utils/data_augmentation.py b/pymove/utils/data_augmentation.py
index 1bbb2771..ace41852 100644
--- a/pymove/utils/data_augmentation.py
+++ b/pymove/utils/data_augmentation.py
@@ -3,25 +3,30 @@
 
 append_row,
 generate_trajectories_df,
-generate_start_feature,
-generate_destiny_feature,
 split_crossover,
-augmentation_trajectories_df,
-insert_points_in_df,
-instance_crossover_augmentation
+_augmentation,
+flatten_trajectories_dataframe,
+instance_crossover_augmentation,
+sliding_window,
+get_all_paths,
+transition_graph_augmentation_all_vertex
 
 """
 from __future__ import annotations
 
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, Text
 
+import networkx as nx
 import numpy as np
 import pandas as pd
+from networkx.classes.digraph import DiGraph
 from pandas.core.frame import DataFrame
 from pandas.core.series import Series
 
-from pymove.utils.constants import DESTINY, START, TID, TRAJECTORY
+from pymove.utils.constants import DESTINY, LOCAL_LABEL, START, TID
 from pymove.utils.log import progress_bar
+from pymove.utils.networkx import build_transition_graph_from_df
+from pymove.utils.trajectories import append_trajectory, split_trajectory
 
 if TYPE_CHECKING:
     from pymove.core.dask import DaskMoveDataFrame
@@ -45,6 +50,39 @@ def append_row(
     columns : dict, optional
         Dictionary containing the values to be added, by default None
 
+    Example
+    -------
+    >>> from pymove.utils.data_augmentation import append_row
+    >>>
+    >>> df
+      id            datetime  local        lat         lon          tid
+    0  1  2017-09-02 21:59:34    162  -3.843132  -38.593314  12017090221
+    1  1  2017-09-02 22:00:27     85  -3.834748  -38.592189  12017090222
+    2  1  2017-09-02 22:01:36    673  -3.823583  -38.590389  12017090222
+    3  1  2017-09-02 22:03:08    394  -3.813889  -38.590444  12017090222
+    4  1  2017-09-02 22:03:46    263  -3.906765  -38.590772  12017090222
+    5  1  2017-09-02 22:07:19    224  -3.885722  -38.592889  12017090222
+    >>>
+    >>> row
+    id                            1
+    datetime    2017-09-02 22:07:40
+    local                       623
+    lat                    -3.88287
+    lon                     -38.593
+    tid                 12017090222
+    dtype: object
+    >>>
+    >>> append_row(df, row)
+    >>> df
+      id             datetime  local        lat         lon          tid
+    0  1  2017-09-02 21:59:34    162  -3.843132  -38.593314  12017090221
+    1  1  2017-09-02 22:00:27     85  -3.834748  -38.592189  12017090222
+    2  1  2017-09-02 22:01:36    673  -3.823583  -38.590389  12017090222
+    3  1  2017-09-02 22:03:08    394  -3.813889  -38.590444  12017090222
+    4  1  2017-09-02 22:03:46    263  -3.906765  -38.590772  12017090222
+    5  1  2017-09-02 22:07:19    224  -3.885722  -38.592889  12017090222
+    6  1  2017-09-02 22:07:40    623  -3.882872  -38.592979  12017090222
+
     """
     if row is not None:
         keys = row.index.tolist()
@@ -57,7 +95,9 @@ def append_row(
 
 
 def generate_trajectories_df(
-    data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame'
+    data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+    label_tid: Text = TID,
+    min_points_traj: int = 3
 ) -> DataFrame:
     """
     Generates a dataframe with the sequence of location points of a trajectory.
@@ -66,83 +106,52 @@ def generate_trajectories_df(
     ----------
     data : DataFrame
         The input trajectory data.
+    label_tid: String, optional
+        Label referring to the ID of the trajectories, by default TID
+    min_points_traj: Number, optional
+        Minimum points per trajectory, by default 3
 
     Return
     ------
     DataFrame
         DataFrame of the trajectories
 
-    """
-    if TID not in data:
-        data.generate_tid_based_on_id_datetime()
-        data.reset_index(drop=True, inplace=True)
-
-    tids = data[TID].unique()
-    new_df = pd.DataFrame(
-        columns=data.columns
-    )
-
-    for tid in progress_bar(tids, total=len(tids)):
-        filter_ = data[data[TID] == tid]
-        filter_.reset_index(drop=True, inplace=True)
-
-        if filter_.shape[0] > 4:
-
-            values = []
-            for col in filter_.columns:
-                if filter_[col].nunique() == 1:
-                    values.append(filter_.at[0, col])
-                else:
-                    values.append(
-                        np.array(
-                            filter_[col], dtype=type(filter_.at[0, col])
-                        ).tolist()
-                    )
-
-            row = pd.Series(values, filter_.columns)
-            append_row(new_df, row=row)
-
-    return new_df
-
-
-def generate_start_feature(
-    data: DataFrame, label_trajectory: str = TRAJECTORY
-):
-    """
-    Removes the last point from the trajectory and adds it in a new column 'destiny'.
-
-    Parameters
-    ----------
-    data : DataFrame
-        The input trajectory data.
-    label_trajectory : str, optional
-        Label of the points sequences, by default TRAJECTORY
+    Example
+    -------
+    >>> from pymove.utils.data_augmentation import generate_trajectories_df
+    >>>
+    >>> df
+      id             datetime  local         lat          lon          tid
+    0  1  2017-09-02 21:59:34    162  -3.8431323  -38.5933142  12017090221
+    1  1  2017-09-02 22:00:27     85  -3.8347478  -38.5921890  12017090222
+    2  1  2017-09-02 22:01:36    673  -3.8235834  -38.5903890  12017090222
+    3  1  2017-09-02 22:03:08    394  -3.8138890  -38.5904445  12017090222
+    4  1  2017-09-02 22:03:46    263  -3.9067654  -38.5907723  12017090222
+    5  1  2017-09-02 22:07:19    224  -3.8857223  -38.5928892  12017090222
+    6  1  2017-09-02 22:07:40    623  -3.8828723  -38.5929789  12017090222
+    >>>
+    >>> traj_df = generate_trajectories_df(df)
+    >>> traj_df.local
+    0    [85, 673, 394, 263, 224, 623]
+    Name: local, dtype: object
 
     """
-    if START not in data:
-        data[START] = data[label_trajectory].apply(
-            lambda x: np.int64(x[0])
+    if label_tid not in data:
+        raise ValueError(
+            '{} not in DataFrame'.format(label_tid)
         )
 
+    frames = []
+    tids = data[label_tid].unique()
 
-def generate_destiny_feature(
-    data: DataFrame, label_trajectory: str = TRAJECTORY
-):
-    """
-    Removes the first point from the trajectory and adds it in a new column 'start'.
+    desc = 'Gererating Trajectories DataFrame'
+    for tid in progress_bar(tids, desc=desc, total=len(tids)):
+        frame = data[data[label_tid] == tid]
 
-    Parameters
-    ----------
-    data : DataFrame
-        The input trajectory data.
-    label_trajectory : str, optional
-        Label of the points sequences, by default 'trajectory'
+        if frame.shape[0] >= min_points_traj:
+            frames.append(frame.T.values.tolist())
 
-    """
-    if DESTINY not in data:
-        data[DESTINY] = data[label_trajectory].apply(
-            lambda x: np.int64(x[-1])
-        )
+    return pd.DataFrame(frames, columns=data.columns)
 
 
 def split_crossover(
@@ -162,9 +171,20 @@ def split_crossover(
 
     Returns
     -------
-    Tuple[List, List]
+    tuple[list, list]
         Arrays with the halves exchanged.
 
+    Example
+    -------
+    >>> from pymove.utils.data_augmentation import split_crossover
+    >>>
+    >>> sequence_a, sequence_b
+    ([0, 2, 4, 6, 8], [1, 3, 5, 7, 9])
+    >>>
+    >>> sequence_a, sequence_b = split_crossover(sequence_a, sequence_b)
+    >>> sequence_a, sequence_b
+    ([0, 2, 5, 7, 9], [1, 3, 4, 6, 8])
+
     """
     size_a = int(len(sequence_a) * frac)
     size_b = int(len(sequence_b) * frac)
@@ -181,7 +201,9 @@ def split_crossover(
     return sequence_a, sequence_b
 
 
-def _augmentation(data: DataFrame, aug_df: DataFrame, frac: float = 0.5):
+def _augmentation(
+    traj_df: DataFrame, frac: float = 0.5
+):
     """
     Generates new data with unobserved trajectories.
 
@@ -189,185 +211,432 @@ def _augmentation(data: DataFrame, aug_df: DataFrame, frac: float = 0.5):
     ----------
     data : DataFrame
         The input trajectories data.
-    aug_df : DataFrame
-        The dataframe with new trajectories
-    frac : number, optional
+    frac : float, optional
         Represents the percentage to be exchanged, by default 0.5
 
+    Return
+    ------
+    DataFrame
+        Increased data set.
+
+    Example
+    -------
+    >>> from pymove.utils.data_augmentation import _augmentation
+    >>>
+    >>> traj_df
+                  id                 local
+    0      [1, 1, 1]        [85, 673, 394]
+    1 	[2, 2, 2, 2]  [263, 224, 623, 515]
+    >>>
+    >>> _augmentations(traj_df, frac=0.5)
+                  id                 local
+    0 	   [1, 1, 1] 	    [85, 673, 394]
+    1 	[2, 2, 2, 2]  [263, 224, 623, 515]
+    2 	   [1, 2, 2]    	[85, 623, 515]
+    3 	[2, 2, 1, 1]  [263, 224, 673, 394]
+
     """
-    data.reset_index(drop=True, inplace=True)
-
-    for idx in range(data.shape[0] - 1):
-        for idx_ in range(idx + 1, data.shape[0]):
-            sequences1 = []
-            sequences2 = []
-
-            columns = data.columns
-
-            for col in columns:
-                if (isinstance(
-                    data.at[idx, col], list
-                ) or isinstance(
-                    data.at[idx, col], np.ndarray
-                )) and (isinstance(
-                    data.at[idx_, col], list
-                ) or isinstance(
-                    data.at[idx_, col], np.ndarray
-                )):
-                    seq1, seq2 = split_crossover(
-                        data.at[idx, col],
-                        data.at[idx_, col],
-                        frac=frac
-                    )
-                    sequences1.append(seq1)
-                    sequences2.append(seq2)
-                else:
-                    value1 = data.at[idx, col]
-                    value2 = data.at[idx_, col]
-
-                    if isinstance(value1, str) and isinstance(value2, str):
-                        sequences1.append(value1 + '_' + value2)  # type: ignore
-                        sequences2.append(value2 + '_' + value1)  # type: ignore
-                    else:
-                        sequences1.append(value1)
-                        sequences2.append(value2)
-
-            row = pd.Series(sequences1, index=columns)
-            append_row(aug_df, row=row)
-
-            row = pd.Series(sequences2, index=columns)
-            append_row(aug_df, row=row)
-
-
-def augmentation_trajectories_df(
-    data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+    traj_df.reset_index(drop=True, inplace=True)
+
+    frames = {}
+    for idx, row in traj_df.iterrows():
+        if idx + 1 < traj_df.shape[0]:
+            series = {}
+            for column in traj_df.columns:
+                series[column] = pd.Series(
+                    traj_df[idx + 1:][column].apply(
+                        lambda x: split_crossover(row[column], x, frac)
+                    ).values[0], name=column,
+                )
+            frames[idx] = pd.concat([series[col] for col in traj_df.columns], axis=1)
+
+    aug_df = pd.concat(
+        [frames[i] for i in range(len(frames))], axis=1
+    )
+    return pd.concat([traj_df, aug_df], ignore_index=True)
+
+
+def flatten_trajectories_dataframe(traj_df: DataFrame) -> DataFrame:
+    """
+    Extracts information from trajectories.
+
+    Parameters
+    ----------
+    traj_df : DataFrame
+        The input trajectories data
+
+    Return
+    ------
+    DataFrames
+        Flat trajectories.
+
+    Example
+    -------
+    >>> from pymove.utils.data_augmentation import flatten_trajectories_dataframe
+    >>>
+    >>> traj_df
+                 id                 local
+    0     [1, 1, 1]        [85, 673, 394]
+    1  [2, 2, 2, 2]  [263, 224, 623, 515]
+    >>>
+    >>> flatten_trajectories_dataframe(traj_df)
+       id  local
+    0   1     85
+    1   1    673
+    2   1    394
+    3   2    263
+    4   2    224
+    5   2    623
+    6   2    515
+
+    """
+    frames = {}
+    for idx, row in progress_bar(traj_df.iterrows(), total=traj_df.shape[0]):
+        frames[idx] = pd.DataFrame(row.to_dict())
+
+    return pd.concat([frames[i] for i in range(len(frames))], ignore_index=True)
+
+
+def instance_crossover_augmentation(
+    data: DataFrame,
     restriction: str = 'destination only',
-    label_trajectory: str = TRAJECTORY,
-    insert_at_df: bool = False,
+    label_local: Text = LOCAL_LABEL,
     frac: float = 0.5,
 ) -> DataFrame:
     """
-    Generates new data from unobserved trajectories, given a specific restriction.
+    Generates new data from unobserved trajectories, with a specific restriction.
 
-    By default, the algorithm uses the same route destination constraint.
+    By default, the algorithm uses the same destination constraint
+    as the route and inserts the points on the
+    original dataframe.
 
     Parameters
     ----------
     data : DataFrame
-        The input trajectories data.
+        The input trajectories data
     restriction : str, optional
         Constraint used to generate new data, by default 'destination only'
-    label_trajectory : str, optional
-        Label of the points sequences, by default TRAJECTORY
-    insert_at_df : boolean, optional
-        Whether to return a new DataFrame, by default False
-        If True then value of copy is ignored.
-    frac : number, optional
+    label_local : str, optional
+        Label of the points sequences, by default LOCAL_LABEL
+    frac : float, optional
         Represents the percentage to be exchanged, by default 0.5
 
-    Returns
+    Example
     -------
-    DataFrame
-        Dataframe with the new data generated
+    >>> from pymove.utils.data_augmentation import instance_crossover_augmentation
+    >>>
+    >>> df
+                 id 	     local_label
+    0     [1, 1, 1]       [85, 673, 394]
+    1  [2, 2, 2, 2]  [85, 224, 623, 394]
+    2     [3, 3, 3]      [263, 673, 394]
+    >>>
+    >>> aug_df = instance_crossover_augmentation(df)
+    >>> aug_df
+                 id 	     local_label
+    0     [1, 1, 1]       [85, 673, 394]
+    1  [2, 2, 2, 2]  [85, 224, 623, 394]
+    2     [3, 3, 3]      [263, 673, 394]
+    3     [1, 2, 2]       [85, 623, 394]
+    4  [2, 2, 1, 1]  [85, 224, 673, 394]
+    5  [2, 2, 3, 3]  [85, 224, 673, 394]
+    6     [3, 2, 2]      [263, 623, 394]
 
     """
-    if DESTINY not in data:
-        generate_destiny_feature(data, label_trajectory=label_trajectory)
+    df = data.copy()
 
-    if restriction == 'departure and destination':
-        generate_start_feature(data)
+    df[DESTINY] = df[label_local].apply(lambda x: x[-1])
+    df[START] = df[label_local].apply(lambda x: x[0])
 
-    if insert_at_df:
-        aug_df = data
-    else:
-        aug_df = pd.DataFrame(columns=data.columns)
-
-    destinations = data[DESTINY].unique()
-    for dest in progress_bar(destinations, total=len(destinations)):
-        filter_ = data[data[DESTINY] == dest]
+    frames = {}
+    destinations = df[DESTINY].unique()
+    for idx, dest in progress_bar(enumerate(destinations), total=len(destinations)):
+        filter_ = df[df[DESTINY] == dest]
 
         if restriction == 'departure and destination':
             starts = filter_[START].unique()
 
             for st in progress_bar(starts, total=len(starts)):
-                f_filter_ = filter_[filter_[START] == st]
-
-                if f_filter_.shape[0] >= 2:
-                    _augmentation(f_filter_, aug_df, frac=frac)
+                filter_ = filter_[filter_[START] == st]
 
+                if filter_.shape[0] >= 2:
+                    frames[idx] = _augmentation(filter_.iloc[:, :-2], frac=frac)
         else:
             if filter_.shape[0] >= 2:
-                _augmentation(filter_, aug_df, frac=frac)
+                frames[idx] = _augmentation(filter_.iloc[:, :-2], frac=frac)
 
-    return aug_df
+    return pd.concat([frames[i] for i in range(len(frames))], axis=0, ignore_index=True)
 
 
-def insert_points_in_df(data: DataFrame, aug_df: DataFrame):
+def sliding_window(
+    data: DataFrame,
+    size_window: int = 6,
+    size_jump: int = 3,
+    label_local: Text = LOCAL_LABEL,
+    columns: list = None,
+) -> DataFrame:
     """
-    Inserts the points of the generated trajectories to the original data sets.
+    Sliding window technique.
+
+    Performs an increase in the trajectory data by sliding a window
+    Over each sequence to a specified size n, skipping m points.
+    This process inserts sub-trajectories in the data set.
 
     Parameters
     ----------
-    data : DataFrame
-        The input trajectories data
-    aug_df : DataFrame
-        The data of unobserved trajectories
+    data: DataFrame
+        Trajectory data in sequence format
+    size_window: int, optional
+        Sliding window size, by default 6
+    size_jump: int, optional
+        Size of the jump in the trajectory, by default 3
+    label_local: str, optional
+        Name of the column referring to the trajectories, by default LOCAL_LABEL
+    columns: list, optional
+        Columns to which the split will be applied, by default None
+
+    Return
+    ------
+    DataFrame
+        Increased data set.
+
+    Example
+    -------
+    >>> from pymove.utils.data_augmentation import sliding_window
+    >>>
+    >>> traj_df
+                             id                                   local
+    0  [1, 1, 1, 1, 1, 1, 1, 1]  [85, 673, 394, 85, 224, 623, 394, 263]
+    1        [2, 2, 2, 2, 2, 2]      [85, 224, 623, 394, 263, 673, 394]
+    2     [3, 3, 3, 3, 3, 3, 3]  [263, 673, 394, 85, 673, 394, 85, 224]
+    >>>
+    >>> sliding_window(traj_df, size_jump=1)
+                        id 	                  local_label
+    0   [1, 1, 1, 1, 1, 1] 	[ 85, 673, 394, 85, 224, 623]
+    1   [1, 1, 1, 1, 1, 1] 	[673, 394, 85, 224, 623, 394]
+    2   [1, 1, 1, 1, 1, 1] 	[394, 85, 224, 623, 394, 263]
+    3   [2, 2, 2, 2, 2, 2] 	[85, 224, 623, 394, 263, 673]
+    4   [3, 3, 3, 3, 3, 3] 	[263, 673, 394, 85, 673, 394]
+    5   [3, 3, 3, 3, 3, 3] 	[673, 394, 85, 673, 394,  85]
 
     """
-    for _, row in progress_bar(aug_df.iterrows(), total=aug_df.shape[0]):
+    if columns is None:
+        columns = data.columns
 
-        keys = row.index.tolist()
-        values = row.values.tolist()
+    frames = {}
+    desc = 'Sliding Window...'
+    for idx, row in progress_bar(data.iterrows(), desc=desc, total=data.shape[0]):
+        frames[idx] = split_trajectory(row, size_window, size_jump, label_local, columns)
 
-        row_df = pd.DataFrame()
+    return pd.concat([frame for frame in frames.values()], ignore_index=True)
 
-        for k, v in zip(keys, values):
-            if k in data:
-                if isinstance(v, list) or isinstance(v, np.ndarray):
-                    row_df[k] = v
 
-        for k, v in zip(keys, values):
-            if k in data:
-                if not isinstance(v, list) and not isinstance(v, np.ndarray):
-                    row_df[k] = v
+def get_all_paths(
+    traj_df: DataFrame, graph: DiGraph, source: str, target: str,
+    min_path_size: int = 3, max_path_size: int = 6,
+    max_sampling_source: int = 100,
+    max_sampling_target: int = 100,
+    label_local: str = LOCAL_LABEL,
+    simple_paths: bool = False
+):
+    """
+    Generate All Paths.
 
-        for _, row_ in row_df.iterrows():
-            append_row(data, row=row_)
+    Retrieves all paths in the graph between the past source and
+    destination, if any. The number of paths returned is limited
+    by the max_sampling_source and max_sampling_target
+    parameters, and the path size is limited by the
+    min_path_size and max_path_size parameters.
 
+    Parameters
+    ----------
+    traj_df: DataFrame
+        Trajectory data in sequence format.
+    graph: DiGraph
+        Transition graph constructed from trajectory data.
+    source: Node
+        Sequence source node.
+    target: Node
+        Sequence destination node.
+    min_path_size: int, optional
+        Minimum number of points for the trajectory, by default 3
+    max_path_size: int, optional
+        Maximum number of points for the trajectory, by default 6
+    max_sampling_source: int, optional
+        Maximum number of paths to be returned,
+        considering the observed origin, by default 10
+    max_sampling_target: int, optional
+        Maximum number of paths to be returned,
+        considering the observed destination, by default 10
+    label_local: str, optional
+        Name of the column referring to the trajectories, by default LOCAL_LABEL
+    simple_paths: bool, optional
+        If true, use the paths with the most used sections
+        Otherwise, use paths with less used sections, by default False
+
+    Example
+    -------
+    >>> from pymove.utils.data_augmentation import get_all_paths
+    >>>
+    >>> traj_df.to_dict()
+    {'id': [[1, 1, 1], [2, 2, 2, 2]],
+     'datetime': [['2017-09-02 22:00:27', '2017-09-02 22:01:36',
+                   '2017-09-02 22:03:08'],
+                  ['2017-09-02 23:03:46', '2017-09-02 23:07:19',
+                   '2017-09-02 23:07:40', '2017-09-02 23:09:10']],
+     'local_label': [[85, 673, 394], [263, 224, 623, 394]],
+     'lat': [[-3.8347478, -3.8235834, -3.813889],
+             [-3.9067654, -3.8857223, -3.8828723, -3.9939834]],
+     'lon': [[-38.592189, -38.590389, -38.5904445],
+             [-38.5907723, -38.5928892, -38.5929789, -38.70409]]}
+    >>>
+    >>> graph = build_transition_graph_from_df(traj_df)
+    >>>
+    >>> get_all_paths(traj_df, graph, 224, 394)
+    [224.0, 623.0, 394.0]
 
-def instance_crossover_augmentation(
-    data: DataFrame,
-    restriction: str = 'destination only',
-    label_trajectory: str = TRAJECTORY,
-    frac: float = 0.5
-):
     """
-    Generates new data from unobserved trajectories, with a specific restriction.
+    if not nx.has_path(graph, source, target):
+        return []
 
-    By default, the algorithm uses the same destination constraint
-    as the route and inserts the points on the
-    original dataframe.
+    param: int | None = None
+
+    if simple_paths:
+        all_paths = nx.all_simple_paths
+        param = max_path_size - 1
+
+    else:
+        all_paths = nx.shortest_simple_paths
+
+    for path in all_paths(graph, source, target, param):
+        freq_source = nx.get_node_attributes(graph, 'freq_source')[source]
+        freq_target = nx.get_node_attributes(graph, 'freq_target')[target]
+
+        if freq_source >= max_sampling_source:
+            break
+
+        if freq_target >= max_sampling_target:
+            break
+
+        if len(path) > max_path_size and simple_paths is False:
+            break
+
+        if len(path) >= min_path_size:
+            path_ = np.array(path, dtype='float32').tolist()
+            if path_ not in traj_df[label_local].values.tolist():
+
+                print(path_)
+                append_trajectory(traj_df, path, graph)
+
+                freq_source += 1
+                freq_target += 1
+
+                graph.add_node(source, freq_source=freq_source)
+                graph.add_node(target, freq_target=freq_target)
+
+
+def transition_graph_augmentation_all_vertex(
+    traj_df: DataFrame,
+    graph: DiGraph | None = None,
+    min_path_size: int = 3,
+    max_path_size: int = 6,
+    max_sampling_source: int = 10,
+    max_sampling_target: int = 10,
+    source: dict | None = None,
+    target: dict | None = None,
+    label_local: Text = LOCAL_LABEL,
+    simple_paths: bool = False,
+    inplace: bool = True
+) -> DataFrame:
+    """
+    Transition Graph Data Augmentation.
+
+    Performs the data increase from the transition graph.
 
     Parameters
     ----------
-    data : DataFrame
-        The input trajectories data
-    restriction : str, optional
-        Constraint used to generate new data, by default 'destination only'
-    label_trajectory : str, optional
-        Label of the points sequences, by default 'trajectory'
-    frac : number, optional
-        Represents the percentage to be exchanged, by default 0.5
+    traj_df: DataFrame
+        Trajectory data in sequence format
+    graph: DiGraph
+        Transition graph constructed from trajectory data
+    min_path_size: int, optional
+        Minimum number of points for the trajectory, by default 3
+    max_path_size: int, optional
+        Maximum number of points for the trajectory, by default 6
+    max_sampling_source: int, optional
+        Maximum number of paths to be returned,
+        considering the observed origin, by default 10
+    max_sampling_target: int, optional
+        Maximum number of paths to be returned,
+        considering the observed destination, by default 10
+    source: dict, optional
+        Degree of entry of each node in the graph, by default None
+        Example: {node: degree-of-entry}
+    target: dict, optional
+        Degree of output of each node in the graph, by default None
+        Example: {node: degree-of-output}
+    label_local: str, optional
+        Name of the column referring to the trajectories, by default LOCAL_LABEL
+    label_tid: str, optional
+        Column name for trajectory IDs, by default TID_STAT
+    simple_paths: boolean, optional
+        If true, use the paths with the most used sections
+        Otherwise, use paths with less used sections, by default False
+    inplace : boolean, optional
+        if set to true the original dataframe will be altered to contain the result
+        of the augmentation, otherwise a copy will be returned, by default True
+
+    Return
+    ------
+    DataFrame
+        Increased data set.
+
+    Example
+    -------
+    >>> from pymove.utils.data_augmentation import (
+            transition_graph_augmentation_all_vertex
+        )
+    >>>
+    >>> traj_df.to_dict()
+    {'id': [[1, 1, 1], [2, 2, 2, 2]],
+     'datetime': [['2017-09-02 22:00:27', '2017-09-02 22:01:36',
+                   '2017-09-02 22:03:08'],
+                  ['2017-09-02 23:03:46', '2017-09-02 23:07:19',
+                   '2017-09-02 23:07:40', '2017-09-02 23:09:10']],
+     'local_label': [[85, 673, 394], [263, 224, 623, 394]],
+     'lat': [[-3.8347478, -3.8235834, -3.813889],
+             [-3.9067654, -3.8857223, -3.8828723, -3.9939834]],
+     'lon': [[-38.592189, -38.590389, -38.5904445],
+             [-38.5907723, -38.5928892, -38.5929789, -38.70409]]}
+    >>>
+    >>> transition_graph_augmentation_all_vertex(traj_df)
+    [263.0, 224.0, 623.0]
+    [224.0, 623.0, 394.0]
 
     """
-    traj_df = generate_trajectories_df(data)
+    if inplace:
+        traj_df_ = traj_df
+    else:
+        traj_df_ = traj_df.copy()
 
-    generate_destiny_feature(traj_df, label_trajectory=label_trajectory)
+    if graph is None:
+        graph = build_transition_graph_from_df(traj_df_)
 
-    if restriction == 'departure and destination':
-        generate_start_feature(traj_df, label_trajectory=label_trajectory)
+    if source is None:
+        source = dict(graph.nodes)
+        source = {key: value['freq_source'] for key, value in source.items()}
 
-    aug_df = augmentation_trajectories_df(
-        traj_df, restriction=restriction, frac=frac
-    )
-    insert_points_in_df(data, aug_df)
+    if target is None:
+        target = dict(graph.nodes)
+        target = {key: value['freq_source'] for key, value in target.items()}
+
+    targets = sorted(target.items(), key=lambda x: x[1], reverse=True)
+    sources = sorted(source.items(), key=lambda x: x[1], reverse=True)
+
+    [[get_all_paths(
+        traj_df_, graph, s, t, min_path_size, max_path_size,
+        max_sampling_source, max_sampling_target, label_local, simple_paths
+    ) for s, _ in sources] for t, _ in targets]
+
+    if not inplace:
+        return traj_df_
diff --git a/pymove/utils/datetime.py b/pymove/utils/datetime.py
index 9ea32068..a45c699d 100644
--- a/pymove/utils/datetime.py
+++ b/pymove/utils/datetime.py
@@ -51,7 +51,7 @@ def date_to_str(dt: datetime) -> str:
     Parameters
     ----------
     dt : datetime
-        Represents a date
+        This represents a date
 
     Returns
     -------
@@ -177,7 +177,7 @@ def min_to_datetime(minutes: int) -> datetime:
     Parameters
     ----------
     minutes : int
-        Represents minutes
+        This represents a value in minutes
 
     Returns
     -------
diff --git a/pymove/utils/geoutils.py b/pymove/utils/geoutils.py
index c7c5086b..0ab9cd60 100644
--- a/pymove/utils/geoutils.py
+++ b/pymove/utils/geoutils.py
@@ -75,9 +75,9 @@ def _encode(lat: float, lon: float, precision: float = 15) -> str:
     Parameters
     ----------
     lat : float
-        Latitude in degrees.
+        This represents latitude in degrees.
     lon : float
-        Longitude in degrees.
+        This represents longitude in degrees.
     precision : float, optional
         Number of characters in resulting geohash, by default 15
 
@@ -135,9 +135,9 @@ def _bin_geohash(lat: float, lon: float, precision: float = 15) -> ndarray:
     Parameters
     ----------
     lat : float
-        Latitude in degrees
+        This represents latitude in degrees.
     lon : float
-        Longitude in degrees
+        This represents longitude in degrees.
     precision : float, optional
         Number of characters in resulting geohash, by default 15
 
diff --git a/pymove/utils/networkx.py b/pymove/utils/networkx.py
new file mode 100644
index 00000000..7759d125
--- /dev/null
+++ b/pymove/utils/networkx.py
@@ -0,0 +1,484 @@
+"""
+Graph operations.
+
+_populate_graph,
+build_transition_graph_from_dict,
+build_transition_graph_from_df,
+graph_to_dict,
+save_graph_as_json,
+read_graph_json
+
+"""
+
+from __future__ import annotations
+
+import json
+from pathlib import Path
+from typing import Dict, Text
+
+import networkx as nx
+import pandas as pd
+from networkx.classes.digraph import DiGraph
+from pandas.core.frame import DataFrame
+from pandas.core.series import Series
+
+from pymove.utils.constants import DATETIME, LATITUDE, LOCAL_LABEL, LONGITUDE
+from pymove.utils.log import progress_bar
+
+
+def _populate_graph(
+    row: Series, nodes: Dict, edges: Dict,
+    label_local: Text = LOCAL_LABEL
+):
+    """
+    Populate Transition Graph.
+
+    Insert the nodes and edges in the transition graph with all the
+    necessary attributes for the execution of the search and
+    recovery operations of paths / trajectories. The required
+    parameters are: latitude, longitude and datetime.
+
+    Parameters
+    ----------
+    row: Series
+        Line of the trajectory dataframe.
+    nodes: dict
+        Attributes of the transition graph nodes.
+    edges: dict
+        Attributes of the transition graph edges.
+    label_local: str, optional
+        Name of the column referring to the trajectories, by default LOCAL_LABEL
+
+    Example
+    -------
+    >>> from pymove.utils.networkx import _populate_graph
+    >>>
+    >>> trajectory
+    {"datetime": ["2017-09-02 22:00:27", "2017-09-02 22:01:36", "2017-09-02 22:03:08",
+                  "2017-09-02 22:03:46", "2017-09-02 22:07:19", "2017-09-02 22:07:40"],
+     "local_label": [85, 673, 394, 263, 224, 623],
+     "lat": [-3.8347478, -3.8235834, -3.813889, -3.9067654, -3.8857223, -3.8828723],
+     "lon": [-38.592189, -38.590389, -38.59044, -38.590772, -38.592889, -38.592978]}
+    >>>
+    >>> nodes = {'datetime': {}, 'coords': {}, 'freq_source': {}, 'freq_target': {}}
+    >>> edges = {}
+    >>>
+    >>> _populate_graph(pd.Series(trajectory), nodes, edges)
+    >>> nodes, edges
+    ({"datetime": { 85: ["2017-09-02 22:00:27"], 673: ["2017-09-02 22:01:36"],
+                394: ["2017-09-02 22:03:08"], 263: ["2017-09-02 22:03:46"],
+                224: ["2017-09-02 22:07:19"], 623: ["2017-09-02 22:07:40"]},
+      "coords": { 85: (-3.8347478, -38.592189), 673: (-3.8235834, -38.590389),
+                394: (-3.8138891, -38.590441), 263: (-3.9067654, -38.590772),
+                224: (-3.8857223, -38.592889), 623: (-3.8828723, -38.592978)},
+      "freq_source": {85: 1, 673: 0, 394: 0, 263: 0, 224: 0, 623: 0},
+      "freq_target": {85: 0, 673: 0, 394: 0, 263: 0, 224: 0, 623: 1}},
+     { 85: {673: {"weight": 1, "mean_times": "0 days 00:01:09"}},
+      673: {394: {"weight": 1, "mean_times": "0 days 00:01:32"}},
+      394: {263: {"weight": 1, "mean_times": "0 days 00:00:38"}},
+      263: {224: {"weight": 1, "mean_times": "0 days 00:03:33"}},
+      224: {623: {"weight": 1, "mean_times": "0 days 00:00:21"}}})
+
+    """
+    traj = row[label_local]
+
+    for index, local in enumerate(traj):
+
+        local_curr = str(local)
+
+        dt = [str(row[DATETIME][index])]
+        fs = (index == 0)
+        ft = (index == len(traj) - 1)
+
+        if local in nodes['datetime']:
+            dt.extend(nodes['datetime'][local_curr])
+            fs += nodes['freq_source'][local_curr]
+            ft += nodes['freq_target'][local_curr]
+
+        nodes['datetime'][local_curr] = dt
+        nodes['freq_source'][local_curr] = fs
+        nodes['freq_target'][local_curr] = ft
+        nodes['coords'][local_curr] = (row[LATITUDE][index], row[LONGITUDE][index])
+
+        if index == len(traj) - 1:
+            break
+
+        next_local = str(traj[index + 1])
+
+        weight = 1
+        mean_times = pd.Timestamp(
+            row[DATETIME][index + 1]
+        ) - pd.Timestamp(row[DATETIME][index])
+
+        if local_curr not in edges:
+            edges[local_curr] = {next_local: {}}
+            edges[local_curr][next_local] = {
+                'weight': 1,
+                'mean_times': str(mean_times)
+            }
+
+        elif next_local not in edges[local_curr]:
+            edges[local_curr] = {**edges[local_curr], **{next_local: {}}}
+            edges[local_curr][next_local] = {
+                'weight': 1,
+                'mean_times': str(mean_times)
+            }
+        else:
+            weight += edges[local_curr][next_local]['weight']
+            mean_times = (
+                mean_times + pd.Timedelta(edges[local_curr][next_local]['mean_times'])
+            ) / 2
+
+            edges[local_curr][next_local]['weight'] = weight
+            edges[local_curr][next_local]['mean_times'] = str(mean_times)
+
+
+def build_transition_graph_from_dict(dict_graph: Dict) -> DiGraph:
+    """
+    Built Graph from Dict.
+
+    It builds a transition graph from a dictionary
+    with nodes and edges and all necessary parameters.
+    Example: {'nodes': nodes, 'edges': edges}.
+
+    Parameters
+    ----------
+    dict_graph: dict
+        Dictionary with the attributes of nodes and edges.
+
+    Return
+    ------
+    graph: DiGraph
+        Transition graph constructed from trajectory data.
+
+    Example
+    -------
+    >>> from pymove.utils.networkx import build_transition_graph_from_dict
+    >>>
+    >>> dict_graph
+    {"nodes": {
+        "datetime": { 85: ["2017-09-02 22:00:27"], 673: ["2017-09-02 22:01:36"],
+                     394: ["2017-09-02 22:03:08"], 263: ["2017-09-02 22:03:46"],
+                     224: ["2017-09-02 22:07:19"], 623: ["2017-09-02 22:07:40"]},
+        "coords": { 85: (-3.8347478, -38.592189), 673: (-3.8235834, -38.590389),
+                   394: (-3.8138891, -38.590441), 263: (-3.9067654, -38.590772),
+                   224: (-3.8857223, -38.592889), 623: (-3.8828723, -38.592978)},
+        "freq_source": {85: 1, 673: 0, 394: 0, 263: 0, 224: 0, 623: 0},
+        "freq_target": {85: 0, 673: 0, 394: 0, 263: 0, 224: 0, 623: 1}},
+    "edges": { 85: {673: {"weight": 1, "mean_times": "0 days 00:01:09"}},
+              673: {394: {"weight": 1, "mean_times": "0 days 00:01:32"}},
+              394: {263: {"weight": 1, "mean_times": "0 days 00:00:38"}},
+              263: {224: {"weight": 1, "mean_times": "0 days 00:03:33"}},
+              224: {623: {"weight": 1, "mean_times": "0 days 00:00:21"}}}}
+    >>>
+    >>> graph = build_transition_graph_from_dict(dict_graph)
+    >>>
+    >>> graph.nodes
+    NodeView((85, 673, 394, 263, 224, 623))
+    >>>
+    >>> graph.edges
+    OutEdgeView([(85, 673), (673, 394), (394, 263), (263, 224), (224, 623)])
+    >>>
+    >>> graph.adj
+    AdjacencyView({ 85: {673: {'weight': 1, 'mean_times': '0 days 00:01:09'}},
+                   673: {394: {'weight': 1, 'mean_times': '0 days 00:01:32'}},
+                   394: {263: {'weight': 1, 'mean_times': '0 days 00:00:38'}},
+                   263: {224: {'weight': 1, 'mean_times': '0 days 00:03:33'}},
+                   224: {623: {'weight': 1, 'mean_times': '0 days 00:00:21'}},
+                   623: {}})
+
+    """
+    graph = nx.DiGraph(dict_graph['edges'])
+
+    for key in dict_graph['nodes']['coords']:
+        graph.add_node(key, coords=dict_graph['nodes']['coords'][key])
+        graph.add_node(key, datetime=dict_graph['nodes']['datetime'][key])
+        graph.add_node(key, freq_source=dict_graph['nodes']['freq_source'][key])
+        graph.add_node(key, freq_target=dict_graph['nodes']['freq_target'][key])
+
+    return graph
+
+
+def build_transition_graph_from_df(data: DataFrame) -> DiGraph:
+    """
+    Build Graph from data.
+
+    Constructs a Transition Graph from trajectory data.
+
+    Parameters
+    ----------
+    data: DataFrame
+        Trajectory data in sequence format.
+
+    Return
+    ------
+    graph: DiGraph
+        Transition graph constructed from trajectory data.
+
+    Example
+    -------
+    >>> from pymove.utils.networkx import build_transition_graph_from_df
+    >>>
+    >>> data
+    {"id": [[1, 1, 1], [2, 2, 2, 2]],
+     "datetime": [["2017-09-02 22:00:27", "2017-09-02 22:01:36",
+                   "2017-09-02 22:03:08"],
+                  ["2017-09-02 23:03:46", "2017-09-02 23:07:19",
+                   "2017-09-02 23:07:40", "2017-09-02 23:09:10"]],
+     "local_label": [[85, 673, 394], [263, 224, 623, 394]],
+     "lat": [[-3.8347478, -3.8235834, -3.8138890],
+             [-3.9067654, -3.8857223, -3.8828723, -3.9939834]],
+     "lon": [[-38.5921890, -38.5903890, -38.5904445],
+             [-38.5907723, -38.5928892, -38.5929789, -38.7040900]]}
+    >>>
+    >>> graph = build_transition_graph_from_df(pd.DataFrame(traj_df))
+    >>>
+    >>> graph.nodes
+    NodeView(('85', '673', '394', '263', '224', '623'))
+    >>>
+    >>> graph.edges
+    OutEdgeView([( '85', '673'), ('673', '394'), ('394', '263'),
+                 ('263', '224'), ('224', '623')])
+    >>>
+    >>> graph.adj
+    AdjacencyView({ '85': {'673': {'weight': 1, 'mean_times': '0 days 00:01:09'}},
+                   '673': {'394': {'weight': 1, 'mean_times': '0 days 00:01:32'}},
+                   '263': {'224': {'weight': 1, 'mean_times': '0 days 00:03:33'}},
+                   '224': {'623': {'weight': 1, 'mean_times': '0 days 00:00:21'}},
+                   '623': {'394': {'weight': 1, 'mean_times': '0 days 00:01:30'}},
+                   '394': {}})
+
+    """
+    nodes: dict = {'datetime': {}, 'coords': {}, 'freq_source': {}, 'freq_target': {}}
+    edges: dict = {}
+
+    desc = 'Building Transition Graph...'
+    for _, row in progress_bar(data.iterrows(), desc=desc, total=data.shape[0]):
+        _populate_graph(row, nodes, edges)
+
+    return build_transition_graph_from_dict(
+        {'nodes': nodes, 'edges': edges}
+    )
+
+
+def graph_to_dict(graph: DiGraph) -> Dict:
+    """
+    Graph to Dict.
+
+    Converts nodes and edges from the Transition Graph
+    with all your attributes in a dictionary.
+
+    Parameters
+    ----------
+    graph: DiGraph
+        Transition graph constructed from trajectory data.
+
+    Return
+    ------
+    dict
+        Dictionary with the attributes of nodes and edges.
+
+    Example
+    -------
+    >>> from pymove.utils.networkx import graph_to_dict
+    >>>
+    >>> graph = DiGraph()
+    >>> graph.add_node('85', coords=(-3.8347478, -38.592189),
+            datetime=['2017-09-02 22:00:27'], freq_source=1, freq_target=0)
+    >>> graph.add_node('673', coords=(-3.8235834, -38.590389),
+            datetime=['2017-09-02 22:01:36'], freq_source=0, freq_target=0)
+    >>> graph.add_node('394', coords=(-3.813889, -38.5904445),
+            datetime=['2017-09-02 22:03:08'], freq_source=0, freq_target=0)
+    >>> graph.add_node('263', coords=(-3.9067654, -38.5907723),
+            datetime=['2017-09-02 22:03:46'], freq_source=0, freq_target=0)
+    >>> graph.add_node('224', coords=(-3.8857223, -38.5928892),
+            datetime=['2017-09-02 22:07:19'], freq_source=0, freq_target=0)
+    >>> graph.add_node('623', coords=(-3.8828723, -38.5929789),
+            datetime=['2017-09-02 22:07:40'], freq_source=0, freq_target=1)
+    >>> graph.add_edge('85', '673', weight=1, mean_times='0 days 00:01:09')
+    >>> graph.add_edge('673', '394', weight=1, mean_times='0 days 00:01:09')
+    >>> graph.add_edge('394', '263', weight=1, mean_times='0 days 00:01:09')
+    >>> graph.add_edge('263', '224', weight=1, mean_times='0 days 00:01:09')
+    >>> graph.add_edge('224', '623', weight=1, mean_times='0 days 00:01:09')
+    >>>
+    >>> dict_graph = graph_to_dict(graph)
+    >>> dict_graph
+    {'nodes': {
+        'coords': { '85': (-3.8347478, -38.5921890), '673': (-3.8235834, -38.5903890),
+                   '394': (-3.8138890, -38.5904445), '263': (-3.9067654, -38.5907723),
+                   '224': (-3.8857223, -38.5928892), '623': (-3.8828723, -38.5929789)},
+        'datetime': { '85': ['2017-09-02 22:00:27'], '673': ['2017-09-02 22:01:36'],
+                     '394': ['2017-09-02 22:03:08'], '263': ['2017-09-02 22:03:46'],
+                     '224': ['2017-09-02 22:07:19'], '623': ['2017-09-02 22:07:40']},
+        'freq_source': {'85': 1, '673': 0, '394': 0, '263': 0, '224': 0, '623': 0},
+        'freq_target': {'85': 0, '673': 0, '394': 0, '263': 0, '224': 0, '623': 1}},
+     'edges': {
+         '85': {'673': {'weight': 1, 'mean_times': '0 days 00:01:09'}},
+        '673': {'394': {'weight': 1, 'mean_times': '0 days 00:01:32'}},
+        '394': {'263': {'weight': 1, 'mean_times': '0 days 00:00:38'}},
+        '263': {'224': {'weight': 1, 'mean_times': '0 days 00:03:33'}},
+        '224': {'623': {'weight': 1, 'mean_times': '0 days 00:00:21'}},
+        '623': {}}}
+    """
+    dict_graph: dict = {'nodes': {}, 'edges': {}}
+
+    dict_graph['nodes']['coords'] = nx.get_node_attributes(graph, 'coords')
+    dict_graph['nodes']['datetime'] = nx.get_node_attributes(graph, 'datetime')
+    dict_graph['nodes']['freq_source'] = nx.get_node_attributes(graph, 'freq_source')
+    dict_graph['nodes']['freq_target'] = nx.get_node_attributes(graph, 'freq_target')
+    dict_graph['edges'] = nx.to_dict_of_dicts(graph)
+
+    return dict_graph
+
+
+def save_graph_as_json(
+    graph: DiGraph,
+    file_path: Path | str = 'graph.json'
+):
+    """
+    Save Graph as JSON.
+
+    Saves the data extracted from the Transition Graph
+    into a JSON file.
+
+    Parameters
+    ----------
+    graph: DiGraph
+        Transition graph constructed from trajectory data.
+    file_path: str or path, optional
+        File name that will be saved with transition graph data, by default 'graph.json'.
+
+    Example
+    -------
+    >>> from pymove.utils.networkx import save_graph_as_json
+    >>>
+    >>> graph.nodes
+    NodeView(('85', '673', '394', '263', '224', '623'))
+    >>>
+    >>> graph.edges
+    OutEdgeView([
+        ('85', '673'), ('673', '394'), ('394', '263'), ('263', '224'), ('224', '623')
+    ])
+    >>>
+    >>> graph.adj
+    AdjacencyView({ '85': {'673': {'weight': 1, 'mean_times': '0 days 00:01:09'}},
+                   '673': {'394': {'weight': 1, 'mean_times': '0 days 00:01:32'}},
+                   '394': {'263': {'weight': 1, 'mean_times': '0 days 00:00:38'}},
+                   '263': {'224': {'weight': 1, 'mean_times': '0 days 00:03:33'}},
+                   '224': {'623': {'weight': 1, 'mean_times': '0 days 00:00:21'}},
+                   '623': {}})
+    >>>
+    >>> save_graph_as_json(graph, 'graph.json')
+    >>>
+    >>> with open('graph.json', 'r') as f:
+    >>>     lines = f.readlines()
+    >>>     print(lines)
+    ['{"nodes": {
+            "coords": {
+                "85": [-3.8347478, -38.592189], "673": [-3.8235834, -38.590389],
+                "394": [-3.813889, -38.5904445], "263": [-3.9067654, -38.5907723],
+                "224": [-3.8857223, -38.5928892], "623": [-3.8828723, -38.5929789]},
+            "datetime": {
+                "85": ["2017-09-02 22:00:27"], "673": ["2017-09-02 22:01:36"],
+                "394": ["2017-09-02 22:03:08"], "263": ["2017-09-02 22:03:46"],
+                "224": ["2017-09-02 22:07:19"], "623": ["2017-09-02 22:07:40"]},
+            "freq_source": {
+                "85": 1, "673": 0, "394": 0, "263": 0, "224": 0, "623": 0},
+            "freq_target": {
+                "85": 0, "673": 0, "394": 0, "263": 0, "224": 0, "623": 1}},
+       "edges": {
+             "85": {"673": {"weight": 1, "mean_times": "0 days 00:01:09"}},
+             "673": {"394": {"weight": 1, "mean_times": "0 days 00:01:32"}},
+             "394": {"263": {"weight": 1, "mean_times": "0 days 00:00:38"}},
+             "263": {"224": {"weight": 1, "mean_times": "0 days 00:03:33"}},
+             "224": {"623": {"weight": 1, "mean_times": "0 days 00:00:21"}},
+             "623": {}}}']
+    """
+    dict_graph = graph_to_dict(graph)
+
+    path = Path(file_path)
+
+    if path.suffix != '.json':
+        raise ValueError(
+            f'Unsupported file extension {path.suffix},'
+            f'Expected extension = json'
+        )
+
+    with open(path, 'w') as f:
+        json.dump(dict_graph, f)
+
+
+def read_graph_json(file_path: Path | str):
+    """
+    Read Graph from JSON file.
+
+    You load a Transition Graph from a file in JSON format.
+
+    Parameters
+    ----------
+    file_path: str or path
+        Name of the JSON file to be read
+
+    Return
+    ------
+    dict
+        Dictionary with the attributes of nodes and edges
+
+    Example
+    -------
+    >>> from pymove.utils.networkx import read_graph_json
+    >>>
+    >>> with open('graph.json', 'r') as f:
+    >>>     lines = f.readlines()
+    >>>     print(lines)
+    ['{"nodes": {
+            "coords": {
+                "85": [-3.8347478, -38.592189], "673": [-3.8235834, -38.590389],
+                "394": [-3.813889, -38.5904445], "263": [-3.9067654, -38.5907723],
+                "224": [-3.8857223, -38.5928892], "623": [-3.8828723, -38.5929789]},
+            "datetime": {
+                "85": ["2017-09-02 22:00:27"], "673": ["2017-09-02 22:01:36"],
+                "394": ["2017-09-02 22:03:08"], "263": ["2017-09-02 22:03:46"],
+                "224": ["2017-09-02 22:07:19"], "623": ["2017-09-02 22:07:40"]},
+             "freq_source": {
+                "85": 1, "673": 0, "394": 0, "263": 0, "224": 0, "623": 0},
+             "freq_target": {
+                "85": 0, "673": 0, "394": 0, "263": 0, "224": 0, "623": 1}},
+       "edges": {
+             "85": {"673": {"weight": 1, "mean_times": "0 days 00:01:09"}},
+             "673": {"394": {"weight": 1, "mean_times": "0 days 00:01:32"}},
+             "394": {"263": {"weight": 1, "mean_times": "0 days 00:00:38"}},
+             "263": {"224": {"weight": 1, "mean_times": "0 days 00:03:33"}},
+             "224": {"623": {"weight": 1, "mean_times": "0 days 00:00:21"}},
+             "623": {}}}']
+    >>>
+    >>> read_graph_json('graph.json')
+    {'nodes': {
+        'coords': {'85': [-3.8347478, -38.592189], '673': [-3.8235834, -38.590389],
+                   '394': [-3.813889, -38.5904445], '263': [-3.9067654, -38.5907723],
+                   '224': [-3.8857223, -38.5928892], '623': [-3.8828723, -38.5929789]},
+        'datetime': {'85': ['2017-09-02 22:00:27'], '673': ['2017-09-02 22:01:36'],
+                     '394': ['2017-09-02 22:03:08'], '263': ['2017-09-02 22:03:46'],
+                     '224': ['2017-09-02 22:07:19'], '623': ['2017-09-02 22:07:40']},
+        'freq_source': {'85': 1, '673': 0, '394': 0, '263': 0, '224': 0, '623': 0},
+        'freq_target': {'85': 0, '673': 0, '394': 0, '263': 0, '224': 0, '623': 1}},
+     'edges': {
+        '85': {'673': {'weight': 1, 'mean_times': '0 days 00:01:09'}},
+        '673': {'394': {'weight': 1, 'mean_times': '0 days 00:01:32'}},
+        '394': {'263': {'weight': 1, 'mean_times': '0 days 00:00:38'}},
+        '263': {'224': {'weight': 1, 'mean_times': '0 days 00:03:33'}},
+        '224': {'623': {'weight': 1, 'mean_times': '0 days 00:00:21'}},
+        '623': {}}}
+    """
+    path = Path(file_path)
+
+    if path.suffix != '.json':
+        raise ValueError(
+            f'Unsupported file extension {path.suffix},'
+            f'Expected extension = json'
+        )
+
+    with open(file_path, 'r') as f:
+        dict_graph = json.load(f)
+
+    return dict_graph
diff --git a/pymove/utils/trajectories.py b/pymove/utils/trajectories.py
index 5ccd621e..670ae13a 100644
--- a/pymove/utils/trajectories.py
+++ b/pymove/utils/trajectories.py
@@ -7,24 +7,36 @@
 flatten_columns,
 shift,
 fill_list_with_new_values,
+append_trajectory,
+split_trajectory,
 object_for_array,
 column_to_array
 
 """
 from __future__ import annotations
 
+from ast import literal_eval
 from itertools import chain
-from typing import Any
+from typing import Any, Generator, Text
 
 import numpy as np
+import pandas as pd
+from networkx.classes.digraph import DiGraph
 from numpy import ndarray
 from pandas import DataFrame, Series
 from pandas import read_csv as _read_csv
 from pandas._typing import FilePathOrBuffer
 
 from pymove.core.dataframe import MoveDataFrame
-from pymove.utils.constants import DATETIME, LATITUDE, LONGITUDE, TRAJ_ID, TYPE_PANDAS
-from pymove.utils.math import is_number
+from pymove.utils.constants import (
+    DATETIME,
+    LATITUDE,
+    LOCAL_LABEL,
+    LONGITUDE,
+    TRAJ_ID,
+    TYPE_PANDAS,
+)
+from pymove.utils.networkx import graph_to_dict
 
 
 def read_csv(
@@ -314,13 +326,152 @@ def fill_list_with_new_values(original_list: list, new_list_values: list):
     original_list[:n] = new_list_values
 
 
+def append_trajectory(
+    data: DataFrame,
+    trajectory: list,
+    graph: DiGraph
+):
+    """
+    Inserts a trajectory in the data set.
+
+    Inserts the trajectory retrieved from the
+    transition graph in the trajectory data set.
+
+    Parameters
+    ----------
+    data: DataFrame
+        Trajectory data in sequence format
+    trajectory: list
+        Trajectory recovered from the transition graph
+    graph: DiGraph
+        Transition graph constructed from trajectory data
+
+    Example
+    -------
+    >>> from pymove.utils.data_augmentation import append_trajectory
+    >>>
+    >>> traj_df.to_dict()
+    {'id': [[1, 1, 1], [2, 2, 2, 2]],
+     'datetime': [['2017-09-02 22:00:27', '2017-09-02 22:01:36',
+                  '2017-09-02 22:03:08'],
+                 ['2017-09-02 23:03:46', '2017-09-02 23:07:19',
+                  '2017-09-02 23:07:40', '2017-09-02 23:09:10']],
+     'local_label': [[85, 673, 394], [263, 224, 623, 394]],
+     'lat': [[-3.8347478, -3.8235834, -3.813889],
+            [-3.9067654, -3.8857223, -3.8828723, -3.9939834]],
+     'lon': [[-38.592189, -38.590389, -38.5904445],
+            [-38.5907723, -38.5928892, -38.5929789, -38.70409]]}
+    >>>
+    >>> trajectory = [263, 224, 623]
+    >>> graph = build_transition_graph_from_df(traj_df)
+    >>>
+    >>> append_trajectory(traj_df, trajectory, graph)
+    >>> traj_df.iloc[-1]
+    id                                                              [3, 3, 3]
+    datetime  [2017-09-02 23:03:46, 2017-09-02 23:07:19, 2017-09-02 23:07:40]
+    local_label                                               [263, 224, 623]
+    lat                                  [-3.9067654, -3.8857223, -3.8828723]
+    lon                               [-38.5907723, -38.5928892, -38.5929789]
+    Name: 2, dtype: object
+
+    """
+    source = str(trajectory[0])
+    dict_graph = graph_to_dict(graph)
+
+    dt = np.random.choice(dict_graph['nodes']['datetime'][source])
+    datetimes = [pd.Timestamp(str(dt))]
+
+    coords = dict_graph['nodes']['coords']
+    lats, lons = [coords[source][0]], [coords[source][1]]
+
+    for idx, edge in enumerate(zip(trajectory[:-1], trajectory[1:])):
+        u, v = str(edge[0]), str(edge[1])
+        mean_times = dict_graph['edges'][u][v]['mean_times']
+
+        datetime = pd.Timestamp(str(datetimes[idx])) + pd.Timedelta(mean_times)
+        datetimes.append(datetime)
+
+        lats.append(coords[v][0])
+        lons.append(coords[v][1])
+
+    prev_id = data.loc[data.shape[0] - 1, TRAJ_ID][0]
+    ids = np.full(len(trajectory), prev_id + 1, dtype=np.int32).tolist()
+
+    path = np.array(trajectory, dtype=np.float32).tolist()
+
+    data.loc[data.shape[0], [
+        DATETIME, TRAJ_ID, LOCAL_LABEL, LATITUDE, LONGITUDE
+    ]] = [datetimes, ids, path, lats, lons]
+
+
+def split_trajectory(
+    row: Series,
+    size_window: int = 6,
+    size_jump: int = 3,
+    label_local: Text = LOCAL_LABEL,
+    columns: list = None
+) -> Generator[Series, None, None]:
+    """
+    It breaks the trajectory in stretches.
+
+    Extracts all possible sub-trajectories, according to the specified
+    window size and jump.
+
+    Parameters
+    ----------
+    row: Series
+        Line of the trajectory dataframe
+    size_window: int, optional
+        Sliding window size, by default 6
+    size_jump: int, optional
+        Size of the jump in the trajectory, by default 3
+    label_local: str, optional
+        Name of the column referring to the trajectories, by default LOCAL_LABEL
+    columns: list, optional
+        Columns to which the split will be applied, by default None
+
+    Return
+    ------
+    Generator of Series
+        Series with the stretches recovered from the observed trajectory.
+
+    Example
+    -------
+    >>> from pymove.utils.trajectories import split_trajectories
+    >>>
+    >>> trajectory
+    id                           [1, 1, 1, 1, 1, 1, 1, 1]
+    local_label    [85, 673, 394, 85, 224, 623, 394, 263]
+    dtype: object
+    >>>
+    >>> split = split_trajectory(trajectory, size_jump=1)
+    >>> split
+
+                        id 	                  local_label
+    0   [1, 1, 1, 1, 1, 1]  [ 85, 673, 394, 85, 224, 623]
+    1   [1, 1, 1, 1, 1, 1]  [673, 394, 85, 224, 623, 394]
+    2   [1, 1, 1, 1, 1, 1]  [394, 85, 224, 623, 394, 263]
+
+    """
+    if columns is None:
+        columns = row.index
+
+    size_t = len(row[label_local])
+
+    return pd.concat([
+        pd.Series(
+            {col: row[col][i:i + size_window] for col in columns}
+        ) for i in range(0, size_t, size_jump) if (size_t - i) > size_window - 1
+    ], axis=1).T
+
+
 def object_for_array(object_: str) -> ndarray:
     """
     Transforms an object into an array.
 
     Parameters
     ----------
-    object : str
+    object_ : str
         object representing a list of integers or strings
 
     Returns
@@ -328,64 +479,61 @@ def object_for_array(object_: str) -> ndarray:
     array
         object converted to a list
 
-    Examples
-    --------
+    Example
+    -------
     >>> from pymove.utils.trajectories import object_for_array
-    >>> list_str = '[1,2,3,4,5]'
-    >>> object_for_array(list_str)
-    array([1., 2., 3., 4., 5.], dtype=float32)
+    >>>
+    >>> object_1, object_2, object_3
+    ('[1, 2, 3]', '[1.5, 2.5, 3.5]', "['event', 'event']")
+    >>>
+    >>> object_for_array(object_1)
+    [1, 2, 3]
+    >>> object_for_array(object_2)
+    [1.5, 2.5, 3.5]
+    >>> object_for_array(object_3)
+    ['event', 'event'   ]
     """
     if object_ is None:
         return object_
 
-    conv = np.array([*map(str.strip, object_[1:-1].split(','))])
-
-    if is_number(conv[0]):
-        return conv.astype(np.float32)
-    else:
-        return conv.astype('object_')
+    return literal_eval('[' + object_ + ']')[0]
 
 
-def column_to_array(data: DataFrame, column: str) -> DataFrame:
+def columns_to_array(
+    traj_df: DataFrame,
+    columns: list | None = None
+):
     """
     Transforms all columns values to list.
 
     Parameters
     ----------
-    data : dataframe
-        The input trajectory data
-
-    column : str
-        Label of data referring to the column for conversion
-
-    Returns
-    -------
-    dataframe
-        Dataframe with the selected column converted to list
+    traj_df : DataFrame
+        The input trajectory data.
+    columns : list, optional
+        List of the columns for conversion.
 
     Example
     -------
-    >>> from pymove.utils.trajectories import column_to_array
-    >>> move_df
-              lat          lon              datetime  id   list_column
-    0   39.984094   116.319236   2008-10-23 05:53:05   1        '[1,2]'
-    1   39.984198   116.319322   2008-10-23 05:53:06   1        '[3,4]'
-    2   39.984224   116.319402   2008-10-23 05:53:11   1        '[5,6]'
-    3   39.984211   116.319389   2008-10-23 05:53:16   1        '[7,8]'
-    4   39.984217   116.319422   2008-10-23 05:53:21   1       '[9,10]'
-    >>> column_to_array(move_df, column='list_column')
-              lat          lon              datetime  id    list_column
-    0   39.984094   116.319236   2008-10-23 05:53:05   1      [1.0,2.0]
-    1   39.984198   116.319322   2008-10-23 05:53:06   1      [3.0,4.0]
-    2   39.984224   116.319402   2008-10-23 05:53:11   1      [5.0,6.0]
-    3   39.984211   116.319389   2008-10-23 05:53:16   1      [7.0,8.0]
-    4   39.984217   116.319422   2008-10-23 05:53:21   1     [9.0,10.0]
+    >>> from pymove.utils.trajectories import columns_to_array
+    >>>
+    >>> traj_df
+                  ids                     descritions                   price
+    0     '[1, 1, 1]'   "['event', 'event', 'event']"    '[10.5, 20.5, 13.5]'
+    1     '[2, 2, 2]'      "['bike', 'bike', 'bike']"    '[50.2, 33.4, 90.0]'
+    2  '[3, 3, 3, 3]'  "['car', 'car', 'car', 'car']"  '[1.0, 2.9, 3.4, 8.4]'
+    3        '[4, 4]'            "['house', 'house']"        '[100.4, 150.5]'
+    >>>
+    >>> columns_to_array(traj_df)
+    >>> traj_df
+                ids            descritions                 price
+    0     [1, 1, 1]  [event, event, event]    [10.5, 20.5, 13.5]
+    1     [2, 2, 2]     [bike, bike, bike]    [50.2, 33.4, 90.0]
+    2  [3, 3, 3, 3]   [car, car, car, car]  [1.0, 2.9, 3.4, 8.4]
+    3        [4, 4]         [house, house]        [100.4, 150.5]
     """
-    data = data.copy()
-    if column not in data:
-        raise KeyError(
-            'Dataframe must contain a %s column' % column
-        )
+    if columns is None:
+        columns = list(traj_df.columns)
 
-    data[column] = data[column].apply(object_for_array)
-    return data
+    f = {col: object_for_array for col in columns}
+    traj_df[columns] = traj_df[columns].agg(f)
diff --git a/requirements.txt b/requirements.txt
index ebe72608..d0897edc 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,8 +9,9 @@ ipywidgets
 joblib
 matplotlib
 mplleaflet
+networkx
 numpy
-pandas>=1.1.0
+pandas>=1.1.0,<1.4.0
 psutil
 python-dateutil
 pytz
diff --git a/setup.cfg b/setup.cfg
index 648286f1..9b591194 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 3.0.0
+current_version = 3.0.1
 tag_name = {new_version}
 commit = True
 
@@ -12,7 +12,17 @@ ignore = E203, E266, W402, W503, F401, F841, D401
 max-line-length = 90
 max-complexity = 15
 select = B,C,E,D,N,F,W
-exclude = pymove/core/interface.py, pymove/tests/*
+exclude =
+	.git,
+	__pycache__,
+	*.egg-info,
+	.venv/*,
+	venv/*,
+	.env/*,
+	env/*,
+	*.egg.info,
+	pymove/core/interface.py,
+	pymove/tests/*
 docstring-convention = numpy
 
 [mypy]
@@ -25,7 +35,7 @@ files = pymove
 multi_line_output = 3
 include_trailing_comma = True
 line_length = 90
-known_third_party = IPython,branca,dask,dateutil,folium,geohash2,holidays,ipywidgets,joblib,matplotlib,numpy,pandas,psutil,scipy,setuptools,shapely,sklearn,tqdm
+known_third_party = IPython,branca,dask,dateutil,folium,geohash2,holidays,ipywidgets,joblib,matplotlib,networkx,numpy,pandas,psutil,scipy,setuptools,shapely,sklearn,tqdm
 
 [tool:pytest]
 addopts =
diff --git a/setup.py b/setup.py
index afbd4b53..2ceccd9f 100644
--- a/setup.py
+++ b/setup.py
@@ -10,7 +10,7 @@
 
 setup(
     name='pymove',
-    version='3.0.0',
+    version='3.0.1',
     author='Insight Data Science Lab',
     author_email='insightlab@dc.ufc.br',
     license='MIT',


Test patch:
diff --git a/pymove/tests/test_query.py b/pymove/tests/test_query.py
index 06de99fb..4fe83b73 100644
--- a/pymove/tests/test_query.py
+++ b/pymove/tests/test_query.py
@@ -1,4 +1,6 @@
-from pandas import DataFrame, Timestamp
+from datetime import timedelta
+
+from pandas import DataFrame, Timedelta, Timestamp
 from pandas.testing import assert_frame_equal
 
 from pymove import MoveDataFrame
@@ -281,6 +283,182 @@
                           [13.5, -61.4, Timestamp('2012-08-12 00:00:00'),
                           '             HELENE']]
 
+expected__datetime_filter = [[11.6, -46.7, Timestamp('2012-08-01 12:00:00'),
+                             '            ERNESTO', Timedelta('801 days 06:00:00'),
+                             '            GONZALO', 16.4, -54.9,
+                             Timestamp('2014-10-11 18:00:00')],
+                             [12.0, -48.2, Timestamp('2012-08-01 18:00:00'),
+                             '            ERNESTO', Timedelta('801 days 00:00:00'),
+                             '            GONZALO', 16.4, -54.9,
+                             Timestamp('2014-10-11 18:00:00')],
+                             [12.4, -49.9, Timestamp('2012-08-02 00:00:00'),
+                             '            ERNESTO', Timedelta('800 days 18:00:00'),
+                             '            GONZALO', 16.4, -54.9,
+                             Timestamp('2014-10-11 18:00:00')],
+                             [12.7, -51.7, Timestamp('2012-08-02 06:00:00'),
+                             '            ERNESTO', Timedelta('800 days 12:00:00'),
+                             '            GONZALO', 16.4, -54.9,
+                             Timestamp('2014-10-11 18:00:00')],
+                             [13.0, -53.6, Timestamp('2012-08-02 12:00:00'),
+                             '            ERNESTO', Timedelta('800 days 06:00:00'),
+                             '            GONZALO', 16.4, -54.9,
+                             Timestamp('2014-10-11 18:00:00')],
+                             [13.2, -55.5, Timestamp('2012-08-02 18:00:00'),
+                             '            ERNESTO', Timedelta('800 days 00:00:00'),
+                             '            GONZALO', 16.4, -54.9,
+                             Timestamp('2014-10-11 18:00:00')],
+                             [13.4, -57.5, Timestamp('2012-08-03 00:00:00'),
+                             '            ERNESTO', Timedelta('799 days 18:00:00'),
+                             '            GONZALO', 16.4, -54.9,
+                             Timestamp('2014-10-11 18:00:00')],
+                             [13.6, -59.7, Timestamp('2012-08-03 06:00:00'),
+                             '            ERNESTO', Timedelta('799 days 12:00:00'),
+                             '            GONZALO', 16.4, -54.9,
+                             Timestamp('2014-10-11 18:00:00')],
+                             [13.7, -61.6, Timestamp('2012-08-03 12:00:00'),
+                             '            ERNESTO', Timedelta('799 days 06:00:00'),
+                             '            GONZALO', 16.4, -54.9,
+                             Timestamp('2014-10-11 18:00:00')],
+                             [13.8, -63.3, Timestamp('2012-08-03 18:00:00'),
+                             '            ERNESTO', Timedelta('799 days 00:00:00'),
+                             '            GONZALO', 16.4, -54.9,
+                             Timestamp('2014-10-11 18:00:00')],
+                             [13.6, -44.6, Timestamp('2012-08-10 00:00:00'),
+                             '             HELENE', Timedelta('792 days 18:00:00'),
+                             '            GONZALO', 16.4, -54.9,
+                             Timestamp('2014-10-11 18:00:00')],
+                             [13.5, -46.3, Timestamp('2012-08-10 06:00:00'),
+                             '             HELENE', Timedelta('792 days 12:00:00'),
+                             '            GONZALO', 16.4, -54.9,
+                             Timestamp('2014-10-11 18:00:00')],
+                             [13.4, -48.2, Timestamp('2012-08-10 12:00:00'),
+                             '             HELENE', Timedelta('792 days 06:00:00'),
+                             '            GONZALO', 16.4, -54.9,
+                             Timestamp('2014-10-11 18:00:00')],
+                             [13.4, -50.5, Timestamp('2012-08-10 18:00:00'),
+                             '             HELENE', Timedelta('792 days 00:00:00'),
+                             '            GONZALO', 16.4, -54.9,
+                             Timestamp('2014-10-11 18:00:00')],
+                             [13.4, -52.9, Timestamp('2012-08-11 00:00:00'),
+                             '             HELENE', Timedelta('791 days 18:00:00'),
+                             '            GONZALO', 16.4, -54.9,
+                             Timestamp('2014-10-11 18:00:00')],
+                             [13.4, -55.4, Timestamp('2012-08-11 06:00:00'),
+                             '             HELENE', Timedelta('791 days 12:00:00'),
+                             '            GONZALO', 16.4, -54.9,
+                             Timestamp('2014-10-11 18:00:00')],
+                             [13.3, -57.9, Timestamp('2012-08-11 12:00:00'),
+                             '             HELENE', Timedelta('791 days 06:00:00'),
+                             '            GONZALO', 16.4, -54.9,
+                             Timestamp('2014-10-11 18:00:00')],
+                             [13.3, -59.9, Timestamp('2012-08-11 18:00:00'),
+                             '             HELENE', Timedelta('791 days 00:00:00'),
+                             '            GONZALO', 16.4, -54.9,
+                             Timestamp('2014-10-11 18:00:00')],
+                             [13.5, -61.4, Timestamp('2012-08-12 00:00:00'),
+                             '             HELENE', Timedelta('790 days 18:00:00'),
+                             '            GONZALO', 16.4, -54.9,
+                             Timestamp('2014-10-11 18:00:00')]]
+
+expected__meters_filter = [[11.6, -46.7, Timestamp('2012-08-01 12:00:00'),
+                           '            ERNESTO', 1066161.6471417674, '            GONZALO',
+                           16.4, -54.9, Timestamp('2014-10-11 18:00:00')],
+                           [12.0, -48.2, Timestamp('2012-08-01 18:00:00'),
+                           '            ERNESTO', 900938.714887712, '            GONZALO',
+                           16.4, -54.9, Timestamp('2014-10-11 18:00:00')],
+                           [12.4, -49.9, Timestamp('2012-08-02 00:00:00'),
+                           '            ERNESTO', 721970.410639291, '            GONZALO',
+                           16.4, -54.9, Timestamp('2014-10-11 18:00:00')],
+                           [12.7, -51.7, Timestamp('2012-08-02 06:00:00'),
+                           '            ERNESTO', 555014.4613063192, '            GONZALO',
+                           16.4, -54.9, Timestamp('2014-10-11 18:00:00')],
+                           [13.0, -53.6, Timestamp('2012-08-02 12:00:00'),
+                           '            ERNESTO', 417258.69534832065, '            GONZALO',
+                           16.4, -54.9, Timestamp('2014-10-11 18:00:00')],
+                           [13.2, -55.5, Timestamp('2012-08-02 18:00:00'),
+                           '            ERNESTO', 374504.9191824335, '            GONZALO',
+                           16.4, -54.9, Timestamp('2014-10-11 18:00:00')],
+                           [13.4, -57.5, Timestamp('2012-08-03 00:00:00'),
+                           '            ERNESTO', 450805.43534718483, '            GONZALO',
+                           16.4, -54.9, Timestamp('2014-10-11 18:00:00')],
+                           [13.6, -59.7, Timestamp('2012-08-03 06:00:00'),
+                           '            ERNESTO', 624231.4229153295, '            GONZALO',
+                           16.4, -54.9, Timestamp('2014-10-11 18:00:00')],
+                           [13.7, -61.6, Timestamp('2012-08-03 12:00:00'),
+                           '            ERNESTO', 808188.0577929622, '            GONZALO',
+                           16.4, -54.9, Timestamp('2014-10-11 18:00:00')],
+                           [13.8, -63.3, Timestamp('2012-08-03 18:00:00'),
+                           '            ERNESTO', 981971.5317471786, '            GONZALO',
+                           16.4, -54.9, Timestamp('2014-10-11 18:00:00')],
+                           [13.6, -44.6, Timestamp('2012-08-10 00:00:00'),
+                           '             HELENE', 1191143.517942208, '            GONZALO',
+                           16.4, -54.9, Timestamp('2014-10-11 18:00:00')],
+                           [13.5, -46.3, Timestamp('2012-08-10 06:00:00'),
+                           '             HELENE', 1013996.5382597771, '            GONZALO',
+                           16.4, -54.9, Timestamp('2014-10-11 18:00:00')],
+                           [13.4, -48.2, Timestamp('2012-08-10 12:00:00'),
+                           '             HELENE', 822030.1743065921, '            GONZALO',
+                           16.4, -54.9, Timestamp('2014-10-11 18:00:00')],
+                           [13.4, -50.5, Timestamp('2012-08-10 18:00:00'),
+                           '             HELENE', 599470.6884598556, '            GONZALO',
+                           16.4, -54.9, Timestamp('2014-10-11 18:00:00')],
+                           [13.4, -52.9, Timestamp('2012-08-11 00:00:00'),
+                           '             HELENE', 411124.72610444814, '            GONZALO',
+                           16.4, -54.9, Timestamp('2014-10-11 18:00:00')],
+                           [13.4, -55.4, Timestamp('2012-08-11 06:00:00'),
+                           '             HELENE', 350076.3224643749, '            GONZALO',
+                           16.4, -54.9, Timestamp('2014-10-11 18:00:00')],
+                           [13.3, -57.9, Timestamp('2012-08-11 12:00:00'),
+                           '             HELENE', 488900.00555183407, '            GONZALO',
+                           16.4, -54.9, Timestamp('2014-10-11 18:00:00')],
+                           [13.3, -59.9, Timestamp('2012-08-11 18:00:00'),
+                           '             HELENE', 661283.3582634325, '            GONZALO',
+                           16.4, -54.9, Timestamp('2014-10-11 18:00:00')],
+                           [13.5, -61.4, Timestamp('2012-08-12 00:00:00'),
+                           '             HELENE', 797018.0293108114, '            GONZALO',
+                           16.4, -54.9, Timestamp('2014-10-11 18:00:00')]]
+
+expected_query_all_points_by_range = [[13.5, -61.4, Timestamp('2012-08-12 00:00:00'),
+                                      '             HELENE', 513299.9786988872, '            GONZALO',
+                                      16.4, -57.9, Timestamp('2014-10-12 12:00:00'),
+                                      Timedelta('791 days 12:00:00')],
+                                      [13.3, -59.9, Timestamp('2012-08-11 18:00:00'),
+                                      '             HELENE', 488900.0055518347, '            GONZALO',
+                                      16.4, -56.9, Timestamp('2014-10-12 06:00:00'),
+                                      Timedelta('791 days 12:00:00')],
+                                      [13.5, -61.4, Timestamp('2012-08-12 00:00:00'),
+                                      '             HELENE', 602173.6463646247, '            GONZALO',
+                                      16.4, -56.9, Timestamp('2014-10-12 06:00:00'),
+                                      Timedelta('791 days 06:00:00')],
+                                      [13.3, -57.9, Timestamp('2012-08-11 12:00:00'),
+                                      '             HELENE', 420788.62897684716, '            GONZALO',
+                                      16.4, -55.9, Timestamp('2014-10-12 00:00:00'),
+                                      Timedelta('791 days 12:00:00')],
+                                      [13.3, -59.9, Timestamp('2012-08-11 18:00:00'),
+                                      '             HELENE', 570760.3863635769, '            GONZALO',
+                                      16.4, -55.9, Timestamp('2014-10-12 00:00:00'),
+                                      Timedelta('791 days 06:00:00')],
+                                      [13.5, -61.4, Timestamp('2012-08-12 00:00:00'),
+                                      '             HELENE', 697519.455413829, '            GONZALO',
+                                      16.4, -55.9, Timestamp('2014-10-12 00:00:00'),
+                                      Timedelta('791 days 00:00:00')],
+                                      [13.4, -55.4, Timestamp('2012-08-11 06:00:00'),
+                                      '             HELENE', 350076.3224643749, '            GONZALO',
+                                      16.4, -54.9, Timestamp('2014-10-11 18:00:00'),
+                                      Timedelta('791 days 12:00:00')],
+                                      [13.3, -57.9, Timestamp('2012-08-11 12:00:00'),
+                                      '             HELENE', 488900.00555183407, '            GONZALO',
+                                      16.4, -54.9, Timestamp('2014-10-11 18:00:00'),
+                                      Timedelta('791 days 06:00:00')],
+                                      [13.3, -59.9, Timestamp('2012-08-11 18:00:00'),
+                                      '             HELENE', 661283.3582634325, '            GONZALO',
+                                      16.4, -54.9, Timestamp('2014-10-11 18:00:00'),
+                                      Timedelta('791 days 00:00:00')],
+                                      [13.5, -61.4, Timestamp('2012-08-12 00:00:00'),
+                                      '             HELENE', 797018.0293108114, '            GONZALO',
+                                      16.4, -54.9, Timestamp('2014-10-11 18:00:00'),
+                                      Timedelta('790 days 18:00:00')]]
+
 
 def _default_traj_df(data=None):
     if data is None:
@@ -348,3 +526,48 @@ def test_knn_query():
 
     medt_move_df = query.knn_query(traj_df, move_df, k=2, distance='MEDT')
     assert_frame_equal(medt_move_df, expected_medt)
+
+def test__datetime_filter():
+    traj_df = _default_traj_df()
+    firstpoint = traj_df.iloc[0]
+    move_df = _default_move_df()
+    expected = DataFrame(
+        data=expected__datetime_filter,
+        columns=['lat', 'lon', 'datetime', 'id', 'temporal_distance', 'target_id',
+                 'target_lat', 'target_lon', 'target_datetime'],
+        index=[20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+               37, 38]
+    )
+
+    result = query._datetime_filter(firstpoint, move_df, timedelta(hours=20000))
+    assert_frame_equal(result, expected)
+
+
+def test__meters_filter():
+    traj_df = _default_traj_df()
+    firstpoint = traj_df.iloc[0]
+    move_df = _default_move_df()
+    expected = DataFrame(
+        data=expected__meters_filter,
+        columns=['lat', 'lon', 'datetime', 'id', 'spatial_distance', 'target_id',
+                 'target_lat', 'target_lon', 'target_datetime'],
+        index=[20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+               37, 38]
+    )
+
+    result = query._meters_filter(firstpoint, move_df, 2000000)
+    assert_frame_equal(result, expected)
+
+
+def test_query_all_points_by_range():
+    traj_df = _default_traj_df();
+    move_df = _default_move_df();
+    expected = DataFrame(
+        data=expected_query_all_points_by_range,
+        columns=['lat', 'lon', 'datetime', 'id', 'spatial_distance', 'target_id',
+                'target_lat', 'target_lon', 'target_datetime', 'temporal_distance'],
+        index=[38, 37, 38, 36, 37, 38, 35, 36, 37, 38]
+    )
+
+    result = query.query_all_points_by_range(traj_df, move_df, minimum_meters=1900000, minimum_time=timedelta(hours=19000))
+    assert_frame_equal(result, expected)
diff --git a/pymove/tests/test_utils_data_augmentation.py b/pymove/tests/test_utils_data_augmentation.py
index 9e99af15..648ac29e 100644
--- a/pymove/tests/test_utils_data_augmentation.py
+++ b/pymove/tests/test_utils_data_augmentation.py
@@ -1,4 +1,3 @@
-import numpy as np
 import pandas as pd
 from numpy.testing import assert_array_almost_equal
 from pandas.testing import assert_frame_equal
@@ -10,132 +9,152 @@
     LATITUDE,
     LOCAL_LABEL,
     LONGITUDE,
+    PREV_LOCAL,
     START,
     TID,
+    TID_STAT,
     TRAJ_ID,
 )
 from pymove.utils.data_augmentation import (
     _augmentation,
     append_row,
-    augmentation_trajectories_df,
-    generate_destiny_feature,
-    generate_start_feature,
-    insert_points_in_df,
+    flatten_trajectories_dataframe,
+    generate_trajectories_df,
+    get_all_paths,
     instance_crossover_augmentation,
+    sliding_window,
     split_crossover,
+    transition_graph_augmentation_all_vertex,
 )
+from pymove.utils.networkx import build_transition_graph_from_df
 
-list_data1 = [['abc-0000', 1, 3.1234567, 38.1234567,
-               pd.Timestamp('2020-01-01 06:08:15'), 'abc-00002020010106'],
-              ['abc-0000', 2, 3.1234567, 38.1234567,
-               pd.Timestamp('2020-01-01 06:16:51'), 'abc-00002020010106'],
-              ['abc-0000', 3, 3.1234567, 38.1234567,
-               pd.Timestamp('2020-01-01 06:31:41'), 'abc-00002020010106'],
-              ['abc-0000', 4, 3.1234567, 38.1234567,
-               pd.Timestamp('2020-01-01 06:45:25'), 'abc-00002020010106'],
-              ['abc-0000', 9, 3.1234567, 38.1234567,
-               pd.Timestamp('2020-01-01 06:49:18'), 'abc-00002020010106'],
-              ['def-1111', 5, 3.1234567, 38.1234567,
-               pd.Timestamp('2020-01-01 09:10:15'), 'def-11112020010109'],
-              ['def-1111', 6, 3.1234567, 38.1234567,
-               pd.Timestamp('2020-01-01 09:15:45'), 'def-11112020010109'],
-              ['def-1111', 7, 3.1234567, 38.1234567,
-               pd.Timestamp('2020-01-01 09:25:34'), 'def-11112020010109'],
-              ['def-1111', 8, 3.1234567, 38.1234567,
-               pd.Timestamp('2020-01-01 09:40:25'), 'def-11112020010109'],
-              ['def-1111', 9, 3.1234567, 38.1234567,
-               pd.Timestamp('2020-01-01 09:52:53'), 'def-11112020010109']]
+list_data1 = [[1, pd.Timestamp('2017-09-02 21:59:34'), 162, -3.8431323, -38.5933142, '12017090221'],
+              [1, pd.Timestamp('2017-09-02 22:00:27'),  85, -3.8347478, -38.5921890, '12017090222'],
+              [1, pd.Timestamp('2017-09-02 22:01:36'), 673, -3.8235834, -38.5903890, '12017090222'],
+              [1, pd.Timestamp('2017-09-02 22:03:08'), 394, -3.8138890, -38.5904445, '12017090222'],
+              [1, pd.Timestamp('2017-09-02 22:03:46'), 263, -3.9067654, -38.5907723, '12017090222'],
+              [1, pd.Timestamp('2017-09-02 22:07:19'), 224, -3.8857223, -38.5928892, '12017090222'],
+              [1, pd.Timestamp('2017-09-02 22:07:40'), 623, -3.8828723, -38.5929789, '12017090222']]
 
 list_data2 = {
-    TRAJ_ID: ['abc-0000', 'def-1111'],
-    LOCAL_LABEL: [[5, 7, 9], [2, 4, 6, 8, 9]],
-    DATETIME: [[pd.Timestamp('2020-01-01 06:08:15'),
-                pd.Timestamp('2020-01-01 06:16:51'),
-                pd.Timestamp('2020-01-01 06:20:40')],
-               [pd.Timestamp('2020-01-01 09:10:15'),
-                pd.Timestamp('2020-01-01 09:15:45'),
-                pd.Timestamp('2020-01-01 09:25:30'),
-                pd.Timestamp('2020-01-01 09:30:17'),
-                pd.Timestamp('2020-01-01 09:45:16')]],
-    LATITUDE: [[3.1234567165374756, 3.1234567165374756,
-                3.1234567165374756],
-               [3.1234567165374756, 3.1234567165374756,
-                3.1234567165374756, 3.1234567165374756,
-                3.1234567165374756]],
-    LONGITUDE: [[38.12345504760742, 38.12345504760742,
-                 38.12345504760742],
-                [38.12345504760742, 38.12345504760742,
-                 38.12345504760742, 38.12345504760742,
-                 38.12345504760742]],
-    TID: [['abc-00002020010106', 'abc-00002020010106',
-           'abc-00002020010106'],
-          ['def-11112020010109', 'def-11112020010109',
-           'abc-00002020010106', 'abc-00002020010106',
-           'abc-00002020010106']]}
+    TRAJ_ID: [[1, 1, 1, 1, 1, 1]],
+    DATETIME: [[pd.Timestamp('2017-09-02 22:00:27'),
+                pd.Timestamp('2017-09-02 22:01:36'),
+                pd.Timestamp('2017-09-02 22:03:08'),
+                pd.Timestamp('2017-09-02 22:03:46'),
+                pd.Timestamp('2017-09-02 22:07:19'),
+                pd.Timestamp('2017-09-02 22:07:40')]],
+    LOCAL_LABEL: [[85, 673, 394, 263, 224, 623]],
+    LATITUDE: [[-3.8347478, -3.8235834, -3.813889,
+                -3.9067654, -3.8857223, -3.8828723]],
+    LONGITUDE: [[-38.592189, -38.590389, -38.5904445,
+                 -38.5907723, -38.5928892, -38.5929789]],
+    TID: [['12017090222', '12017090222', '12017090222',
+           '12017090222', '12017090222', '12017090222']]
+}
+
+list_data3 = {
+    TRAJ_ID: [[1, 1, 1], [2, 2, 2, 2]],
+    DATETIME: [[pd.Timestamp('2017-09-02 22:00:27'),
+                pd.Timestamp('2017-09-02 22:01:36'),
+                pd.Timestamp('2017-09-02 22:03:08')],
+               [pd.Timestamp('2017-09-02 23:03:46'),
+                pd.Timestamp('2017-09-02 23:07:19'),
+                pd.Timestamp('2017-09-02 23:07:40'),
+                pd.Timestamp('2017-09-02 23:09:10')]],
+    LOCAL_LABEL: [[85, 673, 394], [263, 224, 623, 394]],
+    LATITUDE: [[-3.8347478, -3.8235834, -3.813889],
+               [-3.9067654, -3.8857223, -3.8828723, -3.9939834]],
+    LONGITUDE: [[-38.592189, -38.590389, -38.5904445],
+                [-38.5907723, -38.5928892, -38.5929789, -38.7040900]],
+    TID: [['12017090222', '12017090222', '12017090222'],
+          ['22017090223', '22017090223', '22017090223', '22017090223']]
+}
+
+list_data4 = {
+    TRAJ_ID: [[1, 1, 1], [2, 2, 2, 2]],
+    DATETIME: [[pd.Timestamp('2017-09-02 22:00:27'),
+                pd.Timestamp('2017-09-02 22:01:36'),
+                pd.Timestamp('2017-09-02 22:03:08')],
+               [pd.Timestamp('2017-09-02 23:03:46'),
+                pd.Timestamp('2017-09-02 23:07:19'),
+                pd.Timestamp('2017-09-02 23:07:40'),
+                pd.Timestamp('2017-09-02 23:09:10')]],
+    LOCAL_LABEL: [[85, 673, 394], [263, 224, 623, 394]],
+    LATITUDE: [[-3.8347478, -3.8235834, -3.813889],
+               [-3.9067654, -3.8857223, -3.8828723, -3.9939834]],
+    LONGITUDE: [[-38.592189, -38.590389, -38.5904445],
+                [-38.5907723, -38.5928892, -38.5929789, -38.7040900]]
+}
 
 
 def test_append_row():
-    traj_df = pd.DataFrame(
-        data={
-            TRAJ_ID: ['abc-0000'],
-            LOCAL_LABEL: [[1, 2]],
-            DATETIME: [[pd.Timestamp('2020-01-01 06:08:15')]],
-            LATITUDE: [[3.1234567165374756]],
-            LONGITUDE: [[38.12345504760742]],
-            TID: [['abc-00002020010106']]})
+    df = pd.DataFrame(list_data2)
 
     expected = pd.DataFrame(
         data={
-            TRAJ_ID: ['abc-0000', 'def-1111'],
-            LOCAL_LABEL: [[1, 2], [5, 6]],
-            DATETIME: [[pd.Timestamp('2020-01-01 06:08:15')],
-                       [pd.Timestamp('2020-01-01 07:10:15')]],
-            LATITUDE: [[3.1234567165374756], [3.623471260070801]],
-            LONGITUDE: [[38.12345504760742], [38.397525787353516]],
-            TID: [['abc-00002020010106'], ['def-1111202001010']]})
+            TRAJ_ID: [[1, 1, 1, 1, 1, 1], [2, 2, 2]],
+            DATETIME: [[pd.Timestamp('2017-09-02 22:00:27'),
+                        pd.Timestamp('2017-09-02 22:01:36'),
+                        pd.Timestamp('2017-09-02 22:03:08'),
+                        pd.Timestamp('2017-09-02 22:03:46'),
+                        pd.Timestamp('2017-09-02 22:07:19'),
+                        pd.Timestamp('2017-09-02 22:07:40')],
+                       [pd.Timestamp('2017-09-03 14:10:15'),
+                        pd.Timestamp('2017-09-03 14:20:30'),
+                        pd.Timestamp('2017-09-03 14:30:45')]],
+            LOCAL_LABEL: [[85, 673, 394, 263, 224, 623],
+                          [673, 263, 623]],
+            LATITUDE: [[-3.8347478, -3.8235834, -3.813889,
+                        -3.9067654, -3.8857223, -3.8828723],
+                       [-3.8235834, -3.9067654, -3.8828723]],
+            LONGITUDE: [[-38.592189, -38.590389, -38.5904445,
+                         -38.5907723, -38.5928892, -38.5929789],
+                        [-38.590389, -38.5907723, -38.5929789]],
+            TID: [['12017090222', '12017090222', '12017090222',
+                   '12017090222', '12017090222', '12017090222'],
+                  ['22017090314', '22017090314', '22017090314']]})
 
     row = pd.Series(
-        data={TRAJ_ID: 'def-1111',
-              LOCAL_LABEL: [5, 6],
-              DATETIME: [pd.Timestamp('2020-01-01 7:10:15')],
-              LATITUDE: [3.6234712461],
-              LONGITUDE: [38.39752597257],
-              TID: ['def-1111202001010']})
-
-    append_row(traj_df, row=row)
-    assert_frame_equal(expected, traj_df)
+        data={
+            TRAJ_ID: [2, 2, 2],
+            LOCAL_LABEL: [673, 263, 623],
+            DATETIME: [pd.Timestamp('2017-09-03 14:10:15'),
+                       pd.Timestamp('2017-09-03 14:20:30'),
+                       pd.Timestamp('2017-09-03 14:30:45')],
+            LATITUDE: [-3.8235834, -3.9067654, -3.8828723],
+            LONGITUDE: [-38.590389, -38.5907723, -38.5929789],
+            TID: ['22017090314', '22017090314', '22017090314']})
 
+    append_row(df, row)
+    assert_frame_equal(df, expected)
 
-def test__augmentation():
-    traj_df = pd.DataFrame(list_data2)
 
-    expected = pd.DataFrame(
-        data={
-            TRAJ_ID: ['abc-0000_def-1111', 'def-1111_abc-0000'],
-            LOCAL_LABEL: [[5, 6, 8, 9], [2, 4, 7, 9]],
-            DATETIME: [[pd.Timestamp('2020-01-01 06:08:15'),
-                        pd.Timestamp('2020-01-01 09:25:30'),
-                        pd.Timestamp('2020-01-01 09:30:17'),
-                        pd.Timestamp('2020-01-01 09:45:16')],
-                       [pd.Timestamp('2020-01-01 09:10:15'),
-                        pd.Timestamp('2020-01-01 09:15:45'),
-                        pd.Timestamp('2020-01-01 06:16:51'),
-                        pd.Timestamp('2020-01-01 06:20:40')]],
-            LATITUDE: [[3.12345672, 3.12345672, 3.12345672, 3.12345672],
-                       [3.12345672, 3.12345672, 3.12345672, 3.12345672]],
-            LONGITUDE: [[38.12345505, 38.12345505, 38.12345505, 38.12345505],
-                        [38.12345505, 38.12345505, 38.12345505, 38.12345505]],
-            TID: [['abc-00002020010106', 'abc-00002020010106',
-                   'abc-00002020010106', 'abc-00002020010106'],
-                  ['def-11112020010109', 'def-11112020010109',
-                   'abc-00002020010106', 'abc-00002020010106']]
-        }
+def test_generate_trajectories_df():
+    df = pd.DataFrame(
+        list_data1,
+        columns=[TRAJ_ID, DATETIME, LOCAL_LABEL, LATITUDE, LONGITUDE, TID]
     )
 
-    aug_df = pd.DataFrame(columns=traj_df.columns)
-
-    _augmentation(traj_df, aug_df)
-    assert_frame_equal(expected, aug_df)
+    expected = pd.DataFrame({
+        TRAJ_ID: [[1, 1, 1, 1, 1, 1]],
+        DATETIME: [[pd.Timestamp('2017-09-02 22:00:27'),
+                    pd.Timestamp('2017-09-02 22:01:36'),
+                    pd.Timestamp('2017-09-02 22:03:08'),
+                    pd.Timestamp('2017-09-02 22:03:46'),
+                    pd.Timestamp('2017-09-02 22:07:19'),
+                    pd.Timestamp('2017-09-02 22:07:40')]],
+        LOCAL_LABEL: [[85, 673, 394, 263, 224, 623]],
+        LATITUDE: [[-3.8347478, -3.8235834, -3.813889,
+                    -3.9067654, -3.8857223, -3.8828723]],
+        LONGITUDE: [[-38.592189, -38.590389, -38.5904445,
+                     -38.5907723, -38.5928892, -38.5929789]],
+        TID: [['12017090222', '12017090222', '12017090222',
+               '12017090222', '12017090222', '12017090222']]
+    })
+
+    traj_df = generate_trajectories_df(df)
+    assert_frame_equal(traj_df, expected)
 
 
 def test_split_crossover():
@@ -151,229 +170,175 @@ def test_split_crossover():
     assert_array_almost_equal(expected2, s2)
 
 
-def test_insert_points_in_df():
-    move_df = pd.DataFrame(
-        data=np.array(list_data1, dtype=object),
-        columns=[TRAJ_ID, LOCAL_LABEL, LATITUDE, LONGITUDE, DATETIME, TID]
+def test_augmentation():
+    df = pd.DataFrame(list_data3)
+
+    expected = pd.DataFrame(
+        data = {
+            TRAJ_ID: [[1, 1, 1], [2, 2, 2, 2], [1, 2, 2], [2, 2, 1, 1]],
+            DATETIME: [[pd.Timestamp('2017-09-02 22:00:27'), pd.Timestamp('2017-09-02 22:01:36'),
+                        pd.Timestamp('2017-09-02 22:03:08')],
+                       [pd.Timestamp('2017-09-02 23:03:46'), pd.Timestamp('2017-09-02 23:07:19'),
+                        pd.Timestamp('2017-09-02 23:07:40'), pd.Timestamp('2017-09-02 23:09:10')],
+                       [pd.Timestamp('2017-09-02 22:00:27'), pd.Timestamp('2017-09-02 23:07:40'),
+                        pd.Timestamp('2017-09-02 23:09:10')],
+                       [pd.Timestamp('2017-09-02 23:03:46'), pd.Timestamp('2017-09-02 23:07:19'),
+                        pd.Timestamp('2017-09-02 22:01:36'), pd.Timestamp('2017-09-02 22:03:08')]],
+            LOCAL_LABEL: [[85, 673, 394], [263, 224, 623, 394],
+                          [ 85, 623, 394], [263, 224, 673, 394]],
+            LATITUDE: [[-3.8347478, -3.8235834, -3.813889],
+                       [-3.9067654, -3.8857223, -3.8828723, -3.9939834],
+                       [-3.8347478, -3.8828723, -3.9939834],
+                       [-3.9067654, -3.8857223, -3.8235834, -3.8138890]],
+            LONGITUDE: [[-38.592189, -38.590389, -38.5904445],
+                        [-38.5907723, -38.5928892, -38.5929789, -38.70409],
+                        [-38.592189 , -38.5929789, -38.70409  ],
+                        [-38.5907723, -38.5928892, -38.590389 , -38.5904445]],
+            TID: [['12017090222', '12017090222', '12017090222'],
+                  ['22017090223', '22017090223', '22017090223', '22017090223'],
+                  ['12017090222', '22017090223', '22017090223'],
+                  ['22017090223', '22017090223', '12017090222', '12017090222']]
+        }
     )
 
-    aug_df = pd.DataFrame(
-        data={
-            TRAJ_ID: ['abc-0000_def-1111'],
-            LOCAL_LABEL: [[5, 6, 7, 9]],
-            LATITUDE: [[3.1234567165374756, 3.1234567165374756,
-                        3.1234567165374756, 3.1234567165374756]],
-            LONGITUDE: [[38.12345504760742, 38.12345504760742,
-                         38.12345504760742, 38.12345504760742]],
-            DATETIME: [[pd.Timestamp('2020-01-01 06:08:15'),
-                        pd.Timestamp('2020-01-01 09:15:45'),
-                        pd.Timestamp('2020-01-01 09:30:45'),
-                        pd.Timestamp('2020-01-01 09:30:45')]],
-            TID: [['abc-0000202001010', 'abc-0000202001010',
-                   'abc-0000202001010', 'abc-0000202001010']],
-            DESTINY: [9]})
+    aug_df = _augmentation(df, 0.5)
+    assert_frame_equal(aug_df, expected)
 
-    expected = pd.DataFrame(
-        data=np.array(
-            [['abc-0000', 1, 3.1234567, 38.1234567,
-              pd.Timestamp('2020-01-01 06:08:15'), 'abc-00002020010106'],
-             ['abc-0000', 2, 3.1234567, 38.1234567,
-              pd.Timestamp('2020-01-01 06:16:51'), 'abc-00002020010106'],
-             ['abc-0000', 3, 3.1234567, 38.1234567,
-              pd.Timestamp('2020-01-01 06:31:41'), 'abc-00002020010106'],
-             ['abc-0000', 4, 3.1234567, 38.1234567,
-              pd.Timestamp('2020-01-01 06:45:25'), 'abc-00002020010106'],
-             ['abc-0000', 9, 3.1234567, 38.1234567,
-              pd.Timestamp('2020-01-01 06:49:18'), 'abc-00002020010106'],
-             ['def-1111', 5, 3.1234567, 38.1234567,
-              pd.Timestamp('2020-01-01 09:10:15'), 'def-11112020010109'],
-             ['def-1111', 6, 3.1234567, 38.1234567,
-              pd.Timestamp('2020-01-01 09:15:45'), 'def-11112020010109'],
-             ['def-1111', 7, 3.1234567, 38.1234567,
-              pd.Timestamp('2020-01-01 09:25:34'), 'def-11112020010109'],
-             ['def-1111', 8, 3.1234567, 38.1234567,
-              pd.Timestamp('2020-01-01 09:40:25'), 'def-11112020010109'],
-             ['def-1111', 9, 3.1234567, 38.1234567,
-              pd.Timestamp('2020-01-01 09:52:53'), 'def-11112020010109'],
-             ['abc-0000_def-1111', 5, 3.1234567165374756, 38.12345504760742,
-              pd.Timestamp('2020-01-01 06:08:15'), 'abc-0000202001010'],
-             ['abc-0000_def-1111', 6, 3.1234567165374756, 38.12345504760742,
-              pd.Timestamp('2020-01-01 09:15:45'), 'abc-0000202001010'],
-             ['abc-0000_def-1111', 7, 3.1234567165374756, 38.12345504760742,
-              pd.Timestamp('2020-01-01 09:30:45'), 'abc-0000202001010'],
-             ['abc-0000_def-1111', 9, 3.1234567165374756, 38.12345504760742,
-              pd.Timestamp('2020-01-01 09:30:45'), 'abc-0000202001010']],
-            dtype=object),
-        columns=[TRAJ_ID, LOCAL_LABEL, LATITUDE, LONGITUDE, DATETIME, TID])
-
-    insert_points_in_df(move_df, aug_df)
-    assert_frame_equal(expected, move_df)
-
-
-def test_generate_start_feature():
-    move_df = pd.DataFrame(list_data2)
+
+def test_flatten_trajectories_dataframe():
+    traj_df = pd.DataFrame(list_data3)
 
     expected = pd.DataFrame(
         data={
-            TRAJ_ID: ['abc-0000', 'def-1111'],
-            LOCAL_LABEL: [[5, 7, 9], [2, 4, 6, 8, 9]],
-            DATETIME: [[pd.Timestamp('2020-01-01 06:08:15'),
-                        pd.Timestamp('2020-01-01 06:16:51'),
-                        pd.Timestamp('2020-01-01 06:20:40')],
-                       [pd.Timestamp('2020-01-01 09:10:15'),
-                        pd.Timestamp('2020-01-01 09:15:45'),
-                        pd.Timestamp('2020-01-01 09:25:30'),
-                        pd.Timestamp('2020-01-01 09:30:17'),
-                        pd.Timestamp('2020-01-01 09:45:16')]],
-            LATITUDE: [[3.1234567165374756, 3.1234567165374756,
-                        3.1234567165374756],
-                       [3.1234567165374756, 3.1234567165374756,
-                        3.1234567165374756, 3.1234567165374756,
-                        3.1234567165374756]],
-            LONGITUDE: [[38.12345504760742, 38.12345504760742,
-                         38.12345504760742],
-                        [38.12345504760742, 38.12345504760742,
-                         38.12345504760742, 38.12345504760742,
-                         38.12345504760742]],
-            TID: [['abc-00002020010106', 'abc-00002020010106',
-                   'abc-00002020010106'],
-                  ['def-11112020010109', 'def-11112020010109',
-                   'abc-00002020010106', 'abc-00002020010106',
-                   'abc-00002020010106']],
-            START: [5, 2]
-        })
+            TRAJ_ID: [1, 1, 1, 2, 2, 2, 2],
+            DATETIME: [pd.Timestamp('2017-09-02 22:00:27'), pd.Timestamp('2017-09-02 22:01:36'),
+                       pd.Timestamp('2017-09-02 22:03:08'), pd.Timestamp('2017-09-02 23:03:46'),
+                       pd.Timestamp('2017-09-02 23:07:19'), pd.Timestamp('2017-09-02 23:07:40'),
+                       pd.Timestamp('2017-09-02 23:09:10')],
+            LOCAL_LABEL: [85, 673, 394, 263, 224, 623, 394],
+            LATITUDE: [-3.8347478, -3.8235834, -3.813889, -3.9067654, -3.8857223,
+                       -3.8828723, -3.9939834],
+            LONGITUDE: [-38.592189, -38.590389, -38.5904445, -38.5907723, -38.5928892,
+                        -38.5929789, -38.70409],
+            TID: ['12017090222', '12017090222', '12017090222', '22017090223', '22017090223',
+                  '22017090223', '22017090223']
+        }
+    )
 
-    generate_start_feature(move_df, label_trajectory=LOCAL_LABEL)
-    assert_frame_equal(move_df, expected)
+    df = flatten_trajectories_dataframe(traj_df)
+    assert_frame_equal(df, expected)
 
 
-def test_generate_destiny_feature():
-    move_df = pd.DataFrame(list_data2)
+def test_instance_crossover_augmentation():
+    traj_df = pd.DataFrame(list_data3)
 
     expected = pd.DataFrame(
         data={
-            TRAJ_ID: ['abc-0000', 'def-1111'],
-            LOCAL_LABEL: [[5, 7, 9], [2, 4, 6, 8, 9]],
-            DATETIME: [[pd.Timestamp('2020-01-01 06:08:15'),
-                        pd.Timestamp('2020-01-01 06:16:51'),
-                        pd.Timestamp('2020-01-01 06:20:40')],
-                       [pd.Timestamp('2020-01-01 09:10:15'),
-                        pd.Timestamp('2020-01-01 09:15:45'),
-                        pd.Timestamp('2020-01-01 09:25:30'),
-                        pd.Timestamp('2020-01-01 09:30:17'),
-                        pd.Timestamp('2020-01-01 09:45:16')]],
-            LATITUDE: [[3.1234567165374756, 3.1234567165374756,
-                        3.1234567165374756],
-                       [3.1234567165374756, 3.1234567165374756,
-                        3.1234567165374756, 3.1234567165374756,
-                        3.1234567165374756]],
-            LONGITUDE: [[38.12345504760742, 38.12345504760742,
-                         38.12345504760742],
-                        [38.12345504760742, 38.12345504760742,
-                         38.12345504760742, 38.12345504760742,
-                         38.12345504760742]],
-            TID: [['abc-00002020010106', 'abc-00002020010106',
-                   'abc-00002020010106'],
-                  ['def-11112020010109', 'def-11112020010109',
-                   'abc-00002020010106', 'abc-00002020010106',
-                   'abc-00002020010106']],
-            DESTINY: [9, 9]
+            TRAJ_ID: [[1, 1, 1], [2, 2, 2, 2], [1, 2, 2], [2, 2, 1, 1]],
+            DATETIME: [[pd.Timestamp('2017-09-02 22:00:27'), pd.Timestamp('2017-09-02 22:01:36'),
+                        pd.Timestamp('2017-09-02 22:03:08')],
+                       [pd.Timestamp('2017-09-02 23:03:46'), pd.Timestamp('2017-09-02 23:07:19'),
+                        pd.Timestamp('2017-09-02 23:07:40'), pd.Timestamp('2017-09-02 23:09:10')],
+                       [pd.Timestamp('2017-09-02 22:00:27'), pd.Timestamp('2017-09-02 23:07:40'),
+                        pd.Timestamp('2017-09-02 23:09:10')],
+                       [pd.Timestamp('2017-09-02 23:03:46'), pd.Timestamp('2017-09-02 23:07:19'),
+                        pd.Timestamp('2017-09-02 22:01:36'), pd.Timestamp('2017-09-02 22:03:08')]],
+            LOCAL_LABEL: [[85, 673, 394], [263, 224, 623, 394], [ 85, 623, 394], [263, 224, 673, 394]],
+            LATITUDE: [[-3.8347478, -3.8235834, -3.813889],
+                       [-3.9067654, -3.8857223, -3.8828723, -3.9939834],
+                       [-3.8347478, -3.8828723, -3.9939834],
+                       [-3.9067654, -3.8857223, -3.8235834, -3.813889 ]],
+            LONGITUDE: [[-38.592189, -38.590389, -38.5904445],
+                        [-38.5907723, -38.5928892, -38.5929789, -38.70409],
+                        [-38.592189 , -38.5929789, -38.70409  ],
+                        [-38.5907723, -38.5928892, -38.590389 , -38.5904445]],
+            TID: [['12017090222', '12017090222', '12017090222'],
+                  ['22017090223', '22017090223', '22017090223', '22017090223'],
+                  ['12017090222', '22017090223', '22017090223'],
+                  ['22017090223', '22017090223', '12017090222', '12017090222']]
         })
 
-    generate_destiny_feature(move_df, label_trajectory=LOCAL_LABEL)
-    assert_frame_equal(move_df, expected)
+    aug_df = instance_crossover_augmentation(traj_df)
+    assert_frame_equal(aug_df, expected)
 
 
-def test_augmentation_trajectories_df():
-    move_df = pd.DataFrame(list_data2)
-
-    expected = pd.DataFrame(
-        data={
-            TRAJ_ID: ['abc-0000_def-1111', 'def-1111_abc-0000'],
-            LOCAL_LABEL: [[5, 6, 8, 9], [2, 4, 7, 9]],
-            DATETIME: [[pd.Timestamp('2020-01-01 06:08:15'),
-                        pd.Timestamp('2020-01-01 09:25:30'),
-                        pd.Timestamp('2020-01-01 09:30:17'),
-                        pd.Timestamp('2020-01-01 09:45:16')],
-                       [pd.Timestamp('2020-01-01 09:10:15'),
-                        pd.Timestamp('2020-01-01 09:15:45'),
-                        pd.Timestamp('2020-01-01 06:16:51'),
-                        pd.Timestamp('2020-01-01 06:20:40')]],
-            LATITUDE: [[3.12345672, 3.12345672, 3.12345672, 3.12345672],
-                       [3.12345672, 3.12345672, 3.12345672, 3.12345672]],
-            LONGITUDE: [[38.12345505, 38.12345505, 38.12345505, 38.12345505],
-                        [38.12345505, 38.12345505, 38.12345505, 38.12345505]],
-            TID: [['abc-00002020010106', 'abc-00002020010106',
-                   'abc-00002020010106', 'abc-00002020010106'],
-                  ['def-11112020010109', 'def-11112020010109',
-                   'abc-00002020010106', 'abc-00002020010106']],
-            DESTINY: [[9], [9]]})
-
-    aug_df = augmentation_trajectories_df(move_df, label_trajectory=LOCAL_LABEL)
-    assert_frame_equal(expected, aug_df)
-
+def test_sliding_window():
+    traj_df = pd.DataFrame(list_data2)
 
-def test_instance_crossover_augmentation():
-    move_df = pd.DataFrame(
-        list_data1,
-        columns=[TRAJ_ID, LOCAL_LABEL, LATITUDE, LONGITUDE, DATETIME, TID]
-    )
+    expected = pd.DataFrame({
+        'id': [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]],
+        'datetime': [[pd.Timestamp('2017-09-02 22:00:27'), pd.Timestamp('2017-09-02 22:01:36'),
+                      pd.Timestamp('2017-09-02 22:03:08'), pd.Timestamp('2017-09-02 22:03:46')],
+                     [pd.Timestamp('2017-09-02 22:01:36'), pd.Timestamp('2017-09-02 22:03:08'),
+                      pd.Timestamp('2017-09-02 22:03:46'), pd.Timestamp('2017-09-02 22:07:19')],
+                     [pd.Timestamp('2017-09-02 22:03:08'), pd.Timestamp('2017-09-02 22:03:46'),
+                      pd.Timestamp('2017-09-02 22:07:19'), pd.Timestamp('2017-09-02 22:07:40')]],
+        'local_label': [[85, 673, 394, 263], [673, 394, 263, 224], [394, 263, 224, 623]],
+        'lat': [[-3.8347478, -3.8235834, -3.813889, -3.9067654],
+                [-3.8235834, -3.813889, -3.9067654, -3.8857223],
+                [-3.813889, -3.9067654, -3.8857223, -3.8828723]],
+        'lon': [[-38.592189, -38.590389, -38.5904445, -38.5907723],
+                [-38.590389, -38.5904445, -38.5907723, -38.5928892],
+                [-38.5904445, -38.5907723, -38.5928892, -38.5929789]],
+        'tid': [['12017090222', '12017090222', '12017090222', '12017090222'],
+                ['12017090222', '12017090222', '12017090222', '12017090222'],
+                ['12017090222', '12017090222', '12017090222', '12017090222']]
+    })
+
+    sw_df = sliding_window(traj_df, size_window=4, size_jump=1)
+    assert_frame_equal(sw_df, expected)
+
+
+def test_get_all_paths():
+    traj_df = pd.DataFrame(list_data4)
+    graph = build_transition_graph_from_df(traj_df)
 
     expected = pd.DataFrame(
         data={
-            TRAJ_ID: ['abc-0000', 'abc-0000', 'abc-0000', 'abc-0000', 'abc-0000',
-                      'def-1111', 'def-1111', 'def-1111', 'def-1111', 'def-1111',
-                      'abc-0000_def-1111', 'abc-0000_def-1111', 'abc-0000_def-1111',
-                      'abc-0000_def-1111', 'abc-0000_def-1111', 'def-1111_abc-0000',
-                      'def-1111_abc-0000', 'def-1111_abc-0000', 'def-1111_abc-0000',
-                      'def-1111_abc-0000'],
-            LOCAL_LABEL: [1.0, 2.0, 3.0, 4.0, 9.0, 5.0, 6.0, 7.0, 8.0, 9.0,
-                          1.0, 2.0, 7.0, 8.0, 9.0, 5.0, 6.0, 3.0, 4.0, 9.0],
-            LATITUDE: [3.1234567, 3.1234567, 3.1234567, 3.1234567, 3.1234567,
-                       3.1234567, 3.1234567, 3.1234567, 3.1234567, 3.1234567,
-                       3.1234567, 3.1234567, 3.1234567, 3.1234567, 3.1234567,
-                       3.1234567, 3.1234567, 3.1234567, 3.1234567, 3.1234567],
-            LONGITUDE: [38.1234567, 38.1234567, 38.1234567, 38.1234567, 38.1234567,
-                        38.1234567, 38.1234567, 38.1234567, 38.1234567, 38.1234567,
-                        38.1234567, 38.1234567, 38.1234567, 38.1234567, 38.1234567,
-                        38.1234567, 38.1234567, 38.1234567, 38.1234567, 38.1234567],
-            DATETIME: [pd.Timestamp('2020-01-01 06:08:15'),
-                       pd.Timestamp('2020-01-01 06:16:51'),
-                       pd.Timestamp('2020-01-01 06:31:41'),
-                       pd.Timestamp('2020-01-01 06:45:25'),
-                       pd.Timestamp('2020-01-01 06:49:18'),
-                       pd.Timestamp('2020-01-01 09:10:15'),
-                       pd.Timestamp('2020-01-01 09:15:45'),
-                       pd.Timestamp('2020-01-01 09:25:34'),
-                       pd.Timestamp('2020-01-01 09:40:25'),
-                       pd.Timestamp('2020-01-01 09:52:53'),
-                       pd.Timestamp('2020-01-01 06:08:15'),
-                       pd.Timestamp('2020-01-01 06:16:51'),
-                       pd.Timestamp('2020-01-01 09:25:34'),
-                       pd.Timestamp('2020-01-01 09:40:25'),
-                       pd.Timestamp('2020-01-01 09:52:53'),
-                       pd.Timestamp('2020-01-01 09:10:15'),
-                       pd.Timestamp('2020-01-01 09:15:45'),
-                       pd.Timestamp('2020-01-01 06:31:41'),
-                       pd.Timestamp('2020-01-01 06:45:25'),
-                       pd.Timestamp('2020-01-01 06:49:18')],
-            TID: ['abc-00002020010106', 'abc-00002020010106',
-                  'abc-00002020010106', 'abc-00002020010106',
-                  'abc-00002020010106', 'def-11112020010109',
-                  'def-11112020010109', 'def-11112020010109',
-                  'def-11112020010109', 'def-11112020010109',
-                  'abc-00002020010106_def-11112020010109',
-                  'abc-00002020010106_def-11112020010109',
-                  'abc-00002020010106_def-11112020010109',
-                  'abc-00002020010106_def-11112020010109',
-                  'abc-00002020010106_def-11112020010109',
-                  'def-11112020010109_abc-00002020010106',
-                  'def-11112020010109_abc-00002020010106',
-                  'def-11112020010109_abc-00002020010106',
-                  'def-11112020010109_abc-00002020010106',
-                  'def-11112020010109_abc-00002020010106']
-        }
-    )
+            TRAJ_ID: [[1, 1, 1], [2, 2, 2, 2], [3, 3, 3]],
+            DATETIME: [[pd.Timestamp('2017-09-02 22:00:27'), pd.Timestamp('2017-09-02 22:01:36'),
+                        pd.Timestamp('2017-09-02 22:03:08')],
+                       [pd.Timestamp('2017-09-02 23:03:46'), pd.Timestamp('2017-09-02 23:07:19'),
+                        pd.Timestamp('2017-09-02 23:07:40'), pd.Timestamp('2017-09-02 23:09:10')],
+                       [pd.Timestamp('2017-09-02 23:07:19'), pd.Timestamp('2017-09-02 23:07:40'),
+                        pd.Timestamp('2017-09-02 23:09:10')]],
+            LOCAL_LABEL: [[85, 673, 394], [263, 224, 623, 394], [224.0, 623.0, 394.0]],
+            LATITUDE: [[-3.8347478, -3.8235834, -3.813889],
+                       [-3.9067654, -3.8857223, -3.8828723, -3.9939834],
+                       [-3.8857223, -3.8828723, -3.9939834]],
+            LONGITUDE: [[-38.592189, -38.590389, -38.5904445],
+                        [-38.5907723, -38.5928892, -38.5929789, -38.70409],
+                        [-38.5928892, -38.5929789, -38.70409]]
+        })
 
-    instance_crossover_augmentation(move_df, label_trajectory=LOCAL_LABEL)
-    assert_frame_equal(move_df, expected)
+    get_all_paths(traj_df, graph, '224', '394')
+    assert_frame_equal(traj_df, expected)
+
+
+def test_transition_graph_augmentation_all_vertex():
+    traj_df = pd.DataFrame(list_data4)
+
+    expected = pd.DataFrame({
+        TRAJ_ID: [[1, 1, 1], [2, 2, 2, 2], [3, 3, 3], [4, 4, 4]],
+        DATETIME: [[pd.Timestamp('2017-09-02 22:00:27'), pd.Timestamp('2017-09-02 22:01:36'),
+                    pd.Timestamp('2017-09-02 22:03:08')],
+                   [pd.Timestamp('2017-09-02 23:03:46'), pd.Timestamp('2017-09-02 23:07:19'),
+                    pd.Timestamp('2017-09-02 23:07:40'), pd.Timestamp('2017-09-02 23:09:10')],
+                   [pd.Timestamp('2017-09-02 23:03:46'), pd.Timestamp('2017-09-02 23:07:19'),
+                    pd.Timestamp('2017-09-02 23:07:40')],
+                   [pd.Timestamp('2017-09-02 23:07:19'), pd.Timestamp('2017-09-02 23:07:40'),
+                    pd.Timestamp('2017-09-02 23:09:10')]],
+        LOCAL_LABEL: [[85, 673, 394], [263, 224, 623, 394],
+                      [263.0, 224.0, 623.0], [224.0, 623.0, 394.0]],
+        LATITUDE: [[-3.8347478, -3.8235834, -3.813889],
+                   [-3.9067654, -3.8857223, -3.8828723, -3.9939834],
+                   [-3.9067654, -3.8857223, -3.8828723],
+                   [-3.8857223, -3.8828723, -3.9939834]],
+        LONGITUDE: [[-38.592189, -38.590389, -38.5904445],
+                    [-38.5907723, -38.5928892, -38.5929789, -38.70409],
+                    [-38.5907723, -38.5928892, -38.5929789],
+                    [-38.5928892, -38.5929789, -38.70409]]
+    })
+
+    transition_graph_augmentation_all_vertex(traj_df)
+    assert_frame_equal(traj_df, expected)
diff --git a/pymove/tests/test_utils_networkx.py b/pymove/tests/test_utils_networkx.py
new file mode 100644
index 00000000..77a4896c
--- /dev/null
+++ b/pymove/tests/test_utils_networkx.py
@@ -0,0 +1,228 @@
+import json
+import os
+
+import pandas as pd
+from networkx.classes.digraph import DiGraph
+from networkx.testing import assert_graphs_equal
+from numpy.testing import assert_equal
+
+from pymove.utils.constants import (
+    DATETIME,
+    LATITUDE,
+    LOCAL_LABEL,
+    LONGITUDE,
+    PREV_LOCAL,
+    TID,
+    TRAJ_ID,
+)
+from pymove.utils.networkx import (
+    _populate_graph,
+    build_transition_graph_from_df,
+    build_transition_graph_from_dict,
+    graph_to_dict,
+    read_graph_json,
+    save_graph_as_json,
+)
+
+dict_graph = {
+    'nodes': {
+        'coords': { '85': (-3.8347478, -38.592189), '673': (-3.8235834, -38.590389),
+                   '394': (-3.813889, -38.5904445), '263': (-3.9067654, -38.5907723),
+                   '224': (-3.8857223, -38.5928892), '623': (-3.8828723, -38.5929789)},
+        'datetime': { '85': ['2017-09-02 22:00:27'], '673': ['2017-09-02 22:01:36'],
+                     '394': ['2017-09-02 22:03:08'], '263': ['2017-09-02 22:03:46'],
+                     '224': ['2017-09-02 22:07:19'], '623': ['2017-09-02 22:07:40']},
+        'freq_source': {'85': 1, '673': 0, '394': 0, '263': 0, '224': 0, '623': 0},
+        'freq_target': {'85': 0, '673': 0, '394': 0, '263': 0, '224': 0, '623': 1}},
+    'edges': {
+        '85': {'673': {'weight': 1, 'mean_times': '0 days 00:01:09'}},
+        '673': {'394': {'weight': 1, 'mean_times': '0 days 00:01:32'}},
+        '394': {'263': {'weight': 1, 'mean_times': '0 days 00:00:38'}},
+        '263': {'224': {'weight': 1, 'mean_times': '0 days 00:03:33'}},
+        '224': {'623': {'weight': 1, 'mean_times': '0 days 00:00:21'}},
+        '623': {}}}
+
+list_data1 = {
+    TRAJ_ID: [[1, 1, 1, 1, 1, 1]],
+    DATETIME: [[pd.Timestamp('2017-09-02 22:00:27'),
+                pd.Timestamp('2017-09-02 22:01:36'),
+                pd.Timestamp('2017-09-02 22:03:08'),
+                pd.Timestamp('2017-09-02 22:03:46'),
+                pd.Timestamp('2017-09-02 22:07:19'),
+                pd.Timestamp('2017-09-02 22:07:40')]],
+    LOCAL_LABEL: [[85, 673, 394, 263, 224, 623]],
+    LATITUDE: [[-3.8347478, -3.8235834, -3.813889,
+                -3.9067654, -3.8857223, -3.8828723]],
+    LONGITUDE: [[-38.592189, -38.590389, -38.5904445,
+                 -38.5907723, -38.5928892, -38.5929789]],
+    TID: [['12017090222', '12017090222', '12017090222',
+           '12017090222', '12017090222', '12017090222']]
+}
+
+
+def _transition_graph():
+    expected_graph = DiGraph()
+    expected_graph.add_node('85', coords=(-3.8347478, -38.592189),
+                   datetime=['2017-09-02 22:00:27'], freq_source=1, freq_target=0)
+    expected_graph.add_node('673', coords=(-3.8235834, -38.590389),
+                   datetime=['2017-09-02 22:01:36'], freq_source=0, freq_target=0)
+    expected_graph.add_node('394', coords=(-3.813889, -38.5904445),
+                   datetime=['2017-09-02 22:03:08'], freq_source=0, freq_target=0)
+    expected_graph.add_node('263', coords=(-3.9067654, -38.5907723),
+                   datetime=['2017-09-02 22:03:46'], freq_source=0, freq_target=0)
+    expected_graph.add_node('224', coords=(-3.8857223, -38.5928892),
+                   datetime=['2017-09-02 22:07:19'], freq_source=0, freq_target=0)
+    expected_graph.add_node('623', coords=(-3.8828723, -38.5929789),
+               datetime=['2017-09-02 22:07:40'], freq_source=0, freq_target=1)
+    expected_graph.add_edge( '85', '673', weight=1, mean_times='0 days 00:01:09')
+    expected_graph.add_edge('673', '394', weight=1, mean_times='0 days 00:01:32')
+    expected_graph.add_edge('394', '263', weight=1, mean_times='0 days 00:00:38')
+    expected_graph.add_edge('263', '224', weight=1, mean_times='0 days 00:03:33')
+    expected_graph.add_edge('224', '623', weight=1, mean_times='0 days 00:00:21')
+
+    return expected_graph
+
+
+def test_populate_graph():
+    row = pd.DataFrame(list_data1).loc[0]
+
+    nodes = {'datetime': {}, 'coords': {}, 'freq_source': {}, 'freq_target': {}}
+    edges = {}
+
+    expected_nodes = {
+        'datetime': {'85': ['2017-09-02 22:00:27'], '673': ['2017-09-02 22:01:36'],
+                     '394': ['2017-09-02 22:03:08'], '263': ['2017-09-02 22:03:46'],
+                     '224': ['2017-09-02 22:07:19'], '623': ['2017-09-02 22:07:40']},
+        'coords': {'85': (-3.8347478, -38.592189), '673': (-3.8235834, -38.590389),
+                   '394': (-3.813889, -38.5904445), '263': (-3.9067654, -38.5907723),
+                   '224': (-3.8857223, -38.5928892), '623': (-3.8828723, -38.5929789)},
+        'freq_source': {'85': 1, '673': 0, '394': 0, '263': 0, '224': 0, '623': 0},
+        'freq_target': {'85': 0, '673': 0, '394': 0, '263': 0, '224': 0, '623': 1}}
+
+    expected_edges = {
+        '85': {'673': {'weight': 1, 'mean_times': '0 days 00:01:09'}},
+        '673': {'394': {'weight': 1, 'mean_times': '0 days 00:01:32'}},
+        '394': {'263': {'weight': 1, 'mean_times': '0 days 00:00:38'}},
+        '263': {'224': {'weight': 1, 'mean_times': '0 days 00:03:33'}},
+        '224': {'623': {'weight': 1, 'mean_times': '0 days 00:00:21'}}}
+
+    _populate_graph(row, nodes, edges)
+    nodes, edges
+
+    assert_equal(expected_nodes, nodes)
+    assert_equal(expected_edges, edges)
+
+
+def test_build_transition_graph_from_dict():
+    expected_graph = _transition_graph()
+
+    graph = build_transition_graph_from_dict(dict_graph)
+
+    assert_graphs_equal(expected_graph, graph)
+
+
+def test_build_transition_graph_from_df():
+    expected_graph = _transition_graph()
+
+    traj_df = pd.DataFrame(list_data1)
+
+    graph = build_transition_graph_from_df(traj_df)
+
+    assert_graphs_equal(expected_graph, graph)
+
+
+def test_graph_to_dict():
+    graph = _transition_graph()
+
+    expected_dict = {
+    'nodes': {
+        'coords': { '85': (-3.8347478, -38.592189), '673': (-3.8235834, -38.590389),
+                   '394': (-3.813889, -38.5904445), '263': (-3.9067654, -38.5907723),
+                   '224': (-3.8857223, -38.5928892), '623': (-3.8828723, -38.5929789)},
+        'datetime': { '85': ['2017-09-02 22:00:27'], '673': ['2017-09-02 22:01:36'],
+                     '394': ['2017-09-02 22:03:08'], '263': ['2017-09-02 22:03:46'],
+                     '224': ['2017-09-02 22:07:19'], '623': ['2017-09-02 22:07:40']},
+        'freq_source': {'85': 1, '673': 0, '394': 0, '263': 0, '224': 0, '623': 0},
+        'freq_target': {'85': 0, '673': 0, '394': 0, '263': 0, '224': 0, '623': 1}},
+    'edges': {
+        '85': {'673': {'weight': 1, 'mean_times': '0 days 00:01:09'}},
+        '673': {'394': {'weight': 1, 'mean_times': '0 days 00:01:32'}},
+        '394': {'263': {'weight': 1, 'mean_times': '0 days 00:00:38'}},
+        '263': {'224': {'weight': 1, 'mean_times': '0 days 00:03:33'}},
+        '224': {'623': {'weight': 1, 'mean_times': '0 days 00:00:21'}},
+        '623': {}}}
+
+    dict_graph = graph_to_dict(graph)
+
+    assert_equal(expected_dict, dict_graph)
+
+
+def test_save_graph_as_json(tmpdir):
+
+    expected = {
+        'nodes': {
+            'coords': { '85': (-3.8347478, -38.592189), '673': (-3.8235834, -38.590389),
+                       '394': (-3.813889, -38.5904445), '263': (-3.9067654, -38.5907723),
+                       '224': (-3.8857223, -38.5928892), '623': (-3.8828723, -38.5929789)},
+            'datetime': { '85': ['2017-09-02 22:00:27'], '673': ['2017-09-02 22:01:36'],
+                         '394': ['2017-09-02 22:03:08'], '263': ['2017-09-02 22:03:46'],
+                         '224': ['2017-09-02 22:07:19'], '623': ['2017-09-02 22:07:40']},
+            'freq_source': {'85': 1, '673': 0, '394': 0, '263': 0, '224': 0, '623': 0},
+            'freq_target': {'85': 0, '673': 0, '394': 0, '263': 0, '224': 0, '623': 1}},
+        'edges': {
+            '85': {'673': {'weight': 1, 'mean_times': '0 days 00:01:09'}},
+            '673': {'394': {'weight': 1, 'mean_times': '0 days 00:01:32'}},
+            '394': {'263': {'weight': 1, 'mean_times': '0 days 00:00:38'}},
+            '263': {'224': {'weight': 1, 'mean_times': '0 days 00:03:33'}},
+            '224': {'623': {'weight': 1, 'mean_times': '0 days 00:00:21'}},
+            '623': {}}}
+
+    d = tmpdir.mkdir('utils')
+
+    file_write_default = d.join('test_save_graph.json')
+    filename_write_default = os.path.join(
+        file_write_default.dirname, file_write_default.basename
+    )
+
+    graph = _transition_graph()
+    save_graph_as_json(graph, filename_write_default)
+    saved_graph = read_graph_json(filename_write_default)
+
+    assert_equal(saved_graph, expected)
+
+
+def test_read_graph_json(tmpdir):
+
+    expected = {
+        'nodes': {
+            'coords': { '85': (-3.8347478, -38.592189), '673': (-3.8235834, -38.590389),
+                       '394': (-3.813889, -38.5904445), '263': (-3.9067654, -38.5907723),
+                       '224': (-3.8857223, -38.5928892), '623': (-3.8828723, -38.5929789)},
+            'datetime': { '85': ['2017-09-02 22:00:27'], '673': ['2017-09-02 22:01:36'],
+                         '394': ['2017-09-02 22:03:08'], '263': ['2017-09-02 22:03:46'],
+                         '224': ['2017-09-02 22:07:19'], '623': ['2017-09-02 22:07:40']},
+            'freq_source': {'85': 1, '673': 0, '394': 0, '263': 0, '224': 0, '623': 0},
+            'freq_target': {'85': 0, '673': 0, '394': 0, '263': 0, '224': 0, '623': 1}},
+        'edges': {
+            '85': {'673': {'weight': 1, 'mean_times': '0 days 00:01:09'}},
+            '673': {'394': {'weight': 1, 'mean_times': '0 days 00:01:32'}},
+            '394': {'263': {'weight': 1, 'mean_times': '0 days 00:00:38'}},
+            '263': {'224': {'weight': 1, 'mean_times': '0 days 00:03:33'}},
+            '224': {'623': {'weight': 1, 'mean_times': '0 days 00:00:21'}},
+            '623': {}}}
+
+    d = tmpdir.mkdir('utils')
+
+    file_write_default = d.join('test_read_graph.json')
+    filename_write_default = os.path.join(
+        file_write_default.dirname, file_write_default.basename
+    )
+
+    graph = _transition_graph()
+
+    with open(filename_write_default, 'w') as f:
+        json.dump(dict_graph, f)
+
+    saved_graph = read_graph_json(filename_write_default)
+
+    assert_equal(saved_graph, expected)
diff --git a/pymove/tests/test_utils_trajectories.py b/pymove/tests/test_utils_trajectories.py
index fd159718..86664334 100644
--- a/pymove/tests/test_utils_trajectories.py
+++ b/pymove/tests/test_utils_trajectories.py
@@ -1,6 +1,7 @@
 import os
 
 import numpy as np
+import pandas as pd
 from numpy.testing import assert_array_almost_equal, assert_array_equal, assert_equal
 from pandas import DataFrame
 from pandas.testing import assert_frame_equal
@@ -9,11 +10,22 @@
 from pymove.utils.constants import (
     DATETIME,
     LATITUDE,
+    LOCAL_LABEL,
     LONGITUDE,
+    PREV_LOCAL,
+    TID,
+    TID_STAT,
     TRAJ_ID,
     TYPE_DASK,
     TYPE_PANDAS,
 )
+from pymove.utils.networkx import build_transition_graph_from_df
+from pymove.utils.trajectories import (
+    append_trajectory,
+    columns_to_array,
+    object_for_array,
+    split_trajectory,
+)
 
 list_data = [
     [39.984094, 116.319236, '2008-10-23 05:53:05', 1],
@@ -23,6 +35,39 @@
     [39.984217, 116.319422, '2008-10-23 05:53:21', 1],
 ]
 
+list_data2 = {
+    TRAJ_ID: [[1, 1, 1, 1, 1, 1]],
+    DATETIME: [[pd.Timestamp('2017-09-02 22:00:27'),
+                pd.Timestamp('2017-09-02 22:01:36'),
+                pd.Timestamp('2017-09-02 22:03:08'),
+                pd.Timestamp('2017-09-02 22:03:46'),
+                pd.Timestamp('2017-09-02 22:07:19'),
+                pd.Timestamp('2017-09-02 22:07:40')]],
+    LOCAL_LABEL: [[85, 673, 394, 263, 224, 623]],
+    LATITUDE: [[-3.8347478, -3.8235834, -3.813889,
+                -3.9067654, -3.8857223, -3.8828723]],
+    LONGITUDE: [[-38.592189, -38.590389, -38.5904445,
+                 -38.5907723, -38.5928892, -38.5929789]],
+    TID: [['12017090222', '12017090222', '12017090222',
+           '12017090222', '12017090222', '12017090222']]
+}
+
+list_data4 = {
+    TRAJ_ID: [[1, 1, 1], [2, 2, 2, 2]],
+    DATETIME: [[pd.Timestamp('2017-09-02 22:00:27'),
+                pd.Timestamp('2017-09-02 22:01:36'),
+                pd.Timestamp('2017-09-02 22:03:08')],
+               [pd.Timestamp('2017-09-02 23:03:46'),
+                pd.Timestamp('2017-09-02 23:07:19'),
+                pd.Timestamp('2017-09-02 23:07:40'),
+                pd.Timestamp('2017-09-02 23:09:10')]],
+    LOCAL_LABEL: [[85, 673, 394], [263, 224, 623, 394]],
+    LATITUDE: [[-3.8347478, -3.8235834, -3.813889],
+               [-3.9067654, -3.8857223, -3.8828723, -3.9939834]],
+    LONGITUDE: [[-38.592189, -38.590389, -38.5904445],
+                [-38.5907723, -38.5928892, -38.5929789, -38.7040900]],
+}
+
 str_data_default = """
 lat,lon,datetime,id
 39.984094, 116.319236, 2008-10-23 05:53:05, 1
@@ -47,7 +92,7 @@ def test_read_csv(tmpdir):
 
     expected = _default_move_df()
 
-    d = tmpdir.mkdir('prepossessing')
+    d = tmpdir.mkdir('utils')
 
     file_default_columns = d.join('test_read_default.csv')
     file_default_columns.write(str_data_default)
@@ -134,54 +179,89 @@ def test_fill_list_with_new_values():
     assert_array_equal(original_list, exected)
 
 
+def test_append_trajectory():
+    traj_df = pd.DataFrame(list_data4)
+    graph = build_transition_graph_from_df(traj_df)
+
+    expected = pd.DataFrame({
+        TRAJ_ID: [[1, 1, 1], [2, 2, 2, 2], [3, 3, 3]],
+        DATETIME: [[pd.Timestamp('2017-09-02 22:00:27'), pd.Timestamp('2017-09-02 22:01:36'),
+                    pd.Timestamp('2017-09-02 22:03:08')],
+                   [pd.Timestamp('2017-09-02 23:03:46'), pd.Timestamp('2017-09-02 23:07:19'),
+                    pd.Timestamp('2017-09-02 23:07:40'), pd.Timestamp('2017-09-02 23:09:10')],
+                   [pd.Timestamp('2017-09-02 23:07:19'), pd.Timestamp('2017-09-02 23:07:40'),
+                    pd.Timestamp('2017-09-02 23:09:10')]],
+        LOCAL_LABEL: [[85, 673, 394], [263, 224, 623, 394], [224.0, 623.0, 394.0]],
+        LATITUDE: [[-3.8347478, -3.8235834, -3.813889],
+                   [-3.9067654, -3.8857223, -3.8828723, -3.9939834],
+                   [-3.8857223, -3.8828723, -3.9939834]],
+        LONGITUDE: [[-38.592189, -38.590389, -38.5904445],
+                    [-38.5907723, -38.5928892, -38.5929789, -38.70409],
+                    [-38.5928892, -38.5929789, -38.70409]],
+    })
+
+    trajectory = [224, 623, 394]
+    append_trajectory(traj_df, trajectory, graph)
+    assert_frame_equal(traj_df, expected)
+
+
+def test_split_trajectory():
+    trajectory = pd.DataFrame(list_data2).loc[0]
+
+    expected = pd.DataFrame({
+        'id': [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]],
+        'datetime': [[pd.Timestamp('2017-09-02 22:00:27'), pd.Timestamp('2017-09-02 22:01:36'),
+                      pd.Timestamp('2017-09-02 22:03:08'), pd.Timestamp('2017-09-02 22:03:46')],
+                     [pd.Timestamp('2017-09-02 22:01:36'), pd.Timestamp('2017-09-02 22:03:08'),
+                      pd.Timestamp('2017-09-02 22:03:46'), pd.Timestamp('2017-09-02 22:07:19')],
+                     [pd.Timestamp('2017-09-02 22:03:08'), pd.Timestamp('2017-09-02 22:03:46'),
+                      pd.Timestamp('2017-09-02 22:07:19'), pd.Timestamp('2017-09-02 22:07:40')]],
+        'local_label': [[85, 673, 394, 263], [673, 394, 263, 224], [394, 263, 224, 623]],
+        'lat': [[-3.8347478, -3.8235834, -3.813889, -3.9067654],
+                [-3.8235834, -3.813889, -3.9067654, -3.8857223],
+                [-3.813889, -3.9067654, -3.8857223, -3.8828723]],
+        'lon': [[-38.592189, -38.590389, -38.5904445, -38.5907723],
+                [-38.590389, -38.5904445, -38.5907723, -38.5928892],
+                [-38.5904445, -38.5907723, -38.5928892, -38.5929789]],
+        'tid': [['12017090222', '12017090222', '12017090222', '12017090222'],
+                ['12017090222', '12017090222', '12017090222', '12017090222'],
+                ['12017090222', '12017090222', '12017090222', '12017090222']]
+    })
+
+    split = split_trajectory(trajectory, size_window=4, size_jump=1)
+    assert_frame_equal(split, expected)
+
+
 def test_object_for_array():
     data_1 = '[1, 2, 3]'
     data_2 = '[1.5, 2.5, 3.5]'
-    data_3 = '[event, event]'
+    data_3 = "['event', 'event']"
 
     expected_data_1 = np.array([1., 2., 3.], dtype=np.float32)
     expected_data_2 = np.array([1.5, 2.5, 3.5], dtype=np.float32)
     expected_data_3 = np.array(['event', 'event'], dtype='object_')
 
-    assert_array_almost_equal(trajectories.object_for_array(data_1), expected_data_1)
-    assert_array_almost_equal(trajectories.object_for_array(data_2), expected_data_2)
-    assert_array_equal(trajectories.object_for_array(data_3), expected_data_3)
-
-
-def test_column_to_array():
-    list_data_1 = [
-        '[1, 2, 3]',
-        '[5, 8]',
-        '[13, 21, 34, 55]',
-        '[89, 144]'
-    ]
-
-    list_data_2 = [
-        '[event]',
-        '[missa, culto]',
-        '[festa da cidade]'
-    ]
-
-    df_1 = DataFrame(list_data_1, columns=['label'])
-    df_2 = DataFrame(list_data_2, columns=['label'])
-
-    expected_data_1 = DataFrame(
-        data={'label': [[1, 2, 3],
-                        [5, 8],
-                        [13, 21, 34, 55],
-                        [89, 144]]},
-        index=[0, 1, 2, 3]
-    )
+    assert_array_almost_equal(object_for_array(data_1), expected_data_1)
+    assert_array_almost_equal(object_for_array(data_2), expected_data_2)
+    assert_array_equal(object_for_array(data_3), expected_data_3)
 
-    expected_data_2 = DataFrame(
-        data={'label': [['event'],
-                        ['missa', 'culto'],
-                        ['festa da cidade']]},
-        index=[0, 1, 2]
-    )
 
-    df_1 = trajectories.column_to_array(df_1, 'label')
-    df_2 = trajectories.column_to_array(df_2, 'label')
+def test_columns_to_array():
+    df = DataFrame({
+        'ids': ['[1, 1, 1]', '[2, 2, 2]', '[3, 3, 3, 3]', '[4, 4]'],
+        'descritions': ["['event', 'event', 'event']", "['bike', 'bike', 'bike']",
+                        "['car', 'car', 'car', 'car']", "['house', 'house']"],
+        'price': ['[10.5, 20.5, 13.5]', '[50.2, 33.4, 90.0]',
+                  '[1.0, 2.9, 3.4, 8.4]', '[100.4, 150.5]']
+    })
+
+    expected = DataFrame({
+        'ids': [[1, 1, 1], [2, 2, 2], [3, 3, 3, 3], [4, 4]],
+        'descritions': [['event', 'event', 'event'], ['bike', 'bike', 'bike'],
+                        ['car', 'car', 'car', 'car'], ['house', 'house']],
+        'price': [[10.5, 20.5, 13.5], [50.2, 33.4, 90.0],
+                  [1.0, 2.9, 3.4, 8.4], [100.4, 150.5]]
+    })
 
-    assert_frame_equal(df_1, expected_data_1)
-    assert_frame_equal(df_2, expected_data_2)
+    columns_to_array(df)
+    assert_frame_equal(df, expected)