diff --git a/.github/workflows/lint_and_test.yml b/.github/workflows/lint_and_test.yml
index e87807ea..ce999458 100644
--- a/.github/workflows/lint_and_test.yml
+++ b/.github/workflows/lint_and_test.yml
@@ -2,37 +2,26 @@ name: Lint and Test
on: [push]
jobs:
- lint:
- name: Code Linting
+ lint-test:
+ name: Lint and Test
runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ python-version: ['3.7', '3.8', '3.9']
steps:
- - uses: actions/checkout@main
- - name: Set up Python 3.7
- uses: actions/setup-python@main
- with:
- python-version: 3.7
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- make dev
- - name: Lint
- working-directory: ${{ github.workspace }}
- run: |
- make lint
- test:
- name: Code Testing
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@main
- - name: Set up Python 3.7
- uses: actions/setup-python@main
- with:
- python-version: 3.7
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- make dev
- - name: Test
- working-directory: ${{ github.workspace }}
- run: |
- make test
+ - uses: actions/checkout@main
+ - uses: actions/setup-python@main
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ make dev
+ - name: Check code style
+ working-directory: ${{ github.workspace }}
+ run: |
+ make lint
+ - name: Runs unit tests
+ working-directory: ${{ github.workspace }}
+ run: |
+ make test
diff --git a/pymove/core/dask.py b/pymove/core/dask.py
index 99f654de..05c15a90 100644
--- a/pymove/core/dask.py
+++ b/pymove/core/dask.py
@@ -1,6 +1,7 @@
"""DaskMoveDataFrame class."""
+from __future__ import annotations
-from typing import TYPE_CHECKING, Dict, List, Text, Union
+from typing import TYPE_CHECKING
import dask
import numpy as np
@@ -27,11 +28,11 @@ class DaskMoveDataFrame(DataFrame, MoveDataFrameAbstractModel):
def __init__(
self,
- data: Union[DataFrame, List, Dict],
- latitude: Text = LATITUDE,
- longitude: Text = LONGITUDE,
- datetime: Text = DATETIME,
- traj_id: Text = TRAJ_ID,
+ data: DataFrame | list | dict,
+ latitude: str = LATITUDE,
+ longitude: str = LONGITUDE,
+ datetime: str = DATETIME,
+ traj_id: str = TRAJ_ID,
n_partitions: int = 1,
):
"""
@@ -501,8 +502,8 @@ def to_csv(self, *args, **kwargs):
raise NotImplementedError('To be implemented')
def convert_to(
- self, new_type: Text
- ) -> Union[MoveDataFrame, 'PandasMoveDataFrame', 'DaskMoveDataFrame']:
+ self, new_type: str
+ ) -> MoveDataFrame | 'PandasMoveDataFrame' | 'DaskMoveDataFrame':
"""
Convert an object from one type to another specified by the user.
@@ -530,7 +531,7 @@ def convert_to(
else:
return self
- def get_type(self) -> Text:
+ def get_type(self) -> str:
"""
Returns the type of the object.
diff --git a/pymove/core/dataframe.py b/pymove/core/dataframe.py
index 3e586116..ce92cd8a 100644
--- a/pymove/core/dataframe.py
+++ b/pymove/core/dataframe.py
@@ -1,6 +1,5 @@
"""MoveDataFrame class."""
-
-from typing import Dict, List, Text, Union
+from __future__ import annotations
from dateutil.parser._parser import ParserError
from pandas.core.frame import DataFrame
@@ -21,12 +20,12 @@ class MoveDataFrame:
@staticmethod
def __new__(
self,
- data: Union[DataFrame, Dict, List],
- latitude: Text = LATITUDE,
- longitude: Text = LONGITUDE,
- datetime: Text = DATETIME,
- traj_id: Text = TRAJ_ID,
- type_: Text = TYPE_PANDAS,
+ data: DataFrame | dict | list,
+ latitude: str = LATITUDE,
+ longitude: str = LONGITUDE,
+ datetime: str = DATETIME,
+ traj_id: str = TRAJ_ID,
+ type_: str = TYPE_PANDAS,
n_partitions: int = 1,
):
"""
@@ -125,8 +124,8 @@ def validate_move_data_frame(data: DataFrame):
@staticmethod
def format_labels(
- current_id: Text, current_lat: Text, current_lon: Text, current_datetime: Text
- ) -> Dict:
+ current_id: str, current_lat: str, current_lon: str, current_datetime: str
+ ) -> dict:
"""
Format the labels for the PyMove lib pattern labels output lat, lon and datatime.
diff --git a/pymove/core/grid.py b/pymove/core/grid.py
index a29c65a7..f42c782a 100644
--- a/pymove/core/grid.py
+++ b/pymove/core/grid.py
@@ -1,12 +1,11 @@
"""Grid class."""
+from __future__ import annotations
import math
-from typing import Callable, Dict, Optional, Text, Tuple, Union
+from typing import Callable
import joblib
-import matplotlib.pyplot as plt
import numpy as np
-from matplotlib.pyplot import figure
from pandas import DataFrame
from shapely.geometry import Polygon
@@ -17,7 +16,6 @@
INDEX_GRID_LON,
LATITUDE,
LONGITUDE,
- POLYGON,
TRAJ_ID,
)
from pymove.utils.conversions import lat_meters
@@ -30,9 +28,9 @@ class Grid:
def __init__(
self,
- data: Union[DataFrame, Dict],
- cell_size: Optional[float] = None,
- meters_by_degree: Optional[float] = None
+ data: DataFrame | dict,
+ cell_size: float | None = None,
+ meters_by_degree: float | None = None
):
"""
Creates a virtual grid from the trajectories.
@@ -58,7 +56,7 @@ def __init__(
ValueError
If one of data or cell grid is not provided
"""
- self.last_operation: Dict = dict()
+ self.last_operation: dict = dict()
if meters_by_degree is None:
meters_by_degree = lat_meters(-3.71839)
if isinstance(data, dict):
@@ -69,7 +67,7 @@ def __init__(
raise ValueError('Must pass either data or cell size.')
self.grid_polygon = None
- def get_grid(self) -> Dict:
+ def get_grid(self) -> dict:
"""
Returns the grid object in a dict format.
@@ -91,7 +89,7 @@ def get_grid(self) -> Dict:
'cell_size_by_degree': self.cell_size_by_degree,
}
- def _grid_from_dict(self, dict_grid: Dict):
+ def _grid_from_dict(self, dict_grid: dict):
"""
Coverts the dict grid to a Grid object.
@@ -218,8 +216,8 @@ def create_update_index_grid_feature(
def convert_two_index_grid_to_one(
self,
data: DataFrame,
- label_grid_lat: Text = INDEX_GRID_LAT,
- label_grid_lon: Text = INDEX_GRID_LON,
+ label_grid_lat: str = INDEX_GRID_LAT,
+ label_grid_lon: str = INDEX_GRID_LON,
):
"""
Converts grid lat-lon ids to unique values.
@@ -241,7 +239,7 @@ def convert_two_index_grid_to_one(
def convert_one_index_grid_to_two(
self,
data: DataFrame,
- label_grid_index: Text = INDEX_GRID,
+ label_grid_index: str = INDEX_GRID,
):
"""
Converts grid lat-lon ids to unique values.
@@ -360,7 +358,7 @@ def create_all_polygons_to_all_point_on_grid(
self.last_operation = end_operation(operation)
return datapolygons
- def point_to_index_grid(self, event_lat: float, event_lon: float) -> Tuple[int, int]:
+ def point_to_index_grid(self, event_lat: float, event_lon: float) -> tuple[int, int]:
"""
Locate the coordinates x and y in a grid of point (lat, long).
@@ -394,7 +392,7 @@ def point_to_index_grid(self, event_lat: float, event_lon: float) -> Tuple[int,
return indexes_lat_y, indexes_lon_x
- def save_grid_pkl(self, filename: Text):
+ def save_grid_pkl(self, filename: str):
"""
Save a grid with new file .pkl.
@@ -409,7 +407,7 @@ def save_grid_pkl(self, filename: Text):
joblib.dump(self.get_grid(), f)
self.last_operation = end_operation(operation)
- def read_grid_pkl(self, filename: Text) -> 'Grid':
+ def read_grid_pkl(self, filename: str) -> 'Grid':
"""
Read grid dict from a file .pkl.
@@ -431,74 +429,6 @@ def read_grid_pkl(self, filename: Text) -> 'Grid':
self.last_operation = end_operation(operation)
return grid
- def show_grid_polygons(
- self,
- data: DataFrame,
- markersize: float = 10,
- linewidth: float = 2,
- figsize: Tuple[int, int] = (10, 10),
- return_fig: bool = True,
- save_fig: bool = False,
- name: Text = 'grid.png',
- ) -> Optional[figure]:
- """
- Generate a visualization with grid polygons.
-
- Parameters
- ----------
- data : DataFrame
- Input trajectory data
- markersize : float, optional
- Represents visualization size marker, by default 10
- linewidth : float, optional
- Represents visualization size line, by default 2
- figsize : tuple(int, int), optional
- Represents the size (float: width, float: height) of a figure,
- by default (10, 10)
- return_fig : bool, optional
- Represents whether or not to save the generated picture, by default True
- save_fig : bool, optional
- Wether to save the figure, by default False
- name : str, optional
- Represents name of a file, by default 'grid.png'
-
- Returns
- -------
- figure
- The generated picture or None
-
- Raises
- ------
- If the dataframe does not contains the POLYGON feature
- IndexError
- If there is no user with the id passed
-
- """
- if POLYGON not in data:
- raise KeyError('POLYGON feature not in dataframe')
-
- data.dropna(subset=[POLYGON], inplace=True)
-
- operation = begin_operation('show_grid_polygons')
-
- fig = plt.figure(figsize=figsize)
-
- for _, row in data.iterrows():
- xs, ys = row[POLYGON].exterior.xy
- plt.plot(ys, xs, 'g', linewidth=linewidth, markersize=markersize)
- xs_start, ys_start = data.iloc[0][POLYGON].exterior.xy
- xs_end, ys_end = data.iloc[-1][POLYGON].exterior.xy
- plt.plot(ys_start, xs_start, 'bo', markersize=markersize * 1.5)
- plt.plot(ys_end, xs_end, 'bX', markersize=markersize * 1.5) # start point
-
- if save_fig:
- plt.savefig(fname=name)
-
- self.last_operation = end_operation(operation)
-
- if return_fig:
- return fig
-
def __repr__(self) -> str:
"""
String representation of grid.
@@ -512,5 +442,5 @@ def __repr__(self) -> str:
grid_size_lon_x: grid longitude size
cell_size_by_degree: grid cell size
"""
- text = ['{}: {}'.format(k, v) for k, v in self.get_grid().items()]
+ text = [f'{k}: {v}' for k, v in self.get_grid().items()]
return '\n'.join(text)
diff --git a/pymove/core/pandas.py b/pymove/core/pandas.py
index 0f0bf91c..e5da791d 100644
--- a/pymove/core/pandas.py
+++ b/pymove/core/pandas.py
@@ -1,6 +1,7 @@
"""PandasMoveDataFrame class."""
+from __future__ import annotations
-from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Text, Tuple, Union
+from typing import TYPE_CHECKING, Any, Callable
import numpy as np
from pandas import DataFrame, DateOffset, Series, Timedelta
@@ -54,11 +55,11 @@ class PandasMoveDataFrame(DataFrame):
def __init__(
self,
- data: Union[DataFrame, List, Dict],
- latitude: Text = LATITUDE,
- longitude: Text = LONGITUDE,
- datetime: Text = DATETIME,
- traj_id: Text = TRAJ_ID,
+ data: DataFrame | list | dict,
+ latitude: str = LATITUDE,
+ longitude: str = LONGITUDE,
+ datetime: str = DATETIME,
+ traj_id: str = TRAJ_ID,
):
"""
Checks whether past data has 'lat', 'lon', 'datetime' columns.
@@ -113,9 +114,9 @@ def __init__(
if MoveDataFrame.has_columns(tdf):
MoveDataFrame.validate_move_data_frame(tdf)
- super(PandasMoveDataFrame, self).__init__(tdf)
+ super().__init__(tdf)
self._type = TYPE_PANDAS
- self.last_operation: Dict = dict()
+ self.last_operation: dict = dict()
else:
raise KeyError(
@@ -190,13 +191,13 @@ def datetime(self):
def rename(
self,
- mapper: Optional[Union[Dict, Callable]] = None,
- index: Optional[Union[Dict, Callable]] = None,
- columns: Optional[Union[Dict, Callable]] = None,
- axis: Optional[Union[int, Text]] = None,
+ mapper: dict | Callable | None = None,
+ index: dict | Callable | None = None,
+ columns: dict | Callable | None = None,
+ axis: int | str | None = None,
copy: bool = True,
inplace: bool = False
- ) -> Optional[Union['PandasMoveDataFrame', DataFrame]]:
+ ) -> 'PandasMoveDataFrame' | DataFrame | None:
"""
Alter axes labels.
@@ -245,7 +246,7 @@ def rename(
if inplace:
if MoveDataFrame.has_columns(rename_):
self._mgr = rename_._mgr
- self._item_cache: Dict = dict()
+ self._item_cache: dict = dict()
rename_ = None
else:
raise AttributeError(
@@ -352,7 +353,7 @@ def get_users_number(self) -> int:
def to_grid(
self,
cell_size: float,
- meters_by_degree: Optional[float] = None
+ meters_by_degree: float | None = None
) -> Grid:
"""
Converts trajectory data to grid format.
@@ -394,7 +395,7 @@ def to_data_frame(self) -> DataFrame:
return DataFrame(self)
def to_dicrete_move_df(
- self, local_label: Text = LOCAL_LABEL
+ self, local_label: str = LOCAL_LABEL
) -> 'PandasMoveDataFrame':
"""
Generate a discrete dataframe move.
@@ -413,7 +414,7 @@ def to_dicrete_move_df(
if local_label not in self:
raise ValueError(
- 'columns {} not in df'.format(local_label)
+ f'columns {local_label} not in df'
)
self.last_operation = end_operation(operation)
@@ -464,10 +465,10 @@ def copy(self, deep: bool = True) -> 'PandasMoveDataFrame':
def generate_tid_based_on_id_datetime(
self,
- str_format: Text = '%Y%m%d%H',
+ str_format: str = '%Y%m%d%H',
sort: bool = True,
inplace: bool = True
- ) -> Optional['PandasMoveDataFrame']:
+ ) -> 'PandasMoveDataFrame' | None:
"""
Create or update trajectory id based on id and datetime.
@@ -513,7 +514,7 @@ def generate_tid_based_on_id_datetime(
def generate_date_features(
self, inplace: bool = True
- ) -> Optional['PandasMoveDataFrame']:
+ ) -> 'PandasMoveDataFrame' | None:
"""
Create or update date feature based on datetime.
@@ -546,7 +547,7 @@ def generate_date_features(
def generate_hour_features(
self, inplace: bool = True
- ) -> Optional['PandasMoveDataFrame']:
+ ) -> 'PandasMoveDataFrame' | None:
"""
Create or update hour features based on datetime.
@@ -579,7 +580,7 @@ def generate_hour_features(
def generate_day_of_the_week_features(
self, inplace: bool = True
- ) -> Optional['PandasMoveDataFrame']:
+ ) -> 'PandasMoveDataFrame' | None:
"""
Create or update day of the week features based on datetime.
@@ -613,7 +614,7 @@ def generate_weekend_features(
self,
create_day_of_week: bool = False,
inplace: bool = True
- ) -> Optional['PandasMoveDataFrame']:
+ ) -> 'PandasMoveDataFrame' | None:
"""
Adds information to rows determining if it is a weekend day.
@@ -661,7 +662,7 @@ def generate_weekend_features(
def generate_time_of_day_features(
self, inplace: bool = True
- ) -> Optional['PandasMoveDataFrame']:
+ ) -> 'PandasMoveDataFrame' | None:
"""
Create or update time of day features based on datetime.
@@ -719,9 +720,9 @@ def generate_time_of_day_features(
def generate_datetime_in_format_cyclical(
self,
- label_datetime: Text = DATETIME,
+ label_datetime: str = DATETIME,
inplace: bool = True
- ) -> Optional['PandasMoveDataFrame']:
+ ) -> 'PandasMoveDataFrame' | None:
"""
Create or update column with cyclical datetime feature.
@@ -763,8 +764,8 @@ def generate_datetime_in_format_cyclical(
@staticmethod
def _prepare_generate_data(
- data_: DataFrame, sort: bool, label_id: Text
- ) -> Tuple[Any, int, None]:
+ data_: DataFrame, sort: bool, label_id: str
+ ) -> tuple[Any, int, None]:
"""
Processes the data and create variables for generate methods.
@@ -807,11 +808,11 @@ def _prepare_generate_data(
def generate_dist_time_speed_features(
self,
- label_id: Text = TRAJ_ID,
+ label_id: str = TRAJ_ID,
label_dtype: Callable = np.float64,
sort: bool = True,
inplace: bool = True
- ) -> Optional['PandasMoveDataFrame']:
+ ) -> 'PandasMoveDataFrame' | None:
"""
Adds distance, time and speed information to the dataframe.
@@ -903,11 +904,11 @@ def generate_dist_time_speed_features(
def generate_dist_features(
self,
- label_id: Text = TRAJ_ID,
+ label_id: str = TRAJ_ID,
label_dtype: Callable = np.float64,
sort: bool = True,
inplace: bool = True
- ) -> Optional['PandasMoveDataFrame']:
+ ) -> 'PandasMoveDataFrame' | None:
"""
Create the three distance in meters to an GPS point P.
@@ -991,11 +992,11 @@ def generate_dist_features(
def generate_time_features(
self,
- label_id: Text = TRAJ_ID,
+ label_id: str = TRAJ_ID,
label_dtype: Callable = np.float64,
sort: bool = True,
inplace: bool = True
- ) -> Optional['PandasMoveDataFrame']:
+ ) -> 'PandasMoveDataFrame' | None:
"""
Create the three time in seconds to an GPS point P.
@@ -1070,11 +1071,11 @@ def generate_time_features(
def generate_speed_features(
self,
- label_id: Text = TRAJ_ID,
+ label_id: str = TRAJ_ID,
label_dtype: Callable = np.float64,
sort: bool = True,
inplace: bool = True
- ) -> Optional['PandasMoveDataFrame']:
+ ) -> 'PandasMoveDataFrame' | None:
"""
Create the three speed in meter by seconds to an GPS point P.
@@ -1145,7 +1146,7 @@ def generate_speed_features(
def generate_move_and_stop_by_radius(
self,
radius: float = 0,
- target_label: Text = DIST_TO_PREV,
+ target_label: str = DIST_TO_PREV,
inplace: bool = True
):
"""
@@ -1208,7 +1209,7 @@ def time_interval(self) -> Timedelta:
return time_diff
- def get_bbox(self) -> Tuple[float, float, float, float]:
+ def get_bbox(self) -> tuple[float, float, float, float]:
"""
Returns the bounding box of the dataframe.
@@ -1291,7 +1292,7 @@ def show_trajectories_info(self):
if LATITUDE and LONGITUDE in self:
print(
- 'Bounding Box:%s\n' % (self.get_bbox(),)
+ f'Bounding Box:{self.get_bbox()}\n'
) # bbox return = Lat_min , Long_min, Lat_max, Long_max
if TIME_TO_PREV in self:
@@ -1326,9 +1327,9 @@ def show_trajectories_info(self):
def astype(
self,
- dtype: Union[Callable, Dict],
+ dtype: Callable | dict,
copy: bool = True,
- errors: Text = 'raise'
+ errors: str = 'raise'
) -> DataFrame:
"""
Cast a pandas object to a specified dtype.
@@ -1382,13 +1383,13 @@ def astype(
def sort_values(
self,
- by: Union[Text, List[Text]],
+ by: str | list[str],
axis: int = 0,
ascending: bool = True,
inplace: bool = False,
- kind: Text = 'quicksort',
- na_position: Text = 'last',
- ) -> Optional['PandasMoveDataFrame']:
+ kind: str = 'quicksort',
+ na_position: str = 'last',
+ ) -> 'PandasMoveDataFrame' | None:
"""
Sorts the values of the _data, along an axis.
@@ -1441,12 +1442,12 @@ def sort_values(
def reset_index(
self,
- level: Optional[Union[int, Text, Tuple, List]] = None,
+ level: int | str | tuple | list | None = None,
drop: bool = False,
inplace: bool = False,
- col_level: Union[int, Text] = 0,
- col_fill: Text = ''
- ) -> Optional['PandasMoveDataFrame']:
+ col_level: int | str = 0,
+ col_fill: str = ''
+ ) -> 'PandasMoveDataFrame' | None:
"""
Resets the DataFrame's index, and use the default one.
@@ -1489,12 +1490,12 @@ def reset_index(
def set_index(
self,
- keys: Union[Text, List[Text]],
+ keys: str | list[str],
drop: bool = True,
append: bool = False,
inplace: bool = False,
verify_integrity: bool = False,
- ) -> Optional[Union['PandasMoveDataFrame', DataFrame]]:
+ ) -> 'PandasMoveDataFrame' | DataFrame | None:
"""
Set the DataFrame index (row labels) using one or more existing columns or arrays.
@@ -1558,14 +1559,14 @@ def set_index(
def drop(
self,
- labels: Optional[Union[Text, List[Text]]] = None,
- axis: Union[int, Text] = 0,
- index: Optional[Union[Text, List[Text]]] = None,
- columns: Optional[Union[Text, List[Text]]] = None,
- level: Optional[Union[int, Text]] = None,
+ labels: str | list[str] | None = None,
+ axis: int | str = 0,
+ index: str | list[str] | None = None,
+ columns: str | list[str] | None = None,
+ level: int | str | None = None,
inplace: bool = False,
- errors: Text = 'raise',
- ) -> Optional[Union['PandasMoveDataFrame', DataFrame]]:
+ errors: str = 'raise',
+ ) -> 'PandasMoveDataFrame' | DataFrame | None:
"""
Removes rows or columns.
@@ -1651,10 +1652,10 @@ def drop(
def drop_duplicates(
self,
- subset: Optional[Union[int, Text]] = None,
- keep: Union[Text, bool] = 'first',
+ subset: int | str | None = None,
+ keep: str | bool = 'first',
inplace: bool = False
- ) -> Optional['PandasMoveDataFrame']:
+ ) -> 'PandasMoveDataFrame' | None:
"""
Uses the pandas's function drop_duplicates, to remove duplicated rows from data.
@@ -1694,9 +1695,9 @@ def drop_duplicates(
def shift(
self,
periods: int = 1,
- freq: Optional[Union[DateOffset, Timedelta, Text]] = None,
- axis: Union[int, Text] = 0,
- fill_value: Optional[Any] = None
+ freq: DateOffset | Timedelta | str | None = None,
+ axis: int | str = 0,
+ fill_value: Any | None = None
) -> 'PandasMoveDataFrame':
"""
Shift index by desired number of periods with an optional time freq.
@@ -1740,12 +1741,12 @@ def shift(
def fillna(
self,
- value: Optional[Any] = None,
- method: Optional[Text] = None,
- axis: Optional[Union[int, Text]] = None,
+ value: Any | None = None,
+ method: str | None = None,
+ axis: int | str | None = None,
inplace: bool = False,
- limit: Optional[int] = None,
- downcast: Optional[Dict] = None,
+ limit: int | None = None,
+ downcast: dict | None = None,
):
"""
Fill NA/NaN values using the specified method.
@@ -1803,10 +1804,10 @@ def fillna(
def dropna(
self,
- axis: Union[int, Text] = 0,
- how: Text = 'any',
- thresh: Optional[float] = None,
- subset: Optional[List] = None,
+ axis: int | str = 0,
+ how: str = 'any',
+ thresh: float | None = None,
+ subset: list | None = None,
inplace: bool = False
):
"""
@@ -1870,12 +1871,12 @@ def dropna(
def sample(
self,
- n: Optional[int] = None,
- frac: Optional[float] = None,
+ n: int | None = None,
+ frac: float | None = None,
replace: bool = False,
- weights: Optional[Union[Text, List]] = None,
- random_state: Optional[int] = None,
- axis: Optional[Union[int, Text]] = None
+ weights: str | list | None = None,
+ random_state: int | None = None,
+ axis: int | str | None = None
) -> 'PandasMoveDataFrame':
"""
Return a random sample of items from an axis of object.
@@ -1938,7 +1939,7 @@ def sample(
)
return PandasMoveDataFrame(data=_sample)
- def isin(self, values: Union[List, Series, DataFrame, Dict]) -> DataFrame:
+ def isin(self, values: list | Series | DataFrame | dict) -> DataFrame:
"""
Determines whether each element in the DataFrame is contained in values.
@@ -1965,7 +1966,7 @@ def isin(self, values: Union[List, Series, DataFrame, Dict]) -> DataFrame:
def append(
self,
- other: Union['PandasMoveDataFrame', DataFrame],
+ other: 'PandasMoveDataFrame' | DataFrame,
ignore_index: bool = False,
verify_integrity: bool = False,
sort: bool = False
@@ -2010,11 +2011,11 @@ def append(
def join(
self,
- other: Union['PandasMoveDataFrame', DataFrame],
- on: Optional[Union[Text, List]] = None,
- how: Text = 'left',
- lsuffix: Text = '',
- rsuffix: Text = '',
+ other: 'PandasMoveDataFrame' | DataFrame,
+ on: str | list | None = None,
+ how: str = 'left',
+ lsuffix: str = '',
+ rsuffix: str = '',
sort: bool = False
) -> 'PandasMoveDataFrame':
"""
@@ -2080,18 +2081,18 @@ def join(
def merge(
self,
- right: Union['PandasMoveDataFrame', DataFrame, Series],
- how: Text = 'inner',
- on: Optional[Union[Text, List]] = None,
- left_on: Optional[Union[Text, List]] = None,
- right_on: Optional[Union[Text, List]] = None,
+ right: 'PandasMoveDataFrame' | DataFrame | Series,
+ how: str = 'inner',
+ on: str | list | None = None,
+ left_on: str | list | None = None,
+ right_on: str | list | None = None,
left_index: bool = False,
right_index: bool = False,
sort: bool = False,
- suffixes: Tuple[Text, Text] = ('_x', '_y'),
+ suffixes: tuple[str, str] = ('_x', '_y'),
copy: bool = True,
- indicator: Union[bool, Text] = False,
- validate: Optional[Text] = None
+ indicator: bool | str = False,
+ validate: str | None = None
) -> 'PandasMoveDataFrame':
"""
Merge DataFrame or named Series objects with a database-style join.
@@ -2180,7 +2181,7 @@ def merge(
)
return PandasMoveDataFrame(data=_merge)
- def write_file(self, file_name: Text, separator: Text = ','):
+ def write_file(self, file_name: str, separator: str = ','):
"""
Write trajectory data to a new file.
@@ -2197,8 +2198,8 @@ def write_file(self, file_name: Text, separator: Text = ','):
)
def convert_to(
- self, new_type: Text
- ) -> Union[MoveDataFrame, 'PandasMoveDataFrame', 'DaskMoveDataFrame']:
+ self, new_type: str
+ ) -> MoveDataFrame | 'PandasMoveDataFrame' | 'DaskMoveDataFrame':
"""
Convert an object from one type to another specified by the user.
@@ -2231,7 +2232,7 @@ def convert_to(
self.last_operation = end_operation(operation)
return self
- def get_type(self) -> Text:
+ def get_type(self) -> str:
"""
Returns the type of the object.
diff --git a/pymove/core/pandas_discrete.py b/pymove/core/pandas_discrete.py
index 54e9c93e..04d65ab5 100644
--- a/pymove/core/pandas_discrete.py
+++ b/pymove/core/pandas_discrete.py
@@ -1,6 +1,5 @@
"""PandasDiscreteMoveDataFrame class."""
-
-from typing import Dict, List, Optional, Text, Union
+from __future__ import annotations
import numpy as np
import pandas as pd
@@ -37,12 +36,12 @@ class PandasDiscreteMoveDataFrame(PandasMoveDataFrame):
def __init__(
self,
- data: Union[DataFrame, List, Dict],
- latitude: Text = LATITUDE,
- longitude: Text = LONGITUDE,
- datetime: Text = DATETIME,
- traj_id: Text = TRAJ_ID,
- local_label: Text = LOCAL_LABEL
+ data: DataFrame | list | dict,
+ latitude: str = LATITUDE,
+ longitude: str = LONGITUDE,
+ datetime: str = DATETIME,
+ traj_id: str = TRAJ_ID,
+ local_label: str = LOCAL_LABEL
):
"""
Creates a dataframe using local_label as a discrete feature for localization.
@@ -69,7 +68,7 @@ def __init__(
ValueError, ParserError
If the data types can't be converted.
"""
- super(PandasDiscreteMoveDataFrame, self).__init__(
+ super().__init__(
data=data,
latitude=latitude,
longitude=longitude,
@@ -79,7 +78,7 @@ def __init__(
if local_label not in self:
raise ValueError(
- '{} column not in dataframe'.format(local_label)
+ f'{local_label} column not in dataframe'
)
def discretize_based_grid(self, region_size: int = 1000):
@@ -100,11 +99,11 @@ def discretize_based_grid(self, region_size: int = 1000):
def generate_prev_local_features(
self,
- label_id: Text = TRAJ_ID,
- local_label: Text = LOCAL_LABEL,
+ label_id: str = TRAJ_ID,
+ local_label: str = LOCAL_LABEL,
sort: bool = True,
inplace: bool = True
- ) -> Optional['PandasDiscreteMoveDataFrame']:
+ ) -> 'PandasDiscreteMoveDataFrame' | None:
"""
Create a feature prev_local with the label of previous local to current point.
@@ -145,7 +144,7 @@ def generate_prev_local_features(
if (data_[local_label].dtype == 'int'):
data_[local_label] = data_[local_label].astype(np.float16)
for idx in progress_bar(
- ids, desc='Generating previous {}'.format(local_label)
+ ids, desc=f'Generating previous {local_label}'
):
current_local = data_.at[idx, local_label]
current_local = np.array(current_local)
@@ -168,15 +167,15 @@ def generate_prev_local_features(
def generate_tid_based_statistics(
self,
- label_id: Text = TRAJ_ID,
- local_label: Text = LOCAL_LABEL,
+ label_id: str = TRAJ_ID,
+ local_label: str = LOCAL_LABEL,
mean_coef: float = 1.0,
std_coef: float = 1.0,
- statistics: Optional[DataFrame] = None,
- label_tid_stat: Text = TID_STAT,
+ statistics: DataFrame | None = None,
+ label_tid_stat: str = TID_STAT,
drop_single_points: bool = False,
inplace: bool = True,
- ) -> Optional['PandasDiscreteMoveDataFrame']:
+ ) -> 'PandasDiscreteMoveDataFrame' | None:
"""
Splits the trajectories into segments based on time statistics for segments.
@@ -223,7 +222,7 @@ def generate_tid_based_statistics(
self.generate_dist_time_speed_features(TRAJ_ID)
if local_label not in data_:
- raise KeyError('{} not in data frame.'.format(local_label))
+ raise KeyError(f'{local_label} not in data frame.')
if PREV_LOCAL not in data_:
data_[local_label] = data_[local_label].astype(np.float64)
@@ -234,7 +233,7 @@ def generate_tid_based_statistics(
if statistics is None:
if (data_[PREV_LOCAL].isna().sum() == data_.shape[0]):
raise ValueError(
- 'all values in the {} column are null.'.format(PREV_LOCAL)
+ f'all values in the {PREV_LOCAL} column are null.'
)
else:
statistics = generate_time_statistics(data_, local_label=local_label)
@@ -269,7 +268,7 @@ def generate_tid_based_statistics(
if label_id == TID_STAT:
self.reset_index(drop=True, inplace=True)
logger.debug(
- '... {} = {}, then reseting and drop index!'.format(TID, TID_STAT))
+ f'... {TID} = {TID_STAT}, then reseting and drop index!')
else:
self.reset_index(inplace=True)
logger.debug('... reseting index\n')
diff --git a/pymove/models/pattern_mining/clustering.py b/pymove/models/pattern_mining/clustering.py
index d9302b3b..a874b79f 100644
--- a/pymove/models/pattern_mining/clustering.py
+++ b/pymove/models/pattern_mining/clustering.py
@@ -6,8 +6,9 @@
dbscan_clustering
"""
+from __future__ import annotations
-from typing import Callable, Dict, Optional, Text, Union
+from typing import Callable
import numpy as np
from pandas import DataFrame
@@ -24,8 +25,8 @@ def elbow_method(
k_initial: int = 1,
max_clusters: int = 15,
k_iteration: int = 1,
- random_state: Optional[int] = None
-) -> Dict:
+ random_state: int | None = None
+) -> dict:
"""
Determines the optimal number of clusters.
@@ -84,8 +85,8 @@ def gap_statistic(
k_initial: int = 1,
max_clusters: int = 15,
k_iteration: int = 1,
- random_state: Optional[int] = None
-) -> Dict:
+ random_state: int | None = None
+) -> dict:
"""
Calculates optimal clusters numbers using Gap Statistic.
@@ -151,13 +152,13 @@ def gap_statistic(
@timer_decorator
def dbscan_clustering(
move_data: DataFrame,
- cluster_by: Text,
+ cluster_by: str,
meters: int = 10,
min_sample: float = 1680 / 2,
earth_radius: float = EARTH_RADIUS,
- metric: Union[Text, Callable] = 'euclidean',
+ metric: str | Callable = 'euclidean',
inplace: bool = False
-) -> Optional[DataFrame]:
+) -> DataFrame | None:
"""
Performs density based clustering on the move_dataframe according to cluster_by.
diff --git a/pymove/preprocessing/compression.py b/pymove/preprocessing/compression.py
index f79963ee..4bba2a38 100644
--- a/pymove/preprocessing/compression.py
+++ b/pymove/preprocessing/compression.py
@@ -4,8 +4,7 @@
compress_segment_stop_to_point
"""
-
-from typing import Text
+from __future__ import annotations
import numpy as np
from pandas import DataFrame
@@ -28,11 +27,11 @@
@timer_decorator
def compress_segment_stop_to_point(
move_data: DataFrame,
- label_segment: Text = SEGMENT_STOP,
- label_stop: Text = STOP,
- point_mean: Text = 'default',
+ label_segment: str = SEGMENT_STOP,
+ label_stop: str = STOP,
+ point_mean: str = 'default',
drop_moves: bool = False,
- label_id: Text = TRAJ_ID,
+ label_id: str = TRAJ_ID,
dist_radius: float = 30,
time_radius: float = 900,
inplace: bool = False,
@@ -147,7 +146,7 @@ def compress_segment_stop_to_point(
lat_mean[ind_end] = move_data.loc[filter_][LATITUDE].mean()
lon_mean[ind_end] = move_data.loc[filter_][LONGITUDE].mean()
else:
- logger.debug('There are segments with only one point: {}'.format(idx))
+ logger.debug(f'There are segments with only one point: {idx}')
move_data[LAT_MEAN] = lat_mean
move_data[LON_MEAN] = lon_mean
diff --git a/pymove/preprocessing/filters.py b/pymove/preprocessing/filters.py
index 052881d4..871f17ad 100644
--- a/pymove/preprocessing/filters.py
+++ b/pymove/preprocessing/filters.py
@@ -17,8 +17,9 @@
clean_id_by_time_max
"""
+from __future__ import annotations
-from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Text, Tuple, Union
+from typing import TYPE_CHECKING, Any, Callable
import numpy as np
from pandas import DataFrame
@@ -43,8 +44,8 @@
def get_bbox_by_radius(
- coordinates: Tuple[float, float], radius: float = 1000
-) -> Tuple[float, float, float, float]:
+ coordinates: tuple[float, float], radius: float = 1000
+) -> tuple[float, float, float, float]:
"""
Defines minimum and maximum coordinates, given a distance radius from a point.
@@ -82,10 +83,10 @@ def get_bbox_by_radius(
def by_bbox(
move_data: DataFrame,
- bbox: Tuple[float, float, float, float],
+ bbox: tuple[float, float, float, float],
filter_out: bool = False,
inplace: bool = False
-) -> Optional[DataFrame]:
+) -> DataFrame | None:
"""
Filters points of the trajectories according to specified bounding box.
@@ -123,11 +124,11 @@ def by_bbox(
def by_datetime(
move_data: DataFrame,
- start_datetime: Optional[Text] = None,
- end_datetime: Optional[Text] = None,
+ start_datetime: str | None = None,
+ end_datetime: str | None = None,
filter_out: bool = False,
inplace: bool = False,
-) -> Optional[DataFrame]:
+) -> DataFrame | None:
"""
Filters trajectories points according to specified time range.
@@ -173,10 +174,10 @@ def by_datetime(
def by_label(
move_data: DataFrame,
value: Any,
- label_name: Text,
+ label_name: str,
filter_out: bool = False,
inplace: bool = False
-) -> Optional[DataFrame]:
+) -> DataFrame | None:
"""
Filters trajectories points according to specified value and column label.
@@ -212,11 +213,11 @@ def by_label(
def by_id(
move_data: DataFrame,
- id_: Optional[int] = None,
- label_id: Text = TRAJ_ID,
+ id_: int | None = None,
+ label_id: str = TRAJ_ID,
filter_out: bool = False,
inplace: bool = False
-) -> Optional[DataFrame]:
+) -> DataFrame | None:
"""
Filters trajectories points according to specified trajectory id.
@@ -250,10 +251,10 @@ def by_id(
def by_tid(
move_data: DataFrame,
- tid_: Optional[Text] = None,
+ tid_: str | None = None,
filter_out: bool = False,
inplace: bool = False
-) -> Optional[DataFrame]:
+) -> DataFrame | None:
"""
Filters trajectories points according to a specified trajectory tid.
@@ -286,10 +287,10 @@ def by_tid(
def clean_consecutive_duplicates(
move_data: DataFrame,
- subset: Optional[Union[int, Text]] = None,
- keep: Union[Text, bool] = 'first',
+ subset: int | str | None = None,
+ keep: str | bool = 'first',
inplace: bool = False
-) -> Optional[DataFrame]:
+) -> DataFrame | None:
"""
Removes consecutive duplicate rows of the Dataframe.
@@ -378,7 +379,7 @@ def _filter_speed_max_radius(move_data: DataFrame, **kwargs):
return move_data[filter_]
-def _filter_data(move_data: DataFrame, f: Callable, kwargs: Dict):
+def _filter_data(move_data: DataFrame, f: Callable, kwargs: dict):
"""
Filter the dataframe using condition from given function.
@@ -466,13 +467,13 @@ def _clean_gps(move_data: DataFrame, f: Callable, **kwargs):
def clean_gps_jumps_by_distance(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- label_id: Text = TRAJ_ID,
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ label_id: str = TRAJ_ID,
jump_coefficient: float = 3.0,
threshold: float = 1,
label_dtype: Callable = np.float64,
inplace: bool = False,
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Removes the trajectories points that are outliers from the dataframe.
@@ -524,12 +525,12 @@ def clean_gps_jumps_by_distance(
def clean_gps_nearby_points_by_distances(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- label_id: Text = TRAJ_ID,
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ label_id: str = TRAJ_ID,
radius_area: float = 10.0,
label_dtype: Callable = np.float64,
inplace: bool = False,
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Removes points from the trajectories with smaller distance from the point before.
@@ -579,12 +580,12 @@ def clean_gps_nearby_points_by_distances(
def clean_gps_nearby_points_by_speed(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- label_id: Text = TRAJ_ID,
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ label_id: str = TRAJ_ID,
speed_radius: float = 0.0,
label_dtype: Callable = np.float64,
inplace: bool = False,
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Removes points from the trajectories with smaller speed of travel.
@@ -634,12 +635,12 @@ def clean_gps_nearby_points_by_speed(
def clean_gps_speed_max_radius(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- label_id: Text = TRAJ_ID,
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ label_id: str = TRAJ_ID,
speed_max: float = 50.0,
label_dtype: Callable = np.float64,
inplace: bool = False,
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Removes trajectories points with higher speed.
@@ -698,11 +699,11 @@ def clean_gps_speed_max_radius(
def clean_trajectories_with_few_points(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- label_tid: Text = TID,
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ label_tid: str = TID,
min_points_per_trajectory: int = 2,
inplace: bool = False
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Removes from the given dataframe, trajectories with fewer points.
@@ -775,13 +776,13 @@ def clean_trajectories_with_few_points(
def clean_trajectories_short_and_few_points(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- label_id: Text = TID,
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ label_id: str = TID,
min_trajectory_distance: float = 100,
min_points_per_trajectory: int = 2,
label_dtype: Callable = np.float64,
inplace: bool = False,
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Eliminates from the given dataframe trajectories with fewer points and shorter length.
@@ -863,12 +864,12 @@ def clean_trajectories_short_and_few_points(
def clean_id_by_time_max(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- label_id: Text = TRAJ_ID,
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ label_id: str = TRAJ_ID,
time_max: float = 3600,
label_dtype: Callable = np.float64,
inplace: bool = False,
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Clears GPS points with time by ID greater than a user-defined limit.
@@ -909,7 +910,7 @@ def clean_id_by_time_max(
move_dataid_drop = (
move_data.groupby([label_id], as_index=False)
.agg({TIME_TO_PREV: 'sum'})
- .query('%s < %s' % (TIME_TO_PREV, time_max))
+ .query(f'{TIME_TO_PREV} < {time_max}')
)
logger.debug(
'...Ids total: %s\nIds to drop:%s'
diff --git a/pymove/preprocessing/segmentation.py b/pymove/preprocessing/segmentation.py
index 59c94f01..4dfcfe37 100644
--- a/pymove/preprocessing/segmentation.py
+++ b/pymove/preprocessing/segmentation.py
@@ -8,8 +8,9 @@
by_max_speed
"""
+from __future__ import annotations
-from typing import TYPE_CHECKING, Optional, Text, Tuple, Union
+from typing import TYPE_CHECKING
import numpy as np
import pandas as pd
@@ -34,7 +35,7 @@
@timer_decorator
-def bbox_split(bbox: Tuple[int, int, int, int], number_grids: int) -> DataFrame:
+def bbox_split(bbox: tuple[int, int, int, int], number_grids: int) -> DataFrame:
"""
Splits the bounding box in N grids of the same size.
@@ -60,7 +61,7 @@ def bbox_split(bbox: Tuple[int, int, int, int], number_grids: int) -> DataFrame:
const_lat = abs(abs(lat_max) - abs(lat_min)) / number_grids
const_lon = abs(abs(lon_max) - abs(lon_min)) / number_grids
- logger.debug('const_lat: {}\nconst_lon: {}'.format(const_lat, const_lon))
+ logger.debug(f'const_lat: {const_lat}\nconst_lon: {const_lon}')
move_data = pd.DataFrame(
columns=['lat_min', 'lon_min', 'lat_max', 'lon_max']
@@ -79,7 +80,7 @@ def bbox_split(bbox: Tuple[int, int, int, int], number_grids: int) -> DataFrame:
return move_data
-def _drop_single_point(move_data: DataFrame, label_new_tid: Text, label_id: Text):
+def _drop_single_point(move_data: DataFrame, label_new_tid: str, label_id: str):
"""
Removes trajectory with single point.
@@ -147,7 +148,7 @@ def _filter_and_dist_time_speed(
def _filter_or_dist_time_speed(
- move_data: DataFrame, idx: int, feature: Text, max_between_adj_points: float
+ move_data: DataFrame, idx: int, feature: str, max_between_adj_points: float
) -> ndarray:
"""
Filters the dataframe considering thresholds for time, dist and speed.
@@ -172,7 +173,7 @@ def _filter_or_dist_time_speed(
return np.nan_to_num(move_data.at[idx, feature]) > max_between_adj_points
-def _prepare_segmentation(move_data: DataFrame, label_id: Text, label_new_tid: Text):
+def _prepare_segmentation(move_data: DataFrame, label_id: str, label_new_tid: str):
"""
Resets the dataframe index, collects unique ids and initiates curr_id and count.
@@ -196,7 +197,7 @@ def _prepare_segmentation(move_data: DataFrame, label_id: Text, label_new_tid: T
"""
if move_data.index.name is None:
- logger.debug('...setting {} as index'.format(label_id))
+ logger.debug(f'...setting {label_id} as index')
move_data.set_index(label_id, inplace=True)
curr_tid = 0
if label_new_tid not in move_data:
@@ -209,8 +210,8 @@ def _prepare_segmentation(move_data: DataFrame, label_id: Text, label_new_tid: T
def _update_curr_tid_count(
filter_: ndarray, move_data: DataFrame, idx: int,
- label_new_tid: Text, curr_tid: int, count: int
-) -> Tuple[int, int]:
+ label_new_tid: str, curr_tid: int, count: int
+) -> tuple[int, int]:
"""
Updates the tid.
@@ -239,7 +240,7 @@ def _update_curr_tid_count(
"""
curr_tid += 1
if filter_.shape == ():
- logger.debug('id: {} has no point to split'.format(idx))
+ logger.debug(f'id: {idx} has no point to split')
move_data.at[idx, label_new_tid] = curr_tid
count += 1
else:
@@ -255,7 +256,7 @@ def _update_curr_tid_count(
def _filter_by(
- move_data: DataFrame, label_id: Text, label_new_tid: Text,
+ move_data: DataFrame, label_id: str, label_new_tid: str,
drop_single_points: bool, **kwargs
) -> DataFrame:
"""
@@ -333,15 +334,15 @@ def _filter_by(
@timer_decorator
def by_dist_time_speed(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- label_id: Text = TRAJ_ID,
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ label_id: str = TRAJ_ID,
max_dist_between_adj_points: float = 3000,
max_time_between_adj_points: float = 900,
max_speed_between_adj_points: float = 50.0,
drop_single_points: bool = True,
- label_new_tid: Text = TID_PART,
+ label_new_tid: str = TID_PART,
inplace: bool = False,
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Splits the trajectories into segments based on distance, time and speed.
@@ -413,13 +414,13 @@ def by_dist_time_speed(
@timer_decorator
def by_max_dist(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- label_id: Text = TRAJ_ID,
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ label_id: str = TRAJ_ID,
max_dist_between_adj_points: float = 3000,
drop_single_points: bool = True,
- label_new_tid: Text = TID_DIST,
+ label_new_tid: str = TID_DIST,
inplace: bool = False,
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Segments the trajectories based on distance.
@@ -480,13 +481,13 @@ def by_max_dist(
@timer_decorator
def by_max_time(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- label_id: Text = TRAJ_ID,
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ label_id: str = TRAJ_ID,
max_time_between_adj_points: float = 900.0,
drop_single_points: bool = True,
- label_new_tid: Text = TID_TIME,
+ label_new_tid: str = TID_TIME,
inplace: bool = False,
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Splits the trajectories into segments based on a maximum.
@@ -548,13 +549,13 @@ def by_max_time(
@timer_decorator
def by_max_speed(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- label_id: Text = TRAJ_ID,
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ label_id: str = TRAJ_ID,
max_speed_between_adj_points: float = 50.0,
drop_single_points: bool = True,
- label_new_tid: Text = TID_SPEED,
+ label_new_tid: str = TID_SPEED,
inplace: bool = False,
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Splits the trajectories into segments based on a maximum speed.
diff --git a/pymove/preprocessing/stay_point_detection.py b/pymove/preprocessing/stay_point_detection.py
index ba819f5f..a7631699 100644
--- a/pymove/preprocessing/stay_point_detection.py
+++ b/pymove/preprocessing/stay_point_detection.py
@@ -5,8 +5,9 @@
create_or_update_move_and_stop_by_radius
"""
+from __future__ import annotations
-from typing import TYPE_CHECKING, Optional, Text, Union
+from typing import TYPE_CHECKING
import numpy as np
@@ -29,13 +30,13 @@
@timer_decorator
def create_or_update_move_stop_by_dist_time(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
dist_radius: float = 30,
time_radius: float = 900,
- label_id: Text = TRAJ_ID,
- new_label: Text = SEGMENT_STOP,
+ label_id: str = TRAJ_ID,
+ new_label: str = SEGMENT_STOP,
inplace: bool = False
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Determines the stops and moves points of the dataframe.
@@ -97,7 +98,7 @@ def create_or_update_move_stop_by_dist_time(
move_dataagg_tid = (
move_data.groupby(by=new_label)
.agg({TIME_TO_PREV: 'sum'})
- .query('%s > %s' % (TIME_TO_PREV, time_radius))
+ .query(f'{TIME_TO_PREV} > {time_radius}')
.index
)
idx = move_data[
@@ -112,12 +113,12 @@ def create_or_update_move_stop_by_dist_time(
@timer_decorator
def create_or_update_move_and_stop_by_radius(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
radius: float = 0,
- target_label: Text = DIST_TO_PREV,
- new_label: Text = SITUATION,
+ target_label: str = DIST_TO_PREV,
+ new_label: str = SITUATION,
inplace: bool = False,
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Finds the stops and moves points of the dataframe.
diff --git a/pymove/query/query.py b/pymove/query/query.py
index 3ea17ee2..aa02915b 100644
--- a/pymove/query/query.py
+++ b/pymove/query/query.py
@@ -5,8 +5,7 @@
knn_query
"""
-
-from typing import Text
+from __future__ import annotations
import numpy as np
import pandas as pd
@@ -20,12 +19,12 @@
def range_query(
traj: DataFrame,
move_df: DataFrame,
- _id: Text = TRAJ_ID,
+ _id: str = TRAJ_ID,
min_dist: float = 1000,
- distance: Text = MEDP,
- latitude: Text = LATITUDE,
- longitude: Text = LONGITUDE,
- datetime: Text = DATETIME
+ distance: str = MEDP,
+ latitude: str = LATITUDE,
+ longitude: str = LONGITUDE,
+ datetime: str = DATETIME
) -> DataFrame:
"""
Returns all trajectories that have a distance equal to or less than the trajectory.
@@ -81,7 +80,7 @@ def dist_measure(traj, this, latitude, longitude, datetime):
raise ValueError('Unknown distance measure. Use MEDP or MEDT')
for traj_id in progress_bar(
- move_df[_id].unique(), desc='Querying range by {}'.format(distance)
+ move_df[_id].unique(), desc=f'Querying range by {distance}'
):
this = move_df.loc[move_df[_id] == traj_id]
if dist_measure(traj, this, latitude, longitude, datetime) < min_dist:
@@ -94,11 +93,11 @@ def knn_query(
traj: DataFrame,
move_df: DataFrame,
k: int = 5,
- id_: Text = TRAJ_ID,
- distance: Text = MEDP,
- latitude: Text = LATITUDE,
- longitude: Text = LONGITUDE,
- datetime: Text = DATETIME
+ id_: str = TRAJ_ID,
+ distance: str = MEDP,
+ latitude: str = LATITUDE,
+ longitude: str = LONGITUDE,
+ datetime: str = DATETIME
) -> DataFrame:
"""
Returns the k neighboring trajectories closest to the trajectory.
@@ -154,7 +153,7 @@ def dist_measure(traj, this, latitude, longitude, datetime):
raise ValueError('Unknown distance measure. Use MEDP or MEDT')
for traj_id in progress_bar(
- move_df[id_].unique(), desc='Querying knn by {}'.format(distance)
+ move_df[id_].unique(), desc=f'Querying knn by {distance}'
):
if (traj_id != traj[id_].values[0]):
this = move_df.loc[move_df[id_] == traj_id]
diff --git a/pymove/semantic/semantic.py b/pymove/semantic/semantic.py
index ab69f96d..5f7e5d65 100644
--- a/pymove/semantic/semantic.py
+++ b/pymove/semantic/semantic.py
@@ -12,8 +12,9 @@
filter_longer_time_to_stop_segment_by_id
"""
+from __future__ import annotations
-from typing import TYPE_CHECKING, Optional, Text, Tuple, Union
+from typing import TYPE_CHECKING
import numpy as np
from pandas import DataFrame
@@ -42,8 +43,8 @@
def _end_create_operation(
- move_data: DataFrame, new_label: Text, inplace: bool
-) -> Optional[DataFrame]:
+ move_data: DataFrame, new_label: str, inplace: bool
+) -> DataFrame | None:
"""
Returns the dataframe after create operation.
@@ -69,8 +70,8 @@ def _end_create_operation(
def _process_simple_filter(
- move_data: DataFrame, new_label: Text, feature: Text, value: float, inplace: bool
-) -> Optional[DataFrame]:
+ move_data: DataFrame, new_label: str, feature: str, value: float, inplace: bool
+) -> DataFrame | None:
"""
Processes create operation with simple filter.
@@ -108,12 +109,12 @@ def _process_simple_filter(
@timer_decorator
def outliers(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
jump_coefficient: float = 3.0,
threshold: float = 1,
- new_label: Text = OUTLIER,
+ new_label: str = OUTLIER,
inplace: bool = False
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Create or update a boolean feature to detect outliers.
@@ -173,10 +174,10 @@ def outliers(
@timer_decorator
def create_or_update_out_of_the_bbox(
move_data: DataFrame,
- bbox: Tuple[int, int, int, int],
- new_label: Text = OUT_BBOX,
+ bbox: tuple[int, int, int, int],
+ new_label: str = OUT_BBOX,
inplace: bool = False
-) -> Optional[DataFrame]:
+) -> DataFrame | None:
"""
Create or update a boolean feature to detect points out of the bbox.
@@ -229,11 +230,11 @@ def create_or_update_out_of_the_bbox(
@timer_decorator
def create_or_update_gps_deactivated_signal(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
max_time_between_adj_points: float = 7200,
- new_label: Text = DEACTIVATED,
+ new_label: str = DEACTIVATED,
inplace: bool = False
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Creates a new feature that inform if point invalid.
@@ -279,11 +280,11 @@ def create_or_update_gps_deactivated_signal(
@timer_decorator
def create_or_update_gps_jump(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
max_dist_between_adj_points: float = 3000,
- new_label: Text = JUMP,
+ new_label: str = JUMP,
inplace: bool = False
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Creates a new feature that inform if point is a gps jump.
@@ -328,15 +329,15 @@ def create_or_update_gps_jump(
@timer_decorator
def create_or_update_short_trajectory(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
max_dist_between_adj_points: float = 3000,
max_time_between_adj_points: float = 7200,
max_speed_between_adj_points: float = 50,
k_segment_max: int = 50,
- label_tid: Text = TID_PART,
- new_label: Text = SHORT,
+ label_tid: str = TID_PART,
+ new_label: str = SHORT,
inplace: bool = False
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Creates a new feature that inform if point belongs to a short trajectory.
@@ -397,12 +398,12 @@ def create_or_update_short_trajectory(
@timer_decorator
def create_or_update_gps_block_signal(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
max_time_stop: float = 7200,
- new_label: Text = BLOCK,
- label_tid: Text = TID_PART,
+ new_label: str = BLOCK,
+ label_tid: str = TID_PART,
inplace: bool = False
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Creates a new feature that inform segments with periods without moving.
@@ -460,13 +461,13 @@ def create_or_update_gps_block_signal(
@timer_decorator
def filter_block_signal_by_repeated_amount_of_points(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
amount_max_of_points_stop: float = 30.0,
max_time_stop: float = 7200,
filter_out: bool = False,
- label_tid: Text = TID_PART,
+ label_tid: str = TID_PART,
inplace: bool = False
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Filters from dataframe points with blocked signal by amount of points.
@@ -521,12 +522,12 @@ def filter_block_signal_by_repeated_amount_of_points(
@timer_decorator
def filter_block_signal_by_time(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
max_time_stop: float = 7200,
filter_out: bool = False,
- label_tid: Text = TID_PART,
+ label_tid: str = TID_PART,
inplace: bool = False
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Filters from dataframe points with blocked signal by time.
@@ -582,14 +583,14 @@ def filter_block_signal_by_time(
@timer_decorator
def filter_longer_time_to_stop_segment_by_id(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
dist_radius: float = 30,
time_radius: float = 900,
- label_id: Text = TRAJ_ID,
- label_segment_stop: Text = SEGMENT_STOP,
+ label_id: str = TRAJ_ID,
+ label_segment_stop: str = SEGMENT_STOP,
filter_out: bool = False,
inplace: bool = False
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Filters from dataframe segment with longest stop time.
diff --git a/pymove/tests/test_visualization_matplotlib.py b/pymove/tests/test_visualization_matplotlib.py
index 8b4e49f6..ddf0644e 100644
--- a/pymove/tests/test_visualization_matplotlib.py
+++ b/pymove/tests/test_visualization_matplotlib.py
@@ -67,7 +67,7 @@ def test_show_object_id_by_date(tmpdir):
def test_plot_trajectory_by_id(tmpdir):
move_df = _default_move_df()
- move_df[TID] = ['1', '1', '2', '2', '2']
+ move_df[TRAJ_ID] = ['1', '1', '2', '2', '2']
d = tmpdir.mkdir('visualization')
diff --git a/pymove/utils/conversions.py b/pymove/utils/conversions.py
index 9cb45b84..fd39efbd 100644
--- a/pymove/utils/conversions.py
+++ b/pymove/utils/conversions.py
@@ -24,10 +24,10 @@
hours_to_seconds
"""
-
+from __future__ import annotations
import math
-from typing import TYPE_CHECKING, List, Optional, Text, Union
+from typing import TYPE_CHECKING
import numpy as np
from numpy import ndarray
@@ -109,7 +109,7 @@ def meters_to_eps(
return radius_meters / earth_radius
-def list_to_str(input_list: List, delimiter: Text = ',') -> Text:
+def list_to_str(input_list: list, delimiter: str = ',') -> str:
"""
Concatenates a list elements, joining them by the separator `delimiter`.
@@ -138,7 +138,7 @@ def list_to_str(input_list: List, delimiter: Text = ',') -> Text:
)
-def list_to_csv_str(input_list: List) -> Text:
+def list_to_csv_str(input_list: list) -> str:
"""
Concatenates the elements of the list, joining them by ",".
@@ -163,7 +163,7 @@ def list_to_csv_str(input_list: List) -> Text:
return list_to_str(input_list)
-def list_to_svm_line(original_list: List) -> Text:
+def list_to_svm_line(original_list: list) -> str:
"""
Concatenates list elements in consecutive element pairs.
@@ -188,11 +188,11 @@ def list_to_svm_line(original_list: List) -> Text:
list_size = len(original_list)
svm_line = '%s ' % original_list[0]
for i in range(1, list_size):
- svm_line += '%s:%s ' % (i, original_list[i])
+ svm_line += f'{i}:{original_list[i]} '
return svm_line.rstrip()
-def lon_to_x_spherical(lon: Union[float, ndarray]) -> Union[float, ndarray]:
+def lon_to_x_spherical(lon: float | ndarray) -> float | ndarray:
"""
Convert longitude to X EPSG:3857 WGS 84/Pseudo-Mercator.
@@ -222,7 +222,7 @@ def lon_to_x_spherical(lon: Union[float, ndarray]) -> Union[float, ndarray]:
return 6378137 * np.radians(lon)
-def lat_to_y_spherical(lat: Union[float, ndarray]) -> Union[float, ndarray]:
+def lat_to_y_spherical(lat: float | ndarray) -> float | ndarray:
"""
Convert latitude to Y EPSG:3857 WGS 84/Pseudo-Mercator.
@@ -252,7 +252,7 @@ def lat_to_y_spherical(lat: Union[float, ndarray]) -> Union[float, ndarray]:
return 6378137 * np.log(np.tan(np.pi / 4 + np.radians(lat) / 2.0))
-def x_to_lon_spherical(x: Union[float, ndarray]) -> Union[float, ndarray]:
+def x_to_lon_spherical(x: float | ndarray) -> float | ndarray:
"""
Convert X EPSG:3857 WGS 84 / Pseudo-Mercator to longitude.
@@ -281,7 +281,7 @@ def x_to_lon_spherical(x: Union[float, ndarray]) -> Union[float, ndarray]:
return np.degrees(x / 6378137.0)
-def y_to_lat_spherical(y: Union[float, ndarray]) -> Union[float, ndarray]:
+def y_to_lat_spherical(y: float | ndarray) -> float | ndarray:
"""
Convert Y EPSG:3857 WGS 84 / Pseudo-Mercator to latitude.
@@ -312,7 +312,7 @@ def y_to_lat_spherical(y: Union[float, ndarray]) -> Union[float, ndarray]:
def geometry_points_to_lat_and_lon(
move_data: DataFrame,
- geometry_label: Text = GEOMETRY,
+ geometry_label: str = GEOMETRY,
drop_geometry: bool = False,
inplace: bool = False
) -> DataFrame:
@@ -369,8 +369,8 @@ def geometry_points_to_lat_and_lon(
def lat_and_lon_decimal_degrees_to_decimal(
move_data: DataFrame,
- latitude: Text = LATITUDE,
- longitude: Text = LONGITUDE
+ latitude: str = LATITUDE,
+ longitude: str = LONGITUDE
) -> DataFrame:
"""
Converts latitude and longitude format from decimal degrees to decimal format.
@@ -419,11 +419,11 @@ def _decimal_degree_to_decimal(row):
def ms_to_kmh(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- label_speed: Text = SPEED_TO_PREV,
- new_label: Text = None,
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ label_speed: str = SPEED_TO_PREV,
+ new_label: str = None,
inplace: bool = False,
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Convert values, in ms, in label_speed column to kmh.
@@ -496,11 +496,11 @@ def ms_to_kmh(
def kmh_to_ms(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- label_speed: Text = SPEED_TO_PREV,
- new_label: Optional[Text] = None,
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ label_speed: str = SPEED_TO_PREV,
+ new_label: str | None = None,
inplace: bool = False,
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Convert values, in kmh, in label_speed column to ms.
@@ -567,11 +567,11 @@ def kmh_to_ms(
def meters_to_kilometers(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- label_distance: Text = DIST_TO_PREV,
- new_label: Optional[Text] = None,
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ label_distance: str = DIST_TO_PREV,
+ new_label: str | None = None,
inplace: bool = False,
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Convert values, in meters, in label_distance column to kilometers.
@@ -637,11 +637,11 @@ def meters_to_kilometers(
def kilometers_to_meters(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- label_distance: Text = DIST_TO_PREV,
- new_label: Optional[Text] = None,
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ label_distance: str = DIST_TO_PREV,
+ new_label: str | None = None,
inplace: bool = False,
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Convert values, in kilometers, in label_distance column to meters.
@@ -708,11 +708,11 @@ def kilometers_to_meters(
def seconds_to_minutes(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- label_time: Text = TIME_TO_PREV,
- new_label: Optional[Text] = None,
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ label_time: str = TIME_TO_PREV,
+ new_label: str | None = None,
inplace: bool = False,
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Convert values, in seconds, in label_distance column to minutes.
@@ -778,11 +778,11 @@ def seconds_to_minutes(
def minute_to_seconds(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- label_time: Text = TIME_TO_PREV,
- new_label: Optional[Text] = None,
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ label_time: str = TIME_TO_PREV,
+ new_label: str | None = None,
inplace: bool = False,
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Convert values, in minutes, in label_distance column to seconds.
@@ -849,11 +849,11 @@ def minute_to_seconds(
def minute_to_hours(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- label_time: Text = TIME_TO_PREV,
- new_label: Optional[Text] = None,
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ label_time: str = TIME_TO_PREV,
+ new_label: str | None = None,
inplace: bool = False,
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Convert values, in minutes, in label_distance column to hours.
@@ -921,11 +921,11 @@ def minute_to_hours(
def hours_to_minute(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- label_time: Text = TIME_TO_PREV,
- new_label: Optional[Text] = None,
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ label_time: str = TIME_TO_PREV,
+ new_label: str | None = None,
inplace: bool = False,
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Convert values, in hours, in label_distance column to minute.
@@ -992,11 +992,11 @@ def hours_to_minute(
def seconds_to_hours(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- label_time: Text = TIME_TO_PREV,
- new_label: Optional[Text] = None,
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ label_time: str = TIME_TO_PREV,
+ new_label: str | None = None,
inplace: bool = False,
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Convert values, in seconds, in label_distance column to hours.
@@ -1063,11 +1063,11 @@ def seconds_to_hours(
def hours_to_seconds(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- label_time: Text = TIME_TO_PREV,
- new_label: Optional[Text] = None,
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ label_time: str = TIME_TO_PREV,
+ new_label: str | None = None,
inplace: bool = False,
-) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]:
+) -> 'PandasMoveDataFrame' | 'DaskMoveDataFrame' | None:
"""
Convert values, in hours, in label_distance column to seconds.
diff --git a/pymove/utils/data_augmentation.py b/pymove/utils/data_augmentation.py
index d5f2e1b5..1bbb2771 100644
--- a/pymove/utils/data_augmentation.py
+++ b/pymove/utils/data_augmentation.py
@@ -11,8 +11,9 @@
instance_crossover_augmentation
"""
+from __future__ import annotations
-from typing import TYPE_CHECKING, Dict, List, Optional, Text, Tuple, Union
+from typing import TYPE_CHECKING
import numpy as np
import pandas as pd
@@ -29,8 +30,8 @@
def append_row(
data: DataFrame,
- row: Optional[Series] = None,
- columns: Optional[Dict] = None
+ row: Series | None = None,
+ columns: dict | None = None
):
"""
Insert a new line in the dataframe with the information passed by parameter.
@@ -56,7 +57,7 @@ def append_row(
def generate_trajectories_df(
- data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame']
+ data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame'
) -> DataFrame:
"""
Generates a dataframe with the sequence of location points of a trajectory.
@@ -105,7 +106,7 @@ def generate_trajectories_df(
def generate_start_feature(
- data: DataFrame, label_trajectory: Text = TRAJECTORY
+ data: DataFrame, label_trajectory: str = TRAJECTORY
):
"""
Removes the last point from the trajectory and adds it in a new column 'destiny'.
@@ -125,7 +126,7 @@ def generate_start_feature(
def generate_destiny_feature(
- data: DataFrame, label_trajectory: Text = TRAJECTORY
+ data: DataFrame, label_trajectory: str = TRAJECTORY
):
"""
Removes the first point from the trajectory and adds it in a new column 'start'.
@@ -145,8 +146,8 @@ def generate_destiny_feature(
def split_crossover(
- sequence_a: List, sequence_b: List, frac: float = 0.5
-) -> Tuple[List, List]:
+ sequence_a: list, sequence_b: list, frac: float = 0.5
+) -> tuple[list, list]:
"""
Divides two arrays in the indicated ratio and exchange their halves.
@@ -239,9 +240,9 @@ def _augmentation(data: DataFrame, aug_df: DataFrame, frac: float = 0.5):
def augmentation_trajectories_df(
- data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- restriction: Text = 'destination only',
- label_trajectory: Text = TRAJECTORY,
+ data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ restriction: str = 'destination only',
+ label_trajectory: str = TRAJECTORY,
insert_at_df: bool = False,
frac: float = 0.5,
) -> DataFrame:
@@ -336,8 +337,8 @@ def insert_points_in_df(data: DataFrame, aug_df: DataFrame):
def instance_crossover_augmentation(
data: DataFrame,
- restriction: Text = 'destination only',
- label_trajectory: Text = TRAJECTORY,
+ restriction: str = 'destination only',
+ label_trajectory: str = TRAJECTORY,
frac: float = 0.5
):
"""
diff --git a/pymove/utils/datetime.py b/pymove/utils/datetime.py
index 7bc6a61a..9ea32068 100644
--- a/pymove/utils/datetime.py
+++ b/pymove/utils/datetime.py
@@ -21,9 +21,9 @@
threshold_time_statistics
"""
+from __future__ import annotations
from datetime import datetime
-from typing import Optional, Text, Union
import holidays
from pandas import DataFrame, Timestamp
@@ -44,7 +44,7 @@
)
-def date_to_str(dt: datetime) -> Text:
+def date_to_str(dt: datetime) -> str:
"""
Get date, in string format, from timestamp.
@@ -73,7 +73,7 @@ def date_to_str(dt: datetime) -> Text:
return dt.strftime('%Y-%m-%d')
-def str_to_datetime(dt_str: Text) -> datetime:
+def str_to_datetime(dt_str: str) -> datetime:
"""
Converts a datetime in string format to datetime format.
@@ -107,7 +107,7 @@ def str_to_datetime(dt_str: Text) -> datetime:
return datetime.strptime(dt_str, '%Y-%m-%d %H:%M:%S')
-def datetime_to_str(dt: datetime) -> Text:
+def datetime_to_str(dt: datetime) -> str:
"""
Converts a date in datetime format to string format.
@@ -221,9 +221,9 @@ def to_day_of_week_int(dt: datetime) -> int:
def working_day(
- dt: Union[Text, datetime],
- country: Text = 'BR',
- state: Optional[Text] = None
+ dt: str | datetime,
+ country: str = 'BR',
+ state: str | None = None
) -> bool:
"""
Indices if a day specified by the user is a working day.
@@ -280,7 +280,7 @@ def working_day(
return result
-def now_str() -> Text:
+def now_str() -> str:
"""
Get datetime of now.
@@ -298,7 +298,7 @@ def now_str() -> Text:
return datetime_to_str(datetime.now())
-def deltatime_str(deltatime_seconds: float) -> Text:
+def deltatime_str(deltatime_seconds: float) -> str:
"""
Convert time in a format appropriate of time.
@@ -327,14 +327,14 @@ def deltatime_str(deltatime_seconds: float) -> Text:
hours, rem = divmod(deltatime_seconds, 3600)
minutes, seconds = divmod(rem, 60)
if hours:
- return '{:0>2}h:{:0>2}m:{:05.2f}s'.format(int(hours), int(minutes), seconds)
+ return f'{int(hours):0>2}h:{int(minutes):0>2}m:{seconds:05.2f}s'
elif minutes:
- return '{:0>2}m:{:05.2f}s'.format(int(minutes), seconds)
+ return f'{int(minutes):0>2}m:{seconds:05.2f}s'
else:
- return '{:05.2f}s'.format(seconds)
+ return f'{seconds:05.2f}s'
-def timestamp_to_millis(timestamp: Text) -> int:
+def timestamp_to_millis(timestamp: str) -> int:
"""
Converts a local datetime to a POSIX timestamp in milliseconds (like in Java).
@@ -380,7 +380,7 @@ def millis_to_timestamp(milliseconds: float) -> Timestamp:
return Timestamp(milliseconds, unit='ms')
-def time_to_str(time: Timestamp) -> Text:
+def time_to_str(time: Timestamp) -> str:
"""
Get time, in string format, from timestamp.
@@ -403,7 +403,7 @@ def time_to_str(time: Timestamp) -> Text:
return time.strftime('%H:%M:%S')
-def str_to_time(dt_str: Text) -> datetime:
+def str_to_time(dt_str: str) -> datetime:
"""
Converts a time in string format "%H:%M:%S" to datetime format.
@@ -491,10 +491,10 @@ def create_time_slot_in_minute(
data: DataFrame,
slot_interval: int = 15,
initial_slot: int = 0,
- label_datetime: Text = DATETIME,
- label_time_slot: Text = TIME_SLOT,
+ label_datetime: str = DATETIME,
+ label_time_slot: str = TIME_SLOT,
inplace: bool = False
-) -> Optional[DataFrame]:
+) -> DataFrame | None:
"""
Partitions the time in slot windows.
@@ -537,7 +537,7 @@ def create_time_slot_in_minute(
3 39.984224 116.319402 2008-10-23 06:10:15 1 24
"""
if data.dtypes[label_datetime] != 'datetime64[ns]':
- raise ValueError('{} colum must be of type datetime'.format(label_datetime))
+ raise ValueError(f'{label_datetime} colum must be of type datetime')
if not inplace:
data = data.copy()
minute_day = data[label_datetime].dt.hour * 60 + data[label_datetime].dt.minute
@@ -548,7 +548,7 @@ def create_time_slot_in_minute(
def generate_time_statistics(
data: DataFrame,
- local_label: Text = LOCAL_LABEL
+ local_label: str = LOCAL_LABEL
):
"""
Calculates time statistics of the pairwise local labels.
@@ -631,7 +631,7 @@ def _calc_time_threshold(seg_mean: float, seg_std: float) -> float:
0.0
"""
threshold = seg_std + seg_mean
- threshold = float('{:.1f}'.format(threshold))
+ threshold = float(f'{threshold:.1f}')
return threshold
@@ -640,7 +640,7 @@ def threshold_time_statistics(
mean_coef: float = 1.0,
std_coef: float = 1.0,
inplace: bool = False
-) -> Optional[DataFrame]:
+) -> DataFrame | None:
"""
Calculates and creates the threshold column.
diff --git a/pymove/utils/distances.py b/pymove/utils/distances.py
index ce27dddc..5c81711f 100644
--- a/pymove/utils/distances.py
+++ b/pymove/utils/distances.py
@@ -8,7 +8,7 @@
medt
"""
-from typing import Text, Union
+from __future__ import annotations
import numpy as np
import pandas as pd
@@ -21,13 +21,13 @@
def haversine(
- lat1: Union[float, ndarray],
- lon1: Union[float, ndarray],
- lat2: Union[float, ndarray],
- lon2: Union[float, ndarray],
+ lat1: float | ndarray,
+ lon1: float | ndarray,
+ lat2: float | ndarray,
+ lon2: float | ndarray,
to_radians: bool = True,
earth_radius: float = EARTH_RADIUS
-) -> Union[float, ndarray]:
+) -> float | ndarray:
"""
Calculates the great circle distance between two points on the earth.
@@ -83,11 +83,11 @@ def haversine(
def euclidean_distance_in_meters(
- lat1: Union[float, ndarray],
- lon1: Union[float, ndarray],
- lat2: Union[float, ndarray],
- lon2: Union[float, ndarray]
-) -> Union[float, ndarray]:
+ lat1: float | ndarray,
+ lon1: float | ndarray,
+ lat2: float | ndarray,
+ lon2: float | ndarray
+) -> float | ndarray:
"""
Calculate the euclidean distance in meters between two points.
@@ -130,8 +130,8 @@ def euclidean_distance_in_meters(
def nearest_points(
traj1: DataFrame,
traj2: DataFrame,
- latitude: Text = LATITUDE,
- longitude: Text = LONGITUDE,
+ latitude: str = LATITUDE,
+ longitude: str = LONGITUDE,
) -> DataFrame:
"""
Returns the point closest to another trajectory based on the Euclidean distance.
@@ -191,8 +191,8 @@ def nearest_points(
def medp(
traj1: DataFrame,
traj2: DataFrame,
- latitude: Text = LATITUDE,
- longitude: Text = LONGITUDE
+ latitude: str = LATITUDE,
+ longitude: str = LONGITUDE
) -> float:
"""
Returns the Mean Euclidian Distance Predictive between two trajectories.
@@ -243,9 +243,9 @@ def medp(
def medt(
traj1: DataFrame,
traj2: DataFrame,
- latitude: Text = LATITUDE,
- longitude: Text = LONGITUDE,
- datetime: Text = DATETIME
+ latitude: str = LATITUDE,
+ longitude: str = LONGITUDE,
+ datetime: str = DATETIME
) -> float:
"""
Returns the Mean Euclidian Distance Trajectory between two trajectories.
diff --git a/pymove/utils/geoutils.py b/pymove/utils/geoutils.py
index 6137e6fd..c7c5086b 100644
--- a/pymove/utils/geoutils.py
+++ b/pymove/utils/geoutils.py
@@ -7,8 +7,7 @@
decode_geohash_to_latlon,
"""
-
-from typing import Text, Tuple
+from __future__ import annotations
import geohash2 as gh
import numpy as np
@@ -30,15 +29,13 @@
BINARY = [
np.asarray(
- list('{0:05b}'.format(x)), dtype=int
+ list(f'{x:05b}'), dtype=int
) for x in range(0, len(BASE_32))
]
-
-
BASE_32_TO_BIN = dict(zip(BASE_32, BINARY))
-def v_color(ob: BaseGeometry) -> Text:
+def v_color(ob: BaseGeometry) -> str:
"""
Returns '#ffcc33' if object crosses otherwise it returns '#6699cc'.
@@ -69,7 +66,7 @@ def v_color(ob: BaseGeometry) -> Text:
return COLORS[ob.is_simple + 33]
-def _encode(lat: float, lon: float, precision: float = 15) -> Text:
+def _encode(lat: float, lon: float, precision: float = 15) -> str:
"""
Encodes latitude/longitude to geohash.
@@ -102,7 +99,7 @@ def _encode(lat: float, lon: float, precision: float = 15) -> Text:
return gh.encode(lat, lon, precision)
-def _decode(geohash: Text) -> Tuple[float, float]:
+def _decode(geohash: str) -> tuple[float, float]:
"""
Decode geohash to latitude/longitude.
@@ -169,7 +166,7 @@ def _bin_geohash(lat: float, lon: float, precision: float = 15) -> ndarray:
def _reset_and_create_arrays_none(
data: DataFrame, reset_index: bool = True
-) -> Tuple[ndarray, ndarray, ndarray, ndarray]:
+) -> tuple[ndarray, ndarray, ndarray, ndarray]:
"""
Reset the df index and create arrays of none values.
@@ -310,7 +307,7 @@ def create_bin_geohash_df(data: DataFrame, precision: float = 15):
def decode_geohash_to_latlon(
data: DataFrame,
- label_geohash: Text = GEOHASH,
+ label_geohash: str = GEOHASH,
reset_index: bool = True
):
"""
@@ -350,7 +347,7 @@ def decode_geohash_to_latlon(
4 39.984217 116.319422 wx4eqyvhyyr2yy8 39.984217 116.319422
"""
if label_geohash not in data:
- raise ValueError('feature {} not in df'.format(label_geohash))
+ raise ValueError(f'feature {label_geohash} not in df')
lat, lon, _, _ = _reset_and_create_arrays_none(data, reset_index=reset_index)
diff --git a/pymove/utils/integration.py b/pymove/utils/integration.py
index 0cedb7ff..44052cef 100644
--- a/pymove/utils/integration.py
+++ b/pymove/utils/integration.py
@@ -15,9 +15,9 @@
merge_home_with_poi
"""
+from __future__ import annotations
from collections import namedtuple
-from typing import List, Optional, Text, Tuple
import numpy as np
from numpy import ndarray
@@ -50,10 +50,10 @@
def union_poi_bank(
data: DataFrame,
- label_poi: Text = TYPE_POI,
- banks: Optional[List[Text]] = None,
+ label_poi: str = TYPE_POI,
+ banks: list[str] | None = None,
inplace: bool = False
-) -> Optional[DataFrame]:
+) -> DataFrame | None:
"""
Performs the union between the different bank categories.
@@ -114,7 +114,7 @@ def union_poi_bank(
if not inplace:
data = data.copy()
logger.debug('union bank categories to one category')
- logger.debug('... There are {} -- {}'.format(data[label_poi].nunique(), label_poi))
+ logger.debug(f'... There are {data[label_poi].nunique()} -- {label_poi}')
if banks is None:
banks = [
'bancos_filiais',
@@ -131,10 +131,10 @@ def union_poi_bank(
def union_poi_bus_station(
data: DataFrame,
- label_poi: Text = TYPE_POI,
- bus_stations: Optional[List[Text]] = None,
+ label_poi: str = TYPE_POI,
+ bus_stations: list[str] | None = None,
inplace: bool = False
-) -> Optional[DataFrame]:
+) -> DataFrame | None:
"""
Performs the union between the different bus station categories.
@@ -203,10 +203,10 @@ def union_poi_bus_station(
def union_poi_bar_restaurant(
data: DataFrame,
- label_poi: Text = TYPE_POI,
- bar_restaurant: Optional[List[Text]] = None,
+ label_poi: str = TYPE_POI,
+ bar_restaurant: list[str] | None = None,
inplace: bool = False
-) -> Optional[DataFrame]:
+) -> DataFrame | None:
"""
Performs the union between bar and restaurant categories.
@@ -270,10 +270,10 @@ def union_poi_bar_restaurant(
def union_poi_parks(
data: DataFrame,
- label_poi: Text = TYPE_POI,
- parks: Optional[List[Text]] = None,
+ label_poi: str = TYPE_POI,
+ parks: list[str] | None = None,
inplace: bool = False
-) -> Optional[DataFrame]:
+) -> DataFrame | None:
"""
Performs the union between park categories.
@@ -337,10 +337,10 @@ def union_poi_parks(
def union_poi_police(
data: DataFrame,
- label_poi: Text = TYPE_POI,
- police: Optional[List[Text]] = None,
+ label_poi: str = TYPE_POI,
+ police: list[str] | None = None,
inplace: bool = False
-) -> Optional[DataFrame]:
+) -> DataFrame | None:
"""
Performs the union between police categories.
@@ -405,9 +405,9 @@ def union_poi_police(
def join_collective_areas(
data: DataFrame,
areas: DataFrame,
- label_geometry: Text = GEOMETRY,
+ label_geometry: str = GEOMETRY,
inplace: bool = False
-) -> Optional[DataFrame]:
+) -> DataFrame | None:
"""
Performs the integration between trajectories and collective areas.
@@ -487,7 +487,7 @@ def _reset_and_creates_id_and_lat_lon(
df_pois: DataFrame,
lat_lon_poi: bool = True,
reset_index: bool = True
-) -> Tuple[ndarray, ndarray, ndarray, ndarray, ndarray]:
+) -> tuple[ndarray, ndarray, ndarray, ndarray, ndarray]:
"""
Resets the indexes of the dataframes.
@@ -555,8 +555,8 @@ def _reset_and_creates_id_and_lat_lon(
def _reset_set_window__and_creates_event_id_type(
- data: DataFrame, df_events: DataFrame, time_window: float, label_date: Text = DATETIME
-) -> Tuple[Series, Series, ndarray, ndarray, ndarray]:
+ data: DataFrame, df_events: DataFrame, time_window: float, label_date: str = DATETIME
+) -> tuple[Series, Series, ndarray, ndarray, ndarray]:
"""
Resets the indexes of the dataframes.
@@ -619,8 +619,8 @@ def _reset_set_window__and_creates_event_id_type(
def _reset_set_window_and_creates_event_id_type_all(
- data: DataFrame, df_events: DataFrame, time_window: float, label_date: Text = DATETIME
-) -> Tuple[Series, Series, ndarray, ndarray, ndarray]:
+ data: DataFrame, df_events: DataFrame, time_window: float, label_date: str = DATETIME
+) -> tuple[Series, Series, ndarray, ndarray, ndarray]:
"""
Resets the indexes of the dataframes.
@@ -685,8 +685,8 @@ def _reset_set_window_and_creates_event_id_type_all(
def join_with_pois(
data: DataFrame,
df_pois: DataFrame,
- label_id: Text = TRAJ_ID,
- label_poi_name: Text = NAME_POI,
+ label_id: str = TRAJ_ID,
+ label_poi_name: str = NAME_POI,
reset_index: bool = True,
inplace: bool = False
):
@@ -806,8 +806,8 @@ def join_with_pois(
def join_with_pois_by_category(
data: DataFrame,
df_pois: DataFrame,
- label_category: Text = TYPE_POI,
- label_id: Text = TRAJ_ID,
+ label_category: str = TYPE_POI,
+ label_id: str = TRAJ_ID,
inplace: bool = False
):
"""
@@ -888,7 +888,7 @@ def join_with_pois_by_category(
df_category = df_pois[df_pois[label_category] == c]
df_category.reset_index(drop=True, inplace=True)
- desc = 'computing dist to {} category ({}/{})'.format(c, i, size_categories)
+ desc = f'computing dist to {c} category ({i}/{size_categories})'
for idx, row in progress_bar(data.iterrows(), total=len(data), desc=desc):
lat_user = np.full(
df_category.shape[0], row[LATITUDE], dtype=np.float64
@@ -923,10 +923,10 @@ def join_with_pois_by_category(
def join_with_events(
data: DataFrame,
df_events: DataFrame,
- label_date: Text = DATETIME,
+ label_date: str = DATETIME,
time_window: int = 900,
- label_event_id: Text = EVENT_ID,
- label_event_type: Text = EVENT_TYPE,
+ label_event_id: str = EVENT_ID,
+ label_event_type: str = EVENT_TYPE,
inplace: bool = False
):
"""
@@ -1070,9 +1070,9 @@ def join_with_events(
def join_with_event_by_dist_and_time(
data: DataFrame,
df_events: DataFrame,
- label_date: Text = DATETIME,
- label_event_id: Text = EVENT_ID,
- label_event_type: Text = EVENT_TYPE,
+ label_date: str = DATETIME,
+ label_event_id: str = EVENT_ID,
+ label_event_type: str = EVENT_TYPE,
time_window: float = 3600,
radius: float = 1000,
inplace: bool = False
@@ -1219,9 +1219,9 @@ def join_with_event_by_dist_and_time(
def join_with_home_by_id(
data: DataFrame,
df_home: DataFrame,
- label_id: Text = TRAJ_ID,
- label_address: Text = ADDRESS,
- label_city: Text = CITY,
+ label_id: str = TRAJ_ID,
+ label_address: str = ADDRESS,
+ label_city: str = CITY,
drop_id_without_home: bool = False,
inplace: bool = False
):
@@ -1288,7 +1288,7 @@ def join_with_home_by_id(
ids_without_home = []
if data.index.name is None:
- logger.debug('...setting {} as index'.format(label_id))
+ logger.debug(f'...setting {label_id} as index')
data.set_index(label_id, inplace=True)
for idx in progress_bar(
@@ -1297,7 +1297,7 @@ def join_with_home_by_id(
filter_home = df_home[label_id] == idx
if df_home[filter_home].shape[0] == 0:
- logger.debug('...id: {} has not HOME'.format(idx))
+ logger.debug(f'...id: {idx} has not HOME')
ids_without_home.append(idx)
else:
home = df_home[filter_home].iloc[0]
@@ -1338,11 +1338,11 @@ def join_with_home_by_id(
def merge_home_with_poi(
data: DataFrame,
- label_dist_poi: Text = DIST_POI,
- label_name_poi: Text = NAME_POI,
- label_id_poi: Text = ID_POI,
- label_home: Text = HOME,
- label_dist_home: Text = DIST_HOME,
+ label_dist_poi: str = DIST_POI,
+ label_name_poi: str = NAME_POI,
+ label_id_poi: str = ID_POI,
+ label_home: str = HOME,
+ label_dist_home: str = DIST_HOME,
drop_columns: bool = True,
inplace: bool = False
):
diff --git a/pymove/utils/log.py b/pymove/utils/log.py
index c8fed867..2603594c 100644
--- a/pymove/utils/log.py
+++ b/pymove/utils/log.py
@@ -6,12 +6,13 @@
timer_decorator
"""
+from __future__ import annotations
import logging
import os
import time
from functools import wraps
-from typing import Callable, Iterable, Optional, Text
+from typing import Callable, Iterable
from IPython import get_ipython
from IPython.display import display
@@ -42,7 +43,7 @@ def wrapper(*args, **kwargs):
t_start = time.time()
result = func(*args, **kwargs)
t_total = deltatime_str(time.time() - t_start)
- message = '%s took %s' % (func.__name__, t_total)
+ message = f'{func.__name__} took {t_total}'
logger.debug('{}\n{}\n{}'.format('*' * len(message), message, '*' * len(message)))
return result
@@ -51,9 +52,9 @@ def wrapper(*args, **kwargs):
def _log_progress(
sequence: Iterable,
- desc: Optional[Text] = None,
- total: Optional[int] = None,
- miniters: Optional[int] = None
+ desc: str | None = None,
+ total: int | None = None,
+ miniters: int | None = None
):
"""
Make and display a progress bar.
@@ -102,10 +103,10 @@ def _log_progress(
for index, record in enumerate(sequence, 1):
if index == 1 or index % miniters == 0:
if is_iterator:
- label.value = '%s: %s / ?' % (desc, index)
+ label.value = f'{desc}: {index} / ?'
else:
progress.value = index
- label.value = u'%s: %s / %s' % (desc, index, total)
+ label.value = f'{desc}: {index} / {total}'
yield record
except Exception:
progress.bar_style = 'danger'
@@ -113,7 +114,7 @@ def _log_progress(
else:
progress.bar_style = 'success'
progress.value = index
- label.value = '%s: %s' % (desc, str(index or '?'))
+ label.value = '{}: {}'.format(desc, str(index or '?'))
try:
@@ -127,9 +128,9 @@ def _log_progress(
def progress_bar(
sequence: Iterable,
- desc: Optional[Text] = None,
- total: Optional[int] = None,
- miniters: Optional[int] = None
+ desc: str | None = None,
+ total: int | None = None,
+ miniters: int | None = None
):
"""
Make and display a progress bar.
diff --git a/pymove/utils/math.py b/pymove/utils/math.py
index 14dd4b94..f03b3e80 100644
--- a/pymove/utils/math.py
+++ b/pymove/utils/math.py
@@ -11,12 +11,12 @@
interpolation
"""
+from __future__ import annotations
import math
-from typing import List, Optional, Tuple, Union
-def is_number(value: Union[int, float, str]):
+def is_number(value: int | float | str):
"""
Returns if value is numerical or not.
@@ -49,7 +49,7 @@ def is_number(value: Union[int, float, str]):
return True
-def std(values_array: List[float]) -> float:
+def std(values_array: list[float]) -> float:
"""
Compute standard deviation.
@@ -77,12 +77,12 @@ def std(values_array: List[float]) -> float:
"""
size = len(values_array)
mean = sum(values_array) / size
- sum_sq = sum([(i - mean) * (i - mean) for i in values_array])
+ sum_sq = sum((i - mean) * (i - mean) for i in values_array)
return math.sqrt(sum_sq / size)
-def avg_std(values_array: List[float]) -> Tuple[float, float]:
+def avg_std(values_array: list[float]) -> tuple[float, float]:
"""
Compute the average of standard deviation.
@@ -109,7 +109,7 @@ def avg_std(values_array: List[float]) -> Tuple[float, float]:
return avg, std(values_array)
-def std_sample(values_array: List[float]) -> float:
+def std_sample(values_array: list[float]) -> float:
"""
Compute the standard deviation of sample.
@@ -134,7 +134,7 @@ def std_sample(values_array: List[float]) -> float:
return std(values_array) * math.sqrt(size / (size - 1))
-def avg_std_sample(values_array: List[float]) -> Tuple[float, float]:
+def avg_std_sample(values_array: list[float]) -> tuple[float, float]:
"""
Compute the average of standard deviation of sample.
@@ -162,7 +162,7 @@ def avg_std_sample(values_array: List[float]) -> Tuple[float, float]:
def arrays_avg(
- values_array: List[float], weights_array: Optional[List[float]] = None
+ values_array: list[float], weights_array: list[float] | None = None
) -> float:
"""
Computes the mean of the elements of the array.
@@ -211,7 +211,7 @@ def arrays_avg(
return result / n
-def array_stats(values_array: List[float]) -> Tuple[float, float, int]:
+def array_stats(values_array: list[float]) -> tuple[float, float, int]:
"""
Computes statistics about the array.
diff --git a/pymove/utils/mem.py b/pymove/utils/mem.py
index f67b26ae..c5194484 100644
--- a/pymove/utils/mem.py
+++ b/pymove/utils/mem.py
@@ -9,6 +9,7 @@
top_mem_vars
"""
+from __future__ import annotations
import os
import re
@@ -16,7 +17,6 @@
from collections import deque
from itertools import chain
from sys import getsizeof
-from typing import Dict, Text
import numpy as np
import psutil
@@ -52,7 +52,7 @@ def reduce_mem_usage_automatic(df: DataFrame):
dtype: object
"""
start_mem = df.memory_usage().sum() / 1024 ** 2
- logger.info('Memory usage of dataframe is {:.2f} MB'.format(start_mem))
+ logger.info(f'Memory usage of dataframe is {start_mem:.2f} MB')
for col in df.columns:
col_type = df[col].dtype
@@ -113,14 +113,14 @@ def reduce_mem_usage_automatic(df: DataFrame):
df[col] = df[col].astype(np.float64)
end_mem = df.memory_usage().sum() / 1024 ** 2
- logger.info('Memory usage after optimization is: {:.2f} MB'.format(end_mem))
+ logger.info(f'Memory usage after optimization is: {end_mem:.2f} MB')
logger.info(
- 'Decreased by {:.1f} %'.format(100 * (start_mem - end_mem) / start_mem)
+ f'Decreased by {100 * (start_mem - end_mem) / start_mem:.1f} %'
)
def total_size(
- o: object, handlers: Dict = None, verbose: bool = True
+ o: object, handlers: dict = None, verbose: bool = True
) -> float:
"""
Calculates the approximate memory footprint of an given object.
@@ -195,14 +195,14 @@ def sizeof(o):
if verbose:
- logger.info('Size in bytes: {}, Type: {}'.format(s, type(o)))
+ logger.info(f'Size in bytes: {s}, Type: {type(o)}')
return s
return sizeof(o)
-def begin_operation(name: Text) -> Dict:
+def begin_operation(name: str) -> dict:
"""
Gets the stats for the current operation.
@@ -233,7 +233,7 @@ def begin_operation(name: Text) -> Dict:
return {'process': process, 'init': init, 'start': start, 'name': name}
-def end_operation(operation: Dict) -> Dict:
+def end_operation(operation: dict) -> dict:
"""
Gets the time and memory usage of the operation.
@@ -269,7 +269,7 @@ def end_operation(operation: Dict) -> Dict:
}
-def sizeof_fmt(mem_usage: float, suffix: Text = 'B') -> Text:
+def sizeof_fmt(mem_usage: float, suffix: str = 'B') -> str:
"""
Returns the memory usage calculation of the last function.
@@ -295,13 +295,13 @@ def sizeof_fmt(mem_usage: float, suffix: Text = 'B') -> Text:
"""
for unit in ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi']:
if abs(mem_usage) < 1024.0:
- return '{:3.1f} {}{}'.format(mem_usage, unit, suffix)
+ return f'{mem_usage:3.1f} {unit}{suffix}'
mem_usage /= 1024.0
return '{:.1f} {}{}'.format(mem_usage, 'Yi', suffix)
def top_mem_vars(
- variables: Dict, n: int = 10, hide_private=True
+ variables: dict, n: int = 10, hide_private=True
) -> DataFrame:
"""
Shows the sizes of the active variables.
diff --git a/pymove/utils/trajectories.py b/pymove/utils/trajectories.py
index 7b2036a9..bfa989b5 100644
--- a/pymove/utils/trajectories.py
+++ b/pymove/utils/trajectories.py
@@ -11,10 +11,10 @@
column_to_array
"""
-
+from __future__ import annotations
from itertools import chain
-from typing import Any, Dict, List, Optional, Text, Tuple, Union
+from typing import Any
import numpy as np
from numpy import ndarray
@@ -29,11 +29,11 @@
def read_csv(
filepath_or_buffer: FilePathOrBuffer,
- latitude: Text = LATITUDE,
- longitude: Text = LONGITUDE,
- datetime: Text = DATETIME,
- traj_id: Text = TRAJ_ID,
- type_: Text = TYPE_PANDAS,
+ latitude: str = LATITUDE,
+ longitude: str = LONGITUDE,
+ datetime: str = DATETIME,
+ traj_id: str = TRAJ_ID,
+ type_: str = TYPE_PANDAS,
n_partitions: int = 1,
**kwargs
) -> MoveDataFrame:
@@ -94,7 +94,7 @@ def read_csv(
)
-def invert_dict(d: Dict) -> Dict:
+def invert_dict(d: dict) -> dict:
"""
Inverts the key:value relation of a dictionary.
@@ -119,10 +119,10 @@ def invert_dict(d: Dict) -> Dict:
def flatten_dict(
- d: Dict,
- parent_key: Text = '',
- sep: Text = '_'
-) -> Dict:
+ d: dict,
+ parent_key: str = '',
+ sep: str = '_'
+) -> dict:
"""
Flattens a nested dictionary.
@@ -153,7 +153,7 @@ def flatten_dict(
"""
if not isinstance(d, dict):
return {parent_key: d}
- items: List[Tuple[Text, Any]] = []
+ items: list[tuple[str, Any]] = []
for k, v in d.items():
new_key = f'{parent_key}{sep}{k}' if parent_key else k
if isinstance(v, dict):
@@ -163,7 +163,7 @@ def flatten_dict(
return dict(items)
-def flatten_columns(data: DataFrame, columns: List) -> DataFrame:
+def flatten_columns(data: DataFrame, columns: list) -> DataFrame:
"""
Transforms columns containing dictionaries in individual columns.
@@ -223,9 +223,9 @@ def flatten_columns(data: DataFrame, columns: List) -> DataFrame:
def shift(
- arr: Union[List, Series, ndarray],
+ arr: list | Series | ndarray,
num: int,
- fill_value: Optional[Any] = None
+ fill_value: Any | None = None
) -> ndarray:
"""
Shifts the elements of the given array by the number of periods specified.
@@ -288,7 +288,7 @@ def shift(
return result
-def fill_list_with_new_values(original_list: List, new_list_values: List):
+def fill_list_with_new_values(original_list: list, new_list_values: list):
"""
Copies elements from one list to another.
@@ -314,7 +314,7 @@ def fill_list_with_new_values(original_list: List, new_list_values: List):
original_list[:n] = new_list_values
-def object_for_array(object_: Text) -> ndarray:
+def object_for_array(object_: str) -> ndarray:
"""
Transforms an object into an array.
@@ -346,7 +346,7 @@ def object_for_array(object_: Text) -> ndarray:
return conv.astype('object_')
-def column_to_array(data: DataFrame, column: Text) -> DataFrame:
+def column_to_array(data: DataFrame, column: str) -> DataFrame:
"""
Transforms all columns values to list.
diff --git a/pymove/utils/visual.py b/pymove/utils/visual.py
index 80d0a36f..4f10bd5e 100644
--- a/pymove/utils/visual.py
+++ b/pymove/utils/visual.py
@@ -10,8 +10,9 @@
save_wkt
"""
+from __future__ import annotations
-from typing import Sequence, Text, Tuple, Union
+from typing import Sequence
from branca.element import MacroElement, Template
from folium import Map
@@ -23,7 +24,7 @@
from pymove.utils.constants import COLORS, LATITUDE, LONGITUDE, TRAJ_ID
-def add_map_legend(m: Map, title: Text, items: Union[Tuple, Sequence[Tuple]]):
+def add_map_legend(m: Map, title: str, items: tuple | Sequence[tuple]):
"""
Adds a legend for a folium map.
@@ -202,7 +203,7 @@ def add_map_legend(m: Map, title: Text, items: Union[Tuple, Sequence[Tuple]]):
m.get_root().add_child(macro, name='map_legend')
-def generate_color() -> Text:
+def generate_color() -> str:
"""
Generates a random color.
@@ -221,7 +222,7 @@ def generate_color() -> Text:
return COLORS[randint(0, len(COLORS))]
-def rgb(rgb_colors: Tuple[float, float, float]) -> Tuple[int, int, int]:
+def rgb(rgb_colors: tuple[float, float, float]) -> tuple[int, int, int]:
"""
Return a tuple of integers, as used in AWT/Java plots.
@@ -250,7 +251,7 @@ def rgb(rgb_colors: Tuple[float, float, float]) -> Tuple[int, int, int]:
return int(red * 255), int(green * 255), int(blue * 255)
-def hex_rgb(rgb_colors: Tuple[float, float, float]) -> Text:
+def hex_rgb(rgb_colors: tuple[float, float, float]) -> str:
"""
Return a hex str, as used in Tk plots.
@@ -276,7 +277,7 @@ def hex_rgb(rgb_colors: Tuple[float, float, float]) -> Text:
return '#%02X%02X%02X' % rgb(rgb_colors)
-def cmap_hex_color(cmap: ListedColormap, i: int) -> Text:
+def cmap_hex_color(cmap: ListedColormap, i: int) -> str:
"""
Convert a Colormap to hex color.
@@ -305,7 +306,7 @@ def cmap_hex_color(cmap: ListedColormap, i: int) -> Text:
return rgb2hex(cmap(i))
-def get_cmap(cmap: Text) -> Colormap:
+def get_cmap(cmap: str) -> Colormap:
"""
Returns a matplotlib colormap instance.
@@ -329,7 +330,7 @@ def get_cmap(cmap: Text) -> Colormap:
def save_wkt(
- move_data: DataFrame, filename: Text, label_id: Text = TRAJ_ID
+ move_data: DataFrame, filename: str, label_id: str = TRAJ_ID
):
"""
Save a visualization in a map in a new file .wkt.
@@ -370,7 +371,7 @@ def save_wkt(
move_df = move_data[move_data[label_id] == id_]
curr_str = '%s;LINESTRING(' % id_
curr_str += ','.join(
- '%s %s' % (x[0], x[1])
+ f'{x[0]} {x[1]}'
for x in move_df[[LONGITUDE, LATITUDE]].values
)
curr_str += ')\n'
diff --git a/pymove/visualization/folium.py b/pymove/visualization/folium.py
index 3e057d9b..07bf43b6 100644
--- a/pymove/visualization/folium.py
+++ b/pymove/visualization/folium.py
@@ -22,9 +22,10 @@
plot_traj_timestamp_geo_json
"""
+from __future__ import annotations
from datetime import date
-from typing import Any, Dict, List, Optional, Sequence, Text, Tuple, Union
+from typing import Any, Sequence
import folium
import numpy as np
@@ -38,11 +39,9 @@
DATE,
DATETIME,
DAY,
- EVENT_ID,
EVENT_POINT,
HOUR,
LATITUDE,
- LINE_COLOR,
LONGITUDE,
PERIOD,
POI_POINT,
@@ -50,7 +49,6 @@
STOP,
TILES,
TRAJ_ID,
- UID,
USER_POINT,
)
from pymove.utils.datetime import str_to_datetime
@@ -60,12 +58,12 @@
def save_map(
move_data: DataFrame,
- filename: Text,
- tiles: Text = TILES[0],
- label_id: Text = TRAJ_ID,
- cmap: Text = 'Set1',
+ filename: str,
+ tiles: str = TILES[0],
+ label_id: str = TRAJ_ID,
+ cmap: str = 'Set1',
return_map: bool = False
-) -> Optional[Map]:
+) -> Map | None:
"""
Save a visualization in a map in a new file.
@@ -130,9 +128,9 @@ def save_map(
def create_base_map(
move_data: DataFrame,
- lat_origin: Optional[float] = None,
- lon_origin: Optional[float] = None,
- tile: Text = TILES[0],
+ lat_origin: float | None = None,
+ lon_origin: float | None = None,
+ tile: str = TILES[0],
default_zoom_start: float = 12,
) -> Map:
"""
@@ -182,15 +180,15 @@ def create_base_map(
def heatmap(
move_data: DataFrame,
- n_rows: Optional[int] = None,
- lat_origin: Optional[float] = None,
- lon_origin: Optional[float] = None,
+ n_rows: int | None = None,
+ lat_origin: float | None = None,
+ lon_origin: float | None = None,
zoom_start: float = 12,
radius: float = 8,
- base_map: Optional[Map] = None,
- tile: Text = TILES[0],
+ base_map: Map | None = None,
+ tile: str = TILES[0],
save_as_html: bool = False,
- filename: Text = 'heatmap.html',
+ filename: str = 'heatmap.html',
) -> Map:
"""
Generate visualization of Heat Map using folium plugin.
@@ -267,17 +265,17 @@ def heatmap(
def heatmap_with_time(
move_data: DataFrame,
- n_rows: Optional[int] = None,
- lat_origin: Optional[float] = None,
- lon_origin: Optional[float] = None,
+ n_rows: int | None = None,
+ lat_origin: float | None = None,
+ lon_origin: float | None = None,
zoom_start: float = 12,
radius: float = 8,
min_opacity: float = 0.5,
max_opacity: float = 0.8,
- base_map: Optional[Map] = None,
- tile: Text = TILES[0],
+ base_map: Map | None = None,
+ tile: str = TILES[0],
save_as_html: bool = False,
- filename: Text = 'heatmap_time.html',
+ filename: str = 'heatmap_time.html',
) -> Map:
"""
Generate visualization of Heat Map using folium plugin.
@@ -371,14 +369,14 @@ def heatmap_with_time(
def cluster(
move_data: DataFrame,
- n_rows: Optional[int] = None,
- lat_origin: Optional[float] = None,
- lon_origin: Optional[float] = None,
+ n_rows: int | None = None,
+ lat_origin: float | None = None,
+ lon_origin: float | None = None,
zoom_start: float = 12,
- base_map: Optional[Map] = None,
- tile: Text = TILES[0],
+ base_map: Map | None = None,
+ tile: str = TILES[0],
save_as_html: bool = False,
- filename: Text = 'cluster.html',
+ filename: str = 'cluster.html',
) -> Map:
"""
Generate visualization of Heat Map using folium plugin.
@@ -461,14 +459,14 @@ def cluster(
def faster_cluster(
move_data: DataFrame,
- n_rows: Optional[int] = None,
- lat_origin: Optional[float] = None,
- lon_origin: Optional[float] = None,
+ n_rows: int | None = None,
+ lat_origin: float | None = None,
+ lon_origin: float | None = None,
zoom_start: float = 12,
- base_map: Optional[Map] = None,
- tile: Text = TILES[0],
+ base_map: Map | None = None,
+ tile: str = TILES[0],
save_as_html: bool = False,
- filename: Text = 'faster_cluster.html',
+ filename: str = 'faster_cluster.html',
) -> Map:
"""
Generate visualization of Heat Map using folium plugin.
@@ -546,14 +544,14 @@ def faster_cluster(
def plot_markers(
move_data: DataFrame,
- n_rows: Optional[int] = None,
- lat_origin: Optional[float] = None,
- lon_origin: Optional[float] = None,
+ n_rows: int | None = None,
+ lat_origin: float | None = None,
+ lon_origin: float | None = None,
zoom_start: float = 12,
- base_map: Optional[Map] = None,
- tile: Text = TILES[0],
+ base_map: Map | None = None,
+ tile: str = TILES[0],
save_as_html: bool = False,
- filename: Text = 'markers.html',
+ filename: str = 'markers.html',
) -> Map:
"""
Generate visualization of Heat Map using folium plugin.
@@ -646,11 +644,11 @@ def plot_markers(
def _filter_and_generate_colors(
move_data: DataFrame,
- id_: Optional[int] = None,
- n_rows: Optional[int] = None,
- color: Optional[Union[Text, List[Text]]] = None,
- color_by_id: Optional[Dict] = None
-) -> Tuple[DataFrame, List[Tuple[Any, Any]]]:
+ id_: int | None = None,
+ n_rows: int | None = None,
+ color: str | list[str] | None = None,
+ color_by_id: dict | None = None
+) -> tuple[DataFrame, list[tuple[Any, Any]]]:
"""
Filters the dataframe and generate colors for folium map.
@@ -744,7 +742,7 @@ def _filter_and_generate_colors(
def _filter_generated_feature(
- move_data: DataFrame, feature: Text, values: Any
+ move_data: DataFrame, feature: str, values: Any
) -> DataFrame:
"""
Filters the values from the dataframe.
@@ -795,8 +793,8 @@ def _filter_generated_feature(
def _add_begin_end_markers_to_map(
move_data: DataFrame,
base_map: Map,
- color: Optional[Text] = None,
- _id: Optional[int] = None
+ color: str | None = None,
+ _id: int | None = None
):
"""
Adds markers to the beggining and end of a trajectory.
@@ -857,11 +855,11 @@ def _add_begin_end_markers_to_map(
def _add_trajectories_to_map(
move_data: DataFrame,
- items: Sequence[Tuple],
+ items: Sequence[tuple],
base_map: Map,
legend: bool = True,
save_as_html: bool = True,
- filename: Text = 'map.html',
+ filename: str = 'map.html',
):
"""
Adds a trajectory to a folium map with begin and end markers.
@@ -914,17 +912,17 @@ def _add_trajectories_to_map(
def plot_trajectories(
move_data: DataFrame,
- n_rows: Optional[int] = None,
- lat_origin: Optional[float] = None,
- lon_origin: Optional[float] = None,
+ n_rows: int | None = None,
+ lat_origin: float | None = None,
+ lon_origin: float | None = None,
zoom_start: float = 12,
legend: bool = True,
- base_map: Optional[Map] = None,
- tile: Text = TILES[0],
+ base_map: Map | None = None,
+ tile: str = TILES[0],
save_as_html: bool = False,
- color: Optional[Union[Text, List[Text]]] = None,
- color_by_id: Optional[Dict] = None,
- filename: Text = 'plot_trajectories.html',
+ color: str | list[str] | None = None,
+ color_by_id: dict | None = None,
+ filename: str = 'plot_trajectories.html',
) -> Map:
"""
Generate visualization of all trajectories with folium.
@@ -1003,16 +1001,16 @@ def plot_trajectories(
def plot_trajectory_by_id(
move_data: DataFrame,
id_: int,
- n_rows: Optional[int] = None,
- lat_origin: Optional[float] = None,
- lon_origin: Optional[float] = None,
+ n_rows: int | None = None,
+ lat_origin: float | None = None,
+ lon_origin: float | None = None,
zoom_start: float = 12,
legend: bool = True,
- base_map: Optional[Map] = None,
- tile: Text = TILES[0],
+ base_map: Map | None = None,
+ tile: str = TILES[0],
save_as_html: bool = False,
- color: Optional[Union[Text, List[Text]]] = None,
- filename: Text = 'plot_trajectories.html',
+ color: str | list[str] | None = None,
+ filename: str = 'plot_trajectories.html',
) -> Map:
"""
Generate visualization of all trajectories with folium.
@@ -1091,19 +1089,19 @@ def plot_trajectory_by_id(
def plot_trajectory_by_period(
move_data: PandasMoveDataFrame,
- period: Text,
- id_: Optional[int] = None,
- n_rows: Optional[int] = None,
- lat_origin: Optional[float] = None,
- lon_origin: Optional[float] = None,
+ period: str,
+ id_: int | None = None,
+ n_rows: int | None = None,
+ lat_origin: float | None = None,
+ lon_origin: float | None = None,
zoom_start: float = 12,
legend: bool = True,
- base_map: Optional[Map] = None,
- tile: Text = TILES[0],
+ base_map: Map | None = None,
+ tile: str = TILES[0],
save_as_html: bool = False,
- color: Optional[Union[Text, List[Text]]] = None,
- color_by_id: Optional[Dict] = None,
- filename: Text = 'plot_trajectories_by_period.html',
+ color: str | list[str] | None = None,
+ color_by_id: dict | None = None,
+ filename: str = 'plot_trajectories_by_period.html',
) -> Map:
"""
Generate visualization of all trajectories with folium.
@@ -1196,19 +1194,19 @@ def plot_trajectory_by_period(
def plot_trajectory_by_day_week(
move_data: PandasMoveDataFrame,
- day_week: Text,
- id_: Optional[int] = None,
- n_rows: Optional[int] = None,
- lat_origin: Optional[float] = None,
- lon_origin: Optional[float] = None,
+ day_week: str,
+ id_: int | None = None,
+ n_rows: int | None = None,
+ lat_origin: float | None = None,
+ lon_origin: float | None = None,
zoom_start: float = 12,
legend: bool = True,
- base_map: Optional[Map] = None,
- tile: Text = TILES[0],
+ base_map: Map | None = None,
+ tile: str = TILES[0],
save_as_html: bool = False,
- color: Optional[Union[Text, List[Text]]] = None,
- color_by_id: Optional[Dict] = None,
- filename: Text = 'plot_trajectories_by_day_week.html',
+ color: str | list[str] | None = None,
+ color_by_id: dict | None = None,
+ filename: str = 'plot_trajectories_by_day_week.html',
) -> Map:
"""
Generate visualization of all trajectories with folium.
@@ -1301,20 +1299,20 @@ def plot_trajectory_by_day_week(
def plot_trajectory_by_date(
move_data: PandasMoveDataFrame,
- start_date: Union[Text, date],
- end_date: Union[Text, date],
- id_: Optional[int] = None,
- n_rows: Optional[int] = None,
- lat_origin: Optional[float] = None,
- lon_origin: Optional[float] = None,
+ start_date: str | date,
+ end_date: str | date,
+ id_: int | None = None,
+ n_rows: int | None = None,
+ lat_origin: float | None = None,
+ lon_origin: float | None = None,
zoom_start: float = 12,
legend: bool = True,
- base_map: Optional[Map] = None,
- tile: Text = TILES[0],
+ base_map: Map | None = None,
+ tile: str = TILES[0],
save_as_html: bool = False,
- color: Optional[Union[Text, List[Text]]] = None,
- color_by_id: Optional[Dict] = None,
- filename: Text = 'plot_trajectories_by_date.html',
+ color: str | list[str] | None = None,
+ color_by_id: dict | None = None,
+ filename: str = 'plot_trajectories_by_date.html',
) -> Map:
"""
Generate visualization of all trajectories with folium.
@@ -1419,20 +1417,20 @@ def plot_trajectory_by_date(
def plot_trajectory_by_hour(
move_data: PandasMoveDataFrame,
- start_hour: Text,
- end_hour: Text,
- id_: Optional[int] = None,
- n_rows: Optional[int] = None,
- lat_origin: Optional[float] = None,
- lon_origin: Optional[float] = None,
+ start_hour: str,
+ end_hour: str,
+ id_: int | None = None,
+ n_rows: int | None = None,
+ lat_origin: float | None = None,
+ lon_origin: float | None = None,
zoom_start: float = 12,
legend: bool = True,
- base_map: Optional[Map] = None,
- tile: Text = TILES[0],
+ base_map: Map | None = None,
+ tile: str = TILES[0],
save_as_html: bool = False,
- color: Optional[Union[Text, List[Text]]] = None,
- color_by_id: Optional[Dict] = None,
- filename: Text = 'plot_trajectories_by_hour.html',
+ color: str | list[str] | None = None,
+ color_by_id: dict | None = None,
+ filename: str = 'plot_trajectories_by_hour.html',
) -> Map:
"""
Generate visualization of all trajectories with folium.
@@ -1529,17 +1527,17 @@ def plot_stops(
move_data: PandasMoveDataFrame,
radius: float = 0,
weight: float = 3,
- id_: Optional[int] = None,
- n_rows: Optional[int] = None,
- lat_origin: Optional[float] = None,
- lon_origin: Optional[float] = None,
+ id_: int | None = None,
+ n_rows: int | None = None,
+ lat_origin: float | None = None,
+ lon_origin: float | None = None,
zoom_start: float = 12,
legend: bool = True,
- base_map: Optional[Map] = None,
- tile: Text = TILES[0],
+ base_map: Map | None = None,
+ tile: str = TILES[0],
save_as_html: bool = False,
- color: Optional[Union[Text, List[Text]]] = None,
- filename: Text = 'plot_stops.html',
+ color: str | list[str] | None = None,
+ filename: str = 'plot_stops.html',
) -> Map:
"""
Generate visualization of all trajectories with folium.
@@ -1649,12 +1647,12 @@ def plot_stops(
def plot_bbox(
- bbox_tuple: Tuple[float, float, float, float],
- base_map: Optional[Map] = None,
- tiles: Text = TILES[0],
- color: Text = 'red',
+ bbox_tuple: tuple[float, float, float, float],
+ base_map: Map | None = None,
+ tiles: str = TILES[0],
+ color: str = 'red',
save_as_html: bool = False,
- filename: Text = 'bbox.html'
+ filename: str = 'bbox.html'
) -> Map:
"""
Plots a bbox using Folium.
@@ -1707,7 +1705,7 @@ def plot_bbox(
return base_map
-def _format_tags(line: Union[List, Dict], slice_: List) -> Text:
+def _format_tags(line: list | dict, slice_: list) -> str:
"""
Create or format tags.
@@ -1742,17 +1740,17 @@ def _format_tags(line: Union[List, Dict], slice_: List) -> Text:
>>> )
lat: 39.984094
lon: 116.319236
datetime: 2008-10-23 05:53:05
id: 1
"""
- map_formated_tags = map(lambda tag: '{}: {}'.format(tag, line[tag]), slice_)
+ map_formated_tags = map(lambda tag: f'{tag}: {line[tag]}', slice_)
return '
'.join(map_formated_tags)
def _circle_maker(
iter_tuple: DataFrame,
- user_lat: Text,
- user_lon: Text,
- slice_tags: List,
- user_point: Text,
+ user_lat: str,
+ user_lon: str,
+ slice_tags: list,
+ user_point: str,
radius: float,
map_: Map
):
@@ -1814,15 +1812,15 @@ def _circle_maker(
def plot_points(
move_data: DataFrame,
- user_lat: Text = LATITUDE,
- user_lon: Text = LONGITUDE,
- user_point: Text = USER_POINT,
+ user_lat: str = LATITUDE,
+ user_lon: str = LONGITUDE,
+ user_point: str = USER_POINT,
radius: float = 2,
- base_map: Optional[Map] = None,
- slice_tags: Optional[List] = None,
- tiles: Text = TILES[0],
+ base_map: Map | None = None,
+ slice_tags: list | None = None,
+ tiles: str = TILES[0],
save_as_html: bool = False,
- filename: Text = 'points.html'
+ filename: str = 'points.html'
) -> Map:
"""
Generates a folium map with the trajectories plots and a point.
@@ -1901,15 +1899,15 @@ def plot_points(
def plot_poi(
move_data: DataFrame,
- poi_lat: Text = LATITUDE,
- poi_lon: Text = LONGITUDE,
- poi_point: Text = POI_POINT,
+ poi_lat: str = LATITUDE,
+ poi_lon: str = LONGITUDE,
+ poi_point: str = POI_POINT,
radius: float = 2,
- base_map: Optional[Map] = None,
- slice_tags: Optional[List] = None,
- tiles: Text = TILES[0],
+ base_map: Map | None = None,
+ slice_tags: list | None = None,
+ tiles: str = TILES[0],
save_as_html: bool = False,
- filename: Text = 'pois.html'
+ filename: str = 'pois.html'
) -> Map:
"""
Receives a MoveDataFrame and returns a folium map with poi points.
@@ -1970,15 +1968,15 @@ def plot_poi(
def plot_event(
move_data: DataFrame,
- event_lat: Text = LATITUDE,
- event_lon: Text = LONGITUDE,
- event_point: Text = EVENT_POINT,
+ event_lat: str = LATITUDE,
+ event_lon: str = LONGITUDE,
+ event_point: str = EVENT_POINT,
radius: float = 2,
- base_map: Optional[Map] = None,
- slice_tags: Optional[List] = None,
- tiles: Text = TILES[0],
+ base_map: Map | None = None,
+ slice_tags: list | None = None,
+ tiles: str = TILES[0],
save_as_html: bool = False,
- filename: Text = 'events.html'
+ filename: str = 'events.html'
) -> Map:
"""
Receives a MoveDataFrame and returns a folium map with events.
@@ -2036,10 +2034,10 @@ def plot_event(
def _create_geojson_features_line(
move_data: DataFrame,
- label_lat: Text = LATITUDE,
- label_lon: Text = LONGITUDE,
- label_datetime: Text = DATETIME
-) -> List:
+ label_lat: str = LATITUDE,
+ label_lon: str = LONGITUDE,
+ label_datetime: str = DATETIME
+) -> list:
"""
Create geojson features.
@@ -2155,12 +2153,12 @@ def _create_geojson_features_line(
def plot_traj_timestamp_geo_json(
move_data: DataFrame,
- label_lat: Text = LATITUDE,
- label_lon: Text = LONGITUDE,
- label_datetime: Text = DATETIME,
- tiles: Text = TILES[0],
+ label_lat: str = LATITUDE,
+ label_lon: str = LONGITUDE,
+ label_datetime: str = DATETIME,
+ tiles: str = TILES[0],
save_as_html: bool = False,
- filename: Text = 'events.html'
+ filename: str = 'events.html'
) -> Map:
"""
Plot trajectories wit geo_json.
diff --git a/pymove/visualization/matplotlib.py b/pymove/visualization/matplotlib.py
index ec45a4dd..e72de5ba 100644
--- a/pymove/visualization/matplotlib.py
+++ b/pymove/visualization/matplotlib.py
@@ -4,14 +4,16 @@
show_object_id_by_date,
plot_trajectories,
plot_trajectory_by_id,
+plot_grid_polygons,
plot_all_features
plot_coords,
plot_bounds,
plot_line
"""
+from __future__ import annotations
-from typing import TYPE_CHECKING, Any, Callable, List, Optional, Text, Tuple, Union
+from typing import TYPE_CHECKING, Any, Callable
import matplotlib.pyplot as plt
from matplotlib.pyplot import axes, figure
@@ -19,6 +21,7 @@
from shapely.geometry import LineString, MultiLineString
from shapely.geometry.base import BaseGeometry
+from pymove.core.grid import Grid
from pymove.utils.constants import (
DATE,
DAY,
@@ -26,7 +29,7 @@
LATITUDE,
LONGITUDE,
PERIOD,
- TID,
+ POLYGON,
TRAJ_ID,
)
@@ -36,13 +39,13 @@
def show_object_id_by_date(
- move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'],
- kind: Optional[List] = None,
- figsize: Tuple[float, float] = (21, 9),
+ move_data: 'PandasMoveDataFrame' | 'DaskMoveDataFrame',
+ kind: list | None = None,
+ figsize: tuple[float, float] = (21, 9),
return_fig: bool = False,
save_fig: bool = False,
- name: Text = 'shot_points_by_date.png',
-) -> Optional[figure]:
+ name: str = 'shot_points_by_date.png',
+) -> figure | None:
"""
Generates four visualizations based on datetime feature.
@@ -128,13 +131,13 @@ def show_object_id_by_date(
def plot_trajectories(
move_data: DataFrame,
- markers: Text = 'o',
+ markers: str = 'o',
markersize: float = 12,
- figsize: Tuple[float, float] = (10, 10),
+ figsize: tuple[float, float] = (10, 10),
return_fig: bool = False,
save_fig: bool = False,
- name: Text = 'trajectories.png',
-) -> Optional[figure]:
+ name: str = 'trajectories.png',
+) -> figure | None:
"""
Generate a visualization that show trajectories.
@@ -193,17 +196,17 @@ def plot_trajectories(
def plot_trajectory_by_id(
move_data: DataFrame,
- id_: Union[int, Text],
- label: Text = TID,
- feature: Optional[Text] = None,
- value: Optional[Any] = None,
+ id_: int | str,
+ label: str = TRAJ_ID,
+ feature: str | None = None,
+ value: Any | None = None,
linewidth: float = 3,
markersize: float = 20,
- figsize: Tuple[float, float] = (10, 10),
+ figsize: tuple[float, float] = (10, 10),
return_fig: bool = False,
save_fig: bool = False,
- name: Optional[Text] = None,
-) -> Optional[figure]:
+ name: str | None = None,
+) -> figure | None:
"""
Generate a visualization that shows a trajectory with the specified tid.
@@ -302,14 +305,83 @@ def plot_trajectory_by_id(
return fig
+def plot_grid_polygons(
+ data: DataFrame,
+ grid: Grid | None = None,
+ markersize: float = 10,
+ linewidth: float = 2,
+ figsize: tuple[int, int] = (10, 10),
+ return_fig: bool = False,
+ save_fig: bool = False,
+ name: str = 'grid.png',
+) -> figure | None:
+ """
+ Generate a visualization with grid polygons.
+
+ Parameters
+ ----------
+ data : DataFrame
+ Input trajectory data
+ markersize : float, optional
+ Represents visualization size marker, by default 10
+ linewidth : float, optional
+ Represents visualization size line, by default 2
+ figsize : tuple(int, int), optional
+ Represents the size (float: width, float: height) of a figure,
+ by default (10, 10)
+ return_fig : bool, optional
+ Represents whether or not to save the generated picture, by default False
+ save_fig : bool, optional
+ Wether to save the figure, by default False
+ name : str, optional
+ Represents name of a file, by default 'grid.png'
+
+ Returns
+ -------
+ figure
+ The generated picture or None
+
+ Raises
+ ------
+ If the dataframe does not contains the POLYGON feature
+ IndexError
+ If there is no user with the id passed
+
+ """
+ if POLYGON not in data:
+ if grid is None:
+ raise KeyError('POLYGON feature not in dataframe')
+ data = grid.create_all_polygons_to_all_point_on_grid(data)
+
+ data = data.copy()
+
+ data.dropna(subset=[POLYGON], inplace=True)
+
+ fig = plt.figure(figsize=figsize)
+
+ for _, row in data.iterrows():
+ xs, ys = row[POLYGON].exterior.xy
+ plt.plot(ys, xs, 'g', linewidth=linewidth, markersize=markersize)
+ xs_start, ys_start = data.iloc[0][POLYGON].exterior.xy
+ xs_end, ys_end = data.iloc[-1][POLYGON].exterior.xy
+ plt.plot(ys_start, xs_start, 'bo', markersize=markersize * 1.5)
+ plt.plot(ys_end, xs_end, 'bX', markersize=markersize * 1.5)
+
+ if save_fig:
+ plt.savefig(fname=name)
+
+ if return_fig:
+ return fig
+
+
def plot_all_features(
move_data: DataFrame,
dtype: Callable = float,
- figsize: Tuple[float, float] = (21, 15),
+ figsize: tuple[float, float] = (21, 15),
return_fig: bool = False,
save_fig: bool = False,
- name: Text = 'features.png',
-) -> Optional[figure]:
+ name: str = 'features.png',
+) -> figure | None:
"""
Generate a visualization for each columns that type is equal dtype.
@@ -369,7 +441,7 @@ def plot_all_features(
return fig
-def plot_coords(ax: axes, ob: BaseGeometry, color: Text = 'r'):
+def plot_coords(ax: axes, ob: BaseGeometry, color: str = 'r'):
"""
Plot the coordinates of each point of the object in a 2D chart.
@@ -394,7 +466,7 @@ def plot_coords(ax: axes, ob: BaseGeometry, color: Text = 'r'):
ax.plot(x, y, 'o', color=color, zorder=1)
-def plot_bounds(ax: axes, ob: Union[LineString, MultiLineString], color='b'):
+def plot_bounds(ax: axes, ob: LineString | MultiLineString, color='b'):
"""
Plot the limits of geometric object.
@@ -422,10 +494,10 @@ def plot_bounds(ax: axes, ob: Union[LineString, MultiLineString], color='b'):
def plot_line(
ax: axes,
ob: LineString,
- color: Text = 'r',
+ color: str = 'r',
alpha: float = 0.7,
linewidth: float = 3,
- solid_capstyle: Text = 'round',
+ solid_capstyle: str = 'round',
zorder: float = 2
):
"""