From c16b21fc56816f79cdc7534d087abae182d19a14 Mon Sep 17 00:00:00 2001 From: flych3r Date: Tue, 8 Jun 2021 15:54:15 -0300 Subject: [PATCH 1/4] added mypy --- .pre-commit-config.yaml | 4 + pymove/core/dask.py | 146 ++++++------ pymove/core/dataframe.py | 16 +- pymove/core/grid.py | 41 ++-- pymove/core/interface.py | 2 +- pymove/core/pandas.py | 202 +++++++++-------- pymove/core/pandas_discrete.py | 43 ++-- pymove/models/pattern_mining/clustering.py | 24 +- pymove/preprocessing/compression.py | 18 +- pymove/preprocessing/filters.py | 94 ++++---- pymove/preprocessing/segmentation.py | 48 ++-- pymove/preprocessing/stay_point_detection.py | 18 +- pymove/query/query.py | 26 +-- pymove/semantic/semantic.py | 84 +++---- pymove/tests/test_utils_mem.py | 10 +- pymove/utils/conversions.py | 65 +++--- pymove/utils/data_augmentation.py | 30 +-- pymove/utils/datetime.py | 24 +- pymove/utils/distances.py | 29 +-- pymove/utils/geoutils.py | 16 +- pymove/utils/integration.py | 115 ++++++---- pymove/utils/log.py | 4 +- pymove/utils/math.py | 6 +- pymove/utils/mem.py | 17 +- pymove/utils/trajectories.py | 24 +- pymove/utils/visual.py | 4 +- pymove/visualization/folium.py | 224 +++++++++---------- pymove/visualization/matplotlib.py | 56 ++--- setup.cfg | 4 + 29 files changed, 732 insertions(+), 662 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7546e5d7..34dc62dd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -32,3 +32,7 @@ repos: 'flake8-docstrings==1.6.0', 'pep8-naming==0.11.1' ] +# - repo: https://github.com/pre-commit/mirrors-mypy +# rev: 'v0.812' +# hooks: +# - id: mypy diff --git a/pymove/core/dask.py b/pymove/core/dask.py index d6a68088..99f654de 100644 --- a/pymove/core/dask.py +++ b/pymove/core/dask.py @@ -1,6 +1,6 @@ """DaskMoveDataFrame class.""" -from typing import TYPE_CHECKING, Dict, List, Optional, Text, Union +from typing import TYPE_CHECKING, Dict, List, Text, Union import dask import numpy as np @@ -28,11 +28,11 @@ class DaskMoveDataFrame(DataFrame, MoveDataFrameAbstractModel): def __init__( self, data: Union[DataFrame, List, Dict], - latitude: Optional[Text] = LATITUDE, - longitude: Optional[Text] = LONGITUDE, - datetime: Optional[Text] = DATETIME, - traj_id: Optional[Text] = TRAJ_ID, - n_partitions: Optional[int] = 1, + latitude: Text = LATITUDE, + longitude: Text = LONGITUDE, + datetime: Text = DATETIME, + traj_id: Text = TRAJ_ID, + n_partitions: int = 1, ): """ Checks whether past data has 'lat', 'lon', 'datetime' columns. @@ -78,7 +78,7 @@ def __init__( try: zip_list[i] = zip_list[i] except KeyError: - zip_list.append(i) + zip_list.append(str(i)) data = pd.DataFrame(data, columns=zip_list) mapping_columns = MoveDataFrame.format_labels( @@ -204,23 +204,23 @@ def shape(self): """Return a tuple representing the dimensionality of the DataFrame.""" raise NotImplementedError('To be implemented') - def rename(self): + def rename(self, *args, **kwargs): """Alter axes labels..""" raise NotImplementedError('To be implemented') - def len(self): + def len(self, *args, **kwargs): """Returns the length/row numbers in trajectory data.""" raise NotImplementedError('To be implemented') - def unique(self): + def unique(self, *args, **kwargs): """Return unique values of Series object.""" raise NotImplementedError('To be implemented') def head( self, - n: Optional[int] = 5, - npartitions: Optional[int] = 1, - compute: Optional[bool] = True + n: int = 5, + npartitions: int = 1, + compute: bool = True ) -> DataFrame: """ Return the first n rows. @@ -248,9 +248,9 @@ def head( def tail( self, - n: Optional[int] = 5, - npartitions: Optional[int] = 1, - compute: Optional[bool] = True + n: int = 5, + npartitions: int = 1, + compute: bool = True ) -> DataFrame: """ Return the last n rows. @@ -276,19 +276,19 @@ def tail( """ return self._data.tail(n, npartitions, compute) - def get_users_number(self): + def get_users_number(self, *args, **kwargs): """Check and return number of users in trajectory data.""" raise NotImplementedError('To be implemented') - def to_numpy(self): + def to_numpy(self, *args, **kwargs): """Converts trajectory data to numpy array format.""" raise NotImplementedError('To be implemented') - def to_dict(self): + def to_dict(self, *args, **kwargs): """Converts trajectory data to dict format.""" raise NotImplementedError('To be implemented') - def to_grid(self): + def to_grid(self, *args, **kwargs): """Converts trajectory data to grid format.""" raise NotImplementedError('To be implemented') @@ -304,205 +304,205 @@ def to_data_frame(self) -> DataFrame: """ return self._data - def info(self): + def info(self, *args, **kwargs): """Print a concise summary of a DataFrame.""" raise NotImplementedError('To be implemented') - def describe(self): + def describe(self, *args, **kwargs): """Generate descriptive statistics.""" raise NotImplementedError('To be implemented') - def memory_usage(self): + def memory_usage(self, *args, **kwargs): """Return the memory usage of each column in bytes.""" raise NotImplementedError('To be implemented') - def copy(self): + def copy(self, *args, **kwargs): """Make a copy of this object’srs indices and data.""" raise NotImplementedError('To be implemented') - def generate_tid_based_on_id_datetime(self): + def generate_tid_based_on_id_datetime(self, *args, **kwargs): """Create or update trajectory id based on id e datetime.""" raise NotImplementedError('To be implemented') - def generate_date_features(self): + def generate_date_features(self, *args, **kwargs): """Create or update date feature.""" raise NotImplementedError('To be implemented') - def generate_hour_features(self): + def generate_hour_features(self, *args, **kwargs): """Create or update hour feature.""" raise NotImplementedError('To be implemented') - def generate_day_of_the_week_features(self): + def generate_day_of_the_week_features(self, *args, **kwargs): """Create or update a feature day of the week from datatime.""" raise NotImplementedError('To be implemented') - def generate_weekend_features(self): + def generate_weekend_features(self, *args, **kwargs): """Create or update the feature weekend to the dataframe.""" raise NotImplementedError('To be implemented') - def generate_time_of_day_features(self): + def generate_time_of_day_features(self, *args, **kwargs): """Create a feature time of day or period from datatime.""" raise NotImplementedError('To be implemented') - def generate_datetime_in_format_cyclical(self): + def generate_datetime_in_format_cyclical(self, *args, **kwargs): """Create or update column with cyclical datetime feature.""" raise NotImplementedError('To be implemented') - def generate_dist_time_speed_features(self): + def generate_dist_time_speed_features(self, *args, **kwargs): """Creates features of distance, time and speed between points.""" raise NotImplementedError('To be implemented') - def generate_dist_features(self): + def generate_dist_features(self, *args, **kwargs): """Create the three distance in meters to an GPS point P.""" raise NotImplementedError('To be implemented') - def generate_time_features(self): + def generate_time_features(self, *args, **kwargs): """Create the three time in seconds to an GPS point P.""" raise NotImplementedError('To be implemented') - def generate_speed_features(self): + def generate_speed_features(self, *args, **kwargs): """Create the three speed in meters by seconds to an GPS point P.""" raise NotImplementedError('To be implemented') - def generate_move_and_stop_by_radius(self): + def generate_move_and_stop_by_radius(self, *args, **kwargs): """Create or update column with move and stop points by radius.""" raise NotImplementedError('To be implemented') - def time_interval(self): + def time_interval(self, *args, **kwargs): """Get time difference between max and min datetime in trajectory.""" raise NotImplementedError('To be implemented') - def get_bbox(self): + def get_bbox(self, *args, **kwargs): """Creates the bounding box of the trajectories.""" raise NotImplementedError('To be implemented') - def plot_all_features(self): + def plot_all_features(self, *args, **kwargs): """Generate a visualization for each column that type is equal dtype.""" raise NotImplementedError('To be implemented') - def plot_trajs(self): + def plot_trajs(self, *args, **kwargs): """Generate a visualization that show trajectories.""" raise NotImplementedError('To be implemented') - def plot_traj_id(self): + def plot_traj_id(self, *args, **kwargs): """Generate a visualization for a trajectory with the specified tid.""" raise NotImplementedError('To be implemented') - def show_trajectories_info(self): + def show_trajectories_info(self, *args, **kwargs): """Show dataset information from dataframe.""" raise NotImplementedError('To be implemented') - def min(self): + def min(self, *args, **kwargs): """Return the minimum of the values for the requested axis.""" raise NotImplementedError('To be implemented') - def max(self): + def max(self, *args, **kwargs): """Return the maximum of the values for the requested axis.""" raise NotImplementedError('To be implemented') - def count(self): + def count(self, *args, **kwargs): """Counts the non-NA cells for each column or row.""" raise NotImplementedError('To be implemented') - def groupby(self): + def groupby(self, *args, **kwargs): """Groups dask DataFrame using a mapper or by a Series of columns.""" raise NotImplementedError('To be implemented') - def plot(self): + def plot(self, *args, **kwargs): """Plot the data of the dask DataFrame.""" raise NotImplementedError('To be implemented') - def select_dtypes(self): + def select_dtypes(self, *args, **kwargs): """Returns a subset of the columns based on the column dtypes.""" raise NotImplementedError('To be implemented') - def astype(self): + def astype(self, *args, **kwargs): """Casts a dask object to a specified dtype.""" raise NotImplementedError('To be implemented') - def sort_values(self): + def sort_values(self, *args, **kwargs): """Sorts the values of the dask DataFrame.""" raise NotImplementedError('To be implemented') - def reset_index(self): + def reset_index(self, *args, **kwargs): """Resets the dask DataFrame'srs index, and use the default one.""" raise NotImplementedError('To be implemented') - def set_index(self): + def set_index(self, *args, **kwargs): """Set of row labels using one or more existing columns or arrays.""" raise NotImplementedError('To be implemented') - def drop(self): + def drop(self, *args, **kwargs): """Drops specified rows or columns of the dask Dataframe.""" raise NotImplementedError('To be implemented') - def duplicated(self): + def duplicated(self, *args, **kwargs): """Returns boolean Series denoting duplicate rows.""" raise NotImplementedError('To be implemented') - def drop_duplicates(self): + def drop_duplicates(self, *args, **kwargs): """Removes duplicated rows from the data.""" raise NotImplementedError('To be implemented') - def shift(self): + def shift(self, *args, **kwargs): """Shifts by desired number of periods with an optional time freq.""" raise NotImplementedError('To be implemented') - def all(self): + def all(self, *args, **kwargs): """Indicates if all elements are True, potentially over an axis.""" raise NotImplementedError('To be implemented') - def any(self): + def any(self, *args, **kwargs): """Indicates if any element is True, potentially over an axis.""" raise NotImplementedError('To be implemented') - def isna(self): + def isna(self, *args, **kwargs): """Detect missing values.""" raise NotImplementedError('To be implemented') - def fillna(self): + def fillna(self, *args, **kwargs): """Fills missing data in the dask DataFrame.""" raise NotImplementedError('To be implemented') - def dropna(self): + def dropna(self, *args, **kwargs): """Removes missing data from dask DataFrame.""" raise NotImplementedError('To be implemented') - def sample(self): + def sample(self, *args, **kwargs): """Samples data from the dask DataFrame.""" raise NotImplementedError('To be implemented') - def isin(self): + def isin(self, *args, **kwargs): """Determines whether each element is contained in values.""" raise NotImplementedError('To be implemented') - def append(self): + def append(self, *args, **kwargs): """Append rows of other to the end of caller, returning a new object.""" raise NotImplementedError('To be implemented') - def join(self): + def join(self, *args, **kwargs): """Join columns of another DataFrame.""" raise NotImplementedError('To be implemented') - def merge(self): + def merge(self, *args, **kwargs): """Merge columns of another DataFrame.""" raise NotImplementedError('To be implemented') - def nunique(self): + def nunique(self, *args, **kwargs): """Count distinct observations over requested axis.""" raise NotImplementedError('To be implemented') - def write_file(self): + def write_file(self, *args, **kwargs): """Write trajectory data to a new file.""" raise NotImplementedError('To be implemented') - def to_csv(self): + def to_csv(self, *args, **kwargs): """Write object to a comma-separated values (csv) file.""" raise NotImplementedError('To be implemented') def convert_to( self, new_type: Text - ) -> Union['PandasMoveDataFrame', 'DaskMoveDataFrame']: + ) -> Union[MoveDataFrame, 'PandasMoveDataFrame', 'DaskMoveDataFrame']: """ Convert an object from one type to another specified by the user. @@ -517,9 +517,7 @@ def convert_to( The converted object. """ - if new_type == TYPE_DASK: - return self - elif new_type == TYPE_PANDAS: + if new_type == TYPE_PANDAS: df_pandas = self._data.compute() return MoveDataFrame( df_pandas, @@ -529,6 +527,8 @@ def convert_to( traj_id=TRAJ_ID, type_=TYPE_PANDAS ) + else: + return self def get_type(self) -> Text: """ diff --git a/pymove/core/dataframe.py b/pymove/core/dataframe.py index e4052d22..3e586116 100644 --- a/pymove/core/dataframe.py +++ b/pymove/core/dataframe.py @@ -1,6 +1,6 @@ """MoveDataFrame class.""" -from typing import Dict, List, Optional, Text, Union +from typing import Dict, List, Text, Union from dateutil.parser._parser import ParserError from pandas.core.frame import DataFrame @@ -22,12 +22,12 @@ class MoveDataFrame: def __new__( self, data: Union[DataFrame, Dict, List], - latitude: Optional[Text] = LATITUDE, - longitude: Optional[Text] = LONGITUDE, - datetime: Optional[Text] = DATETIME, - traj_id: Optional[Text] = TRAJ_ID, - type_: Optional[Text] = TYPE_PANDAS, - n_partitions: Optional[int] = 1, + latitude: Text = LATITUDE, + longitude: Text = LONGITUDE, + datetime: Text = DATETIME, + traj_id: Text = TRAJ_ID, + type_: Text = TYPE_PANDAS, + n_partitions: int = 1, ): """ Creates the PyMove dataframe, which must contain latitude, longitude and datetime. @@ -48,7 +48,7 @@ def __new__( Represents column name trajectory id, by default TRAJ_ID type_ : str, optional Number of partitions of the dask dataframe, by default TYPE_PANDAS - n_partitions : Optional[int], optional + n_partitions : int, optional Amount of partitions for dask dataframe, by default 1 Raises diff --git a/pymove/core/grid.py b/pymove/core/grid.py index 276f239a..a29c65a7 100644 --- a/pymove/core/grid.py +++ b/pymove/core/grid.py @@ -47,19 +47,26 @@ def __init__( 'grid_size_lat_y': lat y size of grid, 'grid_size_lon_x': lon x size of grid, 'cell_size_by_degree': cell size in radians, - cell_size : float, optional + cell_size : float Represents grid cell size, by default None meters_by_degree : float, optional Represents the corresponding meters of lat by degree, by default lat_meters(-3.71839) + + Raises + ------ + ValueError + If one of data or cell grid is not provided """ - self.last_operation = None + self.last_operation: Dict = dict() if meters_by_degree is None: meters_by_degree = lat_meters(-3.71839) if isinstance(data, dict): self._grid_from_dict(data) - else: + elif cell_size is not None: self._create_virtual_grid(data, cell_size, meters_by_degree) + else: + raise ValueError('Must pass either data or cell size.') self.grid_polygon = None def get_grid(self) -> Dict: @@ -170,9 +177,9 @@ def _create_virtual_grid( def create_update_index_grid_feature( self, data: DataFrame, - unique_index: Optional[bool] = True, - label_dtype: Optional[Callable] = np.int64, - sort: Optional[bool] = True + unique_index: bool = True, + label_dtype: Callable = np.int64, + sort: bool = True ): """ Create or update index grid feature. @@ -185,7 +192,7 @@ def create_update_index_grid_feature( Represents the dataset with contains lat, long and datetime. unique_index: bool, optional How to index the grid, by default True - label_dtype : Optional[Callable], optional + label_dtype : Callable, optional Represents the type of a value of new column in dataframe, by default np.int64 sort : bool, optional Represents if needs to sort the dataframe, by default True @@ -211,8 +218,8 @@ def create_update_index_grid_feature( def convert_two_index_grid_to_one( self, data: DataFrame, - label_grid_lat: Optional[Text] = INDEX_GRID_LAT, - label_grid_lon: Optional[Text] = INDEX_GRID_LON, + label_grid_lat: Text = INDEX_GRID_LAT, + label_grid_lon: Text = INDEX_GRID_LON, ): """ Converts grid lat-lon ids to unique values. @@ -234,7 +241,7 @@ def convert_two_index_grid_to_one( def convert_one_index_grid_to_two( self, data: DataFrame, - label_grid_index: Optional[Text] = INDEX_GRID, + label_grid_index: Text = INDEX_GRID, ): """ Converts grid lat-lon ids to unique values. @@ -427,12 +434,12 @@ def read_grid_pkl(self, filename: Text) -> 'Grid': def show_grid_polygons( self, data: DataFrame, - markersize: Optional[float] = 10, - linewidth: Optional[float] = 2, - figsize: Optional[Tuple[int, int]] = (10, 10), - return_fig: Optional[bool] = True, - save_fig: Optional[bool] = False, - name: Optional[Text] = 'grid.png', + 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. @@ -457,7 +464,7 @@ def show_grid_polygons( Returns ------- - Optional[figure] + figure The generated picture or None Raises diff --git a/pymove/core/interface.py b/pymove/core/interface.py index 3e03ad89..f8408f6e 100644 --- a/pymove/core/interface.py +++ b/pymove/core/interface.py @@ -279,7 +279,7 @@ def write_file(self): pass @abc.abstractmethod - def convert_to(self): + def convert_to(self, new_type: str): pass @abc.abstractmethod diff --git a/pymove/core/pandas.py b/pymove/core/pandas.py index a1693d66..1e48a129 100644 --- a/pymove/core/pandas.py +++ b/pymove/core/pandas.py @@ -55,10 +55,10 @@ class PandasMoveDataFrame(DataFrame): def __init__( self, data: Union[DataFrame, List, Dict], - latitude: Optional[Text] = LATITUDE, - longitude: Optional[Text] = LONGITUDE, - datetime: Optional[Text] = DATETIME, - traj_id: Optional[Text] = TRAJ_ID, + latitude: Text = LATITUDE, + longitude: Text = LONGITUDE, + datetime: Text = DATETIME, + traj_id: Text = TRAJ_ID, ): """ Checks whether past data has 'lat', 'lon', 'datetime' columns. @@ -103,7 +103,7 @@ def __init__( try: zip_list[i] = zip_list[i] except KeyError: - zip_list.append(i) + zip_list.append(str(i)) data = DataFrame(data, columns=zip_list) columns = MoveDataFrame.format_labels( @@ -115,7 +115,7 @@ def __init__( MoveDataFrame.validate_move_data_frame(tdf) super(PandasMoveDataFrame, self).__init__(tdf) self._type = TYPE_PANDAS - self.last_operation = None + self.last_operation: Dict = dict() else: raise KeyError( @@ -189,13 +189,13 @@ def datetime(self): return self[DATETIME] 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, - copy: Optional[bool] = True, - inplace: Optional[bool] = False + 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, + copy: bool = True, + inplace: bool = False ) -> Optional[Union['PandasMoveDataFrame', DataFrame]]: """ Alter axes labels. @@ -245,7 +245,7 @@ def rename( if inplace: if MoveDataFrame.has_columns(rename_): self._mgr = rename_._mgr - self._item_cache = dict() + self._item_cache: Dict = dict() rename_ = None else: raise AttributeError( @@ -277,7 +277,7 @@ def __getitem__(self, key): return PandasMoveDataFrame(item) return item - def head(self, n: Optional[int] = 5) -> 'PandasMoveDataFrame': + def head(self, n: int = 5) -> 'PandasMoveDataFrame': """ Return the first n rows. @@ -303,7 +303,7 @@ def head(self, n: Optional[int] = 5) -> 'PandasMoveDataFrame': head_ = super().head(n=n) return PandasMoveDataFrame(data=head_) - def tail(self, n: Optional[int] = 5) -> 'PandasMoveDataFrame': + def tail(self, n: int = 5) -> 'PandasMoveDataFrame': """ Return the last n rows. @@ -394,7 +394,7 @@ def to_data_frame(self) -> DataFrame: return DataFrame(self) def to_dicrete_move_df( - self, local_label: Optional[Text] = LOCAL_LABEL + self, local_label: Text = LOCAL_LABEL ) -> 'PandasMoveDataFrame': """ Generate a discrete dataframe move. @@ -423,7 +423,7 @@ def to_dicrete_move_df( self, LATITUDE, LONGITUDE, DATETIME, TRAJ_ID, local_label ) - def copy(self, deep: Optional[bool] = True) -> 'PandasMoveDataFrame': + def copy(self, deep: bool = True) -> 'PandasMoveDataFrame': """ Make a copy of this object’s indices and data. @@ -464,9 +464,9 @@ def copy(self, deep: Optional[bool] = True) -> 'PandasMoveDataFrame': def generate_tid_based_on_id_datetime( self, - str_format: Optional[Text] = '%Y%m%d%H', - sort: Optional[bool] = True, - inplace: Optional[bool] = True + str_format: Text = '%Y%m%d%H', + sort: bool = True, + inplace: bool = True ) -> Optional['PandasMoveDataFrame']: """ Create or update trajectory id based on id and datetime. @@ -512,7 +512,7 @@ def generate_tid_based_on_id_datetime( return data def generate_date_features( - self, inplace: Optional[bool] = True + self, inplace: bool = True ) -> Optional['PandasMoveDataFrame']: """ Create or update date feature based on datetime. @@ -545,7 +545,7 @@ def generate_date_features( return data def generate_hour_features( - self, inplace: Optional[bool] = True + self, inplace: bool = True ) -> Optional['PandasMoveDataFrame']: """ Create or update hour features based on datetime. @@ -578,7 +578,7 @@ def generate_hour_features( return data def generate_day_of_the_week_features( - self, inplace: Optional[bool] = True + self, inplace: bool = True ) -> Optional['PandasMoveDataFrame']: """ Create or update day of the week features based on datetime. @@ -610,7 +610,9 @@ def generate_day_of_the_week_features( return data def generate_weekend_features( - self, create_day_of_week: Optional[bool] = False, inplace: Optional[bool] = True + self, + create_day_of_week: bool = False, + inplace: bool = True ) -> Optional['PandasMoveDataFrame']: """ Adds information to rows determining if it is a weekend day. @@ -658,7 +660,7 @@ def generate_weekend_features( return data def generate_time_of_day_features( - self, inplace: Optional[bool] = True + self, inplace: bool = True ) -> Optional['PandasMoveDataFrame']: """ Create or update time of day features based on datetime. @@ -716,7 +718,9 @@ def generate_time_of_day_features( return data def generate_datetime_in_format_cyclical( - self, label_datetime: Optional[Text] = DATETIME, inplace: Optional[bool] = True + self, + label_datetime: Text = DATETIME, + inplace: bool = True ) -> Optional['PandasMoveDataFrame']: """ Create or update column with cyclical datetime feature. @@ -760,7 +764,7 @@ def generate_datetime_in_format_cyclical( @staticmethod def _prepare_generate_data( data_: DataFrame, sort: bool, label_id: Text - ) -> Tuple[List, int, int, int]: + ) -> Tuple[Any, int, None]: """ Processes the data and create variables for generate methods. @@ -803,10 +807,10 @@ def _prepare_generate_data( def generate_dist_time_speed_features( self, - label_id: Optional[Text] = TRAJ_ID, - label_dtype: Optional[Callable] = np.float64, - sort: Optional[bool] = True, - inplace: Optional[bool] = True + label_id: Text = TRAJ_ID, + label_dtype: Callable = np.float64, + sort: bool = True, + inplace: bool = True ) -> Optional['PandasMoveDataFrame']: """ Adds distance, time and speed information to the dataframe. @@ -899,10 +903,10 @@ def generate_dist_time_speed_features( def generate_dist_features( self, - label_id: Optional[Text] = TRAJ_ID, - label_dtype: Optional[Callable] = np.float64, - sort: Optional[bool] = True, - inplace: Optional[bool] = True + label_id: Text = TRAJ_ID, + label_dtype: Callable = np.float64, + sort: bool = True, + inplace: bool = True ) -> Optional['PandasMoveDataFrame']: """ Create the three distance in meters to an GPS point P. @@ -987,10 +991,10 @@ def generate_dist_features( def generate_time_features( self, - label_id: Optional[Text] = TRAJ_ID, - label_dtype: Optional[Callable] = np.float64, - sort: Optional[bool] = True, - inplace: Optional[bool] = True + label_id: Text = TRAJ_ID, + label_dtype: Callable = np.float64, + sort: bool = True, + inplace: bool = True ) -> Optional['PandasMoveDataFrame']: """ Create the three time in seconds to an GPS point P. @@ -1066,10 +1070,10 @@ def generate_time_features( def generate_speed_features( self, - label_id: Optional[Text] = TRAJ_ID, - label_dtype: Optional[Callable] = np.float64, - sort: Optional[bool] = True, - inplace: Optional[bool] = True + label_id: Text = TRAJ_ID, + label_dtype: Callable = np.float64, + sort: bool = True, + inplace: bool = True ) -> Optional['PandasMoveDataFrame']: """ Create the three speed in meter by seconds to an GPS point P. @@ -1091,6 +1095,11 @@ def generate_speed_features( PandasMoveDataFrame Object with new features or None + Raises + ------ + ValueError + If feature generation fails + Examples -------- - P to P.next = 1 meter/seconds @@ -1108,15 +1117,15 @@ def generate_speed_features( '\nCreating or updating speed features meters by seconds\n' ) - dist_cols = [DIST_TO_PREV, DIST_TO_NEXT, DIST_PREV_TO_NEXT] - time_cols = [TIME_TO_PREV, TIME_TO_NEXT, TIME_PREV_TO_NEXT] - dists = data.generate_dist_features( label_id, label_dtype, sort, inplace=False - )[dist_cols] + ) times = data.generate_time_features( label_id, label_dtype, sort, inplace=False - )[time_cols] + ) + + if dists is None or times is None: + raise ValueError('Geretating dist or time feature failed') data[SPEED_TO_PREV] = dists[DIST_TO_PREV] / times[TIME_TO_PREV] data[SPEED_TO_NEXT] = dists[DIST_TO_NEXT] / times[TIME_TO_NEXT] @@ -1129,14 +1138,15 @@ def generate_speed_features( ) data.reset_index(inplace=True) data.last_operation = end_operation(operation) + if not inplace: return data def generate_move_and_stop_by_radius( self, - radius: Optional[int] = 0, - target_label: Optional[Text] = DIST_TO_PREV, - inplace: Optional[bool] = True + radius: int = 0, + target_label: Text = DIST_TO_PREV, + inplace: bool = True ): """ Create or update column with move and stop points by radius. @@ -1317,8 +1327,8 @@ def show_trajectories_info(self): def astype( self, dtype: Union[Callable, Dict], - copy: Optional[bool] = True, - errors: Optional[Text] = 'raise' + copy: bool = True, + errors: Text = 'raise' ) -> DataFrame: """ Cast a pandas object to a specified dtype. @@ -1373,11 +1383,11 @@ def astype( def sort_values( self, by: Union[Text, List[Text]], - axis: Optional[int] = 0, - ascending: Optional[bool] = True, - inplace: Optional[bool] = False, - kind: Optional[Text] = 'quicksort', - na_position: Optional[Text] = 'last', + axis: int = 0, + ascending: bool = True, + inplace: bool = False, + kind: Text = 'quicksort', + na_position: Text = 'last', ) -> Optional['PandasMoveDataFrame']: """ Sorts the values of the _data, along an axis. @@ -1432,10 +1442,10 @@ def sort_values( def reset_index( self, level: Optional[Union[int, Text, Tuple, List]] = None, - drop: Optional[bool] = False, - inplace: Optional[bool] = False, - col_level: Optional[Union[int, Text]] = 0, - col_fill: Optional[Text] = '' + drop: bool = False, + inplace: bool = False, + col_level: Union[int, Text] = 0, + col_fill: Text = '' ) -> Optional['PandasMoveDataFrame']: """ Resets the DataFrame's index, and use the default one. @@ -1480,10 +1490,10 @@ def reset_index( def set_index( self, keys: Union[Text, List[Text]], - drop: Optional[bool] = True, - append: Optional[bool] = False, - inplace: Optional[bool] = False, - verify_integrity: Optional[bool] = False, + drop: bool = True, + append: bool = False, + inplace: bool = False, + verify_integrity: bool = False, ) -> Optional[Union['PandasMoveDataFrame', DataFrame]]: """ Set the DataFrame index (row labels) using one or more existing columns or arrays. @@ -1549,12 +1559,12 @@ def set_index( def drop( self, labels: Optional[Union[Text, List[Text]]] = None, - axis: Optional[Union[int, Text]] = 0, + 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, - inplace: Optional[bool] = False, - errors: Optional[Text] = 'raise', + inplace: bool = False, + errors: Text = 'raise', ) -> Optional[Union['PandasMoveDataFrame', DataFrame]]: """ Removes rows or columns. @@ -1642,8 +1652,8 @@ def drop( def drop_duplicates( self, subset: Optional[Union[int, Text]] = None, - keep: Optional[Union[Text, bool]] = 'first', - inplace: Optional[bool] = False + keep: Union[Text, bool] = 'first', + inplace: bool = False ) -> Optional['PandasMoveDataFrame']: """ Uses the pandas's function drop_duplicates, to remove duplicated rows from data. @@ -1683,9 +1693,9 @@ def drop_duplicates( def shift( self, - periods: Optional[int] = 1, + periods: int = 1, freq: Optional[Union[DateOffset, Timedelta, Text]] = None, - axis: Optional[Union[int, Text]] = 0, + axis: Union[int, Text] = 0, fill_value: Optional[Any] = None ) -> 'PandasMoveDataFrame': """ @@ -1733,7 +1743,7 @@ def fillna( value: Optional[Any] = None, method: Optional[Text] = None, axis: Optional[Union[int, Text]] = None, - inplace: Optional[bool] = False, + inplace: bool = False, limit: Optional[int] = None, downcast: Optional[Dict] = None, ): @@ -1793,11 +1803,11 @@ def fillna( def dropna( self, - axis: Optional[Union[int, Text]] = 0, - how: Optional[Text] = 'any', + axis: Union[int, Text] = 0, + how: Text = 'any', thresh: Optional[float] = None, subset: Optional[List] = None, - inplace: Optional[bool] = False + inplace: bool = False ): """ Removes missing data. @@ -1862,7 +1872,7 @@ def sample( self, n: Optional[int] = None, frac: Optional[float] = None, - replace: Optional[bool] = False, + replace: bool = False, weights: Optional[Union[Text, List]] = None, random_state: Optional[int] = None, axis: Optional[Union[int, Text]] = None @@ -1956,9 +1966,9 @@ def isin(self, values: Union[List, Series, DataFrame, Dict]) -> DataFrame: def append( self, other: Union['PandasMoveDataFrame', DataFrame], - ignore_index: Optional[bool] = False, - verify_integrity: Optional[bool] = False, - sort: Optional[bool] = False + ignore_index: bool = False, + verify_integrity: bool = False, + sort: bool = False ) -> 'PandasMoveDataFrame': """ Append rows of other to the end of caller, returning a new object. @@ -2002,10 +2012,10 @@ def join( self, other: Union['PandasMoveDataFrame', DataFrame], on: Optional[Union[Text, List]] = None, - how: Optional[Text] = 'left', - lsuffix: Optional[Text] = '', - rsuffix: Optional[Text] = '', - sort: Optional[bool] = False + how: Text = 'left', + lsuffix: Text = '', + rsuffix: Text = '', + sort: bool = False ) -> 'PandasMoveDataFrame': """ Join columns of other, returning a new object. @@ -2071,16 +2081,16 @@ def join( def merge( self, right: Union['PandasMoveDataFrame', DataFrame, Series], - how: Optional[Text] = 'inner', + how: Text = 'inner', on: Optional[Union[Text, List]] = None, left_on: Optional[Union[Text, List]] = None, right_on: Optional[Union[Text, List]] = None, - left_index: Optional[bool] = False, - right_index: Optional[bool] = False, - sort: Optional[bool] = False, - suffixes: Optional[Tuple[Text, Text]] = ('_x', '_y'), - copy: Optional[bool] = True, - indicator: Optional[Union[bool, Text]] = False, + left_index: bool = False, + right_index: bool = False, + sort: bool = False, + suffixes: Tuple[Text, Text] = ('_x', '_y'), + copy: bool = True, + indicator: Union[bool, Text] = False, validate: Optional[Text] = None ) -> 'PandasMoveDataFrame': """ @@ -2170,7 +2180,7 @@ def merge( ) return PandasMoveDataFrame(data=_merge) - def write_file(self, file_name: Text, separator: Optional[Text] = ','): + def write_file(self, file_name: Text, separator: Text = ','): """ Write trajectory data to a new file. @@ -2188,7 +2198,7 @@ def write_file(self, file_name: Text, separator: Optional[Text] = ','): def convert_to( self, new_type: Text - ) -> Union['PandasMoveDataFrame', 'DaskMoveDataFrame']: + ) -> Union[MoveDataFrame, 'PandasMoveDataFrame', 'DaskMoveDataFrame']: """ Convert an object from one type to another specified by the user. @@ -2217,7 +2227,7 @@ def convert_to( ) self.last_operation = end_operation(operation) return _dask - elif new_type == TYPE_PANDAS: + else: self.last_operation = end_operation(operation) return self diff --git a/pymove/core/pandas_discrete.py b/pymove/core/pandas_discrete.py index 7f38be20..54e9c93e 100644 --- a/pymove/core/pandas_discrete.py +++ b/pymove/core/pandas_discrete.py @@ -38,11 +38,11 @@ class PandasDiscreteMoveDataFrame(PandasMoveDataFrame): def __init__( self, data: Union[DataFrame, List, Dict], - latitude: Optional[Text] = LATITUDE, - longitude: Optional[Text] = LONGITUDE, - datetime: Optional[Text] = DATETIME, - traj_id: Optional[Text] = TRAJ_ID, - local_label: Optional[Text] = LOCAL_LABEL + latitude: Text = LATITUDE, + longitude: Text = LONGITUDE, + datetime: Text = DATETIME, + traj_id: Text = TRAJ_ID, + local_label: Text = LOCAL_LABEL ): """ Creates a dataframe using local_label as a discrete feature for localization. @@ -82,7 +82,7 @@ def __init__( '{} column not in dataframe'.format(local_label) ) - def discretize_based_grid(self, region_size: Optional[int] = 1000): + def discretize_based_grid(self, region_size: int = 1000): """ Discrete space in cells of the same size, assigning a unique id to each cell. @@ -100,10 +100,10 @@ def discretize_based_grid(self, region_size: Optional[int] = 1000): def generate_prev_local_features( self, - label_id: Optional[Text] = TRAJ_ID, - local_label: Optional[Text] = LOCAL_LABEL, - sort: Optional[bool] = True, - inplace: Optional[bool] = True + label_id: Text = TRAJ_ID, + local_label: Text = LOCAL_LABEL, + sort: bool = True, + inplace: bool = True ) -> Optional['PandasDiscreteMoveDataFrame']: """ Create a feature prev_local with the label of previous local to current point. @@ -162,19 +162,20 @@ def generate_prev_local_features( data_.reset_index(inplace=True) data_.last_operation = end_operation(operation) + if not inplace: return data_ def generate_tid_based_statistics( self, - label_id: Optional[Text] = TRAJ_ID, - local_label: Optional[Text] = LOCAL_LABEL, - mean_coef: Optional[float] = 1.0, - std_coef: Optional[float] = 1.0, + label_id: Text = TRAJ_ID, + local_label: Text = LOCAL_LABEL, + mean_coef: float = 1.0, + std_coef: float = 1.0, statistics: Optional[DataFrame] = None, - label_tid_stat: Optional[Text] = TID_STAT, - drop_single_points: Optional[bool] = False, - inplace: Optional[bool] = True, + label_tid_stat: Text = TID_STAT, + drop_single_points: bool = False, + inplace: bool = True, ) -> Optional['PandasDiscreteMoveDataFrame']: """ Splits the trajectories into segments based on time statistics for segments. @@ -190,7 +191,7 @@ def generate_tid_based_statistics( Multiplication coefficient of the mean time for the segment, by default 1.0 std_coef : float, optional Multiplication coefficient of sdt time for the segment, by default 1.0 - statistics : Optional[DataFrame], optional + statistics : DataFrame, optional Time Statistics of the pairwise local labels, by default None label_tid_stat : str, optional The label of the column containing the ids of the formed segments. @@ -260,9 +261,10 @@ def generate_tid_based_statistics( filter_.append(row[TIME_TO_PREV] > threshold) - filter_ = np.array(filter_) + filter_arr = np.array(filter_) current_tid, count = _update_curr_tid_count( - filter_, data_, idx, label_tid_stat, current_tid, count) + filter_arr, data_, idx, label_tid_stat, current_tid, count + ) if label_id == TID_STAT: self.reset_index(drop=True, inplace=True) @@ -275,5 +277,6 @@ def generate_tid_based_statistics( if drop_single_points: _drop_single_point(data_, TID_STAT, label_id) self.generate_dist_time_speed_features() + if not inplace: return data_ diff --git a/pymove/models/pattern_mining/clustering.py b/pymove/models/pattern_mining/clustering.py index 7a519cd0..d9302b3b 100644 --- a/pymove/models/pattern_mining/clustering.py +++ b/pymove/models/pattern_mining/clustering.py @@ -21,9 +21,9 @@ @timer_decorator def elbow_method( move_data: DataFrame, - k_initial: Optional[int] = 1, - max_clusters: Optional[int] = 15, - k_iteration: Optional[int] = 1, + k_initial: int = 1, + max_clusters: int = 15, + k_iteration: int = 1, random_state: Optional[int] = None ) -> Dict: """ @@ -80,10 +80,10 @@ def elbow_method( @timer_decorator def gap_statistic( move_data: DataFrame, - nrefs: Optional[int] = 3, - k_initial: Optional[int] = 1, - max_clusters: Optional[int] = 15, - k_iteration: Optional[int] = 1, + nrefs: int = 3, + k_initial: int = 1, + max_clusters: int = 15, + k_iteration: int = 1, random_state: Optional[int] = None ) -> Dict: """ @@ -152,11 +152,11 @@ def gap_statistic( def dbscan_clustering( move_data: DataFrame, cluster_by: Text, - meters: Optional[int] = 10, - min_sample: Optional[float] = 1680 / 2, - earth_radius: Optional[float] = EARTH_RADIUS, - metric: Optional[Union[Text, Callable]] = 'euclidean', - inplace: Optional[bool] = False + meters: int = 10, + min_sample: float = 1680 / 2, + earth_radius: float = EARTH_RADIUS, + metric: Union[Text, Callable] = 'euclidean', + inplace: bool = False ) -> Optional[DataFrame]: """ 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 c70e96b6..3be11a53 100644 --- a/pymove/preprocessing/compression.py +++ b/pymove/preprocessing/compression.py @@ -5,7 +5,7 @@ """ -from typing import Optional, Text +from typing import Text import numpy as np from pandas import DataFrame @@ -28,14 +28,14 @@ @timer_decorator def compress_segment_stop_to_point( move_data: DataFrame, - label_segment: Optional[Text] = SEGMENT_STOP, - label_stop: Optional[Text] = STOP, - point_mean: Optional[Text] = 'default', - drop_moves: Optional[bool] = False, - label_id: Optional[Text] = TRAJ_ID, - dist_radius: Optional[float] = 30, - time_radius: Optional[float] = 900, - inplace: Optional[bool] = False, + label_segment: Text = SEGMENT_STOP, + label_stop: Text = STOP, + point_mean: Text = 'default', + drop_moves: bool = False, + label_id: Text = TRAJ_ID, + dist_radius: float = 30, + time_radius: float = 900, + inplace: bool = False, ) -> DataFrame: """ Compress the trajectories using the stop points in the dataframe. diff --git a/pymove/preprocessing/filters.py b/pymove/preprocessing/filters.py index 885ba011..0f2c9d28 100644 --- a/pymove/preprocessing/filters.py +++ b/pymove/preprocessing/filters.py @@ -18,7 +18,7 @@ """ -from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Text, Tuple, Union +from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Text, Tuple, Union import numpy as np from pandas import DataFrame @@ -43,8 +43,8 @@ def get_bbox_by_radius( - coordinates: Tuple[float, float], radius: Optional[float] = 1000 -) -> List: + coordinates: Tuple[float, float], radius: float = 1000 +) -> Tuple[float, float, float, float]: """ Defines minimum and maximum coordinates, given a distance radius from a point. @@ -77,14 +77,14 @@ def get_bbox_by_radius( lonmin = lon - delta_lon lonmax = lon + delta_lon - return np.rad2deg([latmin, lonmin, latmax, lonmax]) + return tuple(np.rad2deg([latmin, lonmin, latmax, lonmax])) def by_bbox( move_data: DataFrame, - bbox: Tuple[int, int, int, int], - filter_out: Optional[bool] = False, - inplace: Optional[bool] = False + bbox: Tuple[float, float, float, float], + filter_out: bool = False, + inplace: bool = False ) -> Optional[DataFrame]: """ Filters points of the trajectories according to specified bounding box. @@ -125,8 +125,8 @@ def by_datetime( move_data: DataFrame, start_datetime: Optional[Text] = None, end_datetime: Optional[Text] = None, - filter_out: Optional[bool] = False, - inplace: Optional[bool] = False, + filter_out: bool = False, + inplace: bool = False, ) -> Optional[DataFrame]: """ Filters trajectories points according to specified time range. @@ -174,8 +174,8 @@ def by_label( move_data: DataFrame, value: Any, label_name: Text, - filter_out: Optional[bool] = False, - inplace: Optional[bool] = False + filter_out: bool = False, + inplace: bool = False ) -> Optional[DataFrame]: """ Filters trajectories points according to specified value and column label. @@ -213,9 +213,9 @@ def by_label( def by_id( move_data: DataFrame, id_: Optional[int] = None, - label_id: Optional[Text] = TRAJ_ID, - filter_out: Optional[bool] = False, - inplace: Optional[bool] = False + label_id: Text = TRAJ_ID, + filter_out: bool = False, + inplace: bool = False ) -> Optional[DataFrame]: """ Filters trajectories points according to specified trajectory id. @@ -251,8 +251,8 @@ def by_id( def by_tid( move_data: DataFrame, tid_: Optional[Text] = None, - filter_out: Optional[bool] = False, - inplace: Optional[bool] = False + filter_out: bool = False, + inplace: bool = False ) -> Optional[DataFrame]: """ Filters trajectories points according to a specified trajectory tid. @@ -287,8 +287,8 @@ def by_tid( def clean_consecutive_duplicates( move_data: DataFrame, subset: Optional[Union[int, Text]] = None, - keep: Optional[Union[Text, bool]] = 'first', - inplace: Optional[bool] = False + keep: Union[Text, bool] = 'first', + inplace: bool = False ) -> Optional[DataFrame]: """ Removes consecutive duplicate rows of the Dataframe. @@ -467,11 +467,11 @@ def _clean_gps(move_data: DataFrame, f: callable, **kwargs): def clean_gps_jumps_by_distance( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - label_id: Optional[Text] = TRAJ_ID, - jump_coefficient: Optional[float] = 3.0, - threshold: Optional[float] = 1, - label_dtype: Optional[callable] = np.float64, - inplace: Optional[bool] = False, + label_id: Text = TRAJ_ID, + jump_coefficient: float = 3.0, + threshold: float = 1, + label_dtype: callable = np.float64, + inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Removes the trajectories points that are outliers from the dataframe. @@ -525,10 +525,10 @@ def clean_gps_jumps_by_distance( def clean_gps_nearby_points_by_distances( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - label_id: Optional[Text] = TRAJ_ID, - radius_area: Optional[float] = 10.0, - label_dtype: Optional[callable] = np.float64, - inplace: Optional[bool] = False, + label_id: Text = TRAJ_ID, + radius_area: float = 10.0, + label_dtype: callable = np.float64, + inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Removes points from the trajectories with smaller distance from the point before. @@ -580,10 +580,10 @@ def clean_gps_nearby_points_by_distances( def clean_gps_nearby_points_by_speed( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - label_id: Optional[Text] = TRAJ_ID, - speed_radius: Optional[float] = 0.0, - label_dtype: Optional[Callable] = np.float64, - inplace: Optional[bool] = False, + label_id: Text = TRAJ_ID, + speed_radius: float = 0.0, + label_dtype: Callable = np.float64, + inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Removes points from the trajectories with smaller speed of travel. @@ -635,10 +635,10 @@ def clean_gps_nearby_points_by_speed( def clean_gps_speed_max_radius( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - label_id: Optional[Text] = TRAJ_ID, - speed_max: Optional[float] = 50.0, - label_dtype: Optional[Callable] = np.float64, - inplace: Optional[bool] = False, + label_id: Text = TRAJ_ID, + speed_max: float = 50.0, + label_dtype: Callable = np.float64, + inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Removes trajectories points with higher speed. @@ -699,9 +699,9 @@ def clean_gps_speed_max_radius( def clean_trajectories_with_few_points( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - label_tid: Optional[Text] = TID, - min_points_per_trajectory: Optional[int] = 2, - inplace: Optional[bool] = False + label_tid: Text = TID, + min_points_per_trajectory: int = 2, + inplace: bool = False ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Removes from the given dataframe, trajectories with fewer points. @@ -776,11 +776,11 @@ def clean_trajectories_with_few_points( def clean_trajectories_short_and_few_points( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - label_id: Optional[Text] = TID, - min_trajectory_distance: Optional[float] = 100, - min_points_per_trajectory: Optional[int] = 2, - label_dtype: Optional[Callable] = np.float64, - inplace: Optional[bool] = False, + label_id: Text = TID, + min_trajectory_distance: float = 100, + min_points_per_trajectory: int = 2, + label_dtype: Callable = np.float64, + inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Eliminates from the given dataframe trajectories with fewer points and shorter length. @@ -864,10 +864,10 @@ def clean_trajectories_short_and_few_points( def clean_id_by_time_max( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - label_id: Optional[Text] = TRAJ_ID, - time_max: Optional[float] = 3600, - label_dtype: Optional[Callable] = np.float64, - inplace: Optional[bool] = False, + label_id: Text = TRAJ_ID, + time_max: float = 3600, + label_dtype: Callable = np.float64, + inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Clears GPS points with time by ID greater than a user-defined limit. diff --git a/pymove/preprocessing/segmentation.py b/pymove/preprocessing/segmentation.py index f6030afb..59c94f01 100644 --- a/pymove/preprocessing/segmentation.py +++ b/pymove/preprocessing/segmentation.py @@ -209,7 +209,7 @@ 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: float, count: int + label_new_tid: Text, curr_tid: int, count: int ) -> Tuple[int, int]: """ Updates the tid. @@ -334,13 +334,13 @@ def _filter_by( @timer_decorator def by_dist_time_speed( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - label_id: Optional[Text] = TRAJ_ID, - max_dist_between_adj_points: Optional[float] = 3000, - max_time_between_adj_points: Optional[float] = 900, - max_speed_between_adj_points: Optional[float] = 50.0, - drop_single_points: Optional[bool] = True, - label_new_tid: Optional[Text] = TID_PART, - inplace: Optional[bool] = False, + label_id: Text = 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, + inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Splits the trajectories into segments based on distance, time and speed. @@ -414,11 +414,11 @@ def by_dist_time_speed( @timer_decorator def by_max_dist( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - label_id: Optional[Text] = TRAJ_ID, - max_dist_between_adj_points: Optional[float] = 3000, - drop_single_points: Optional[bool] = True, - label_new_tid: Optional[Text] = TID_DIST, - inplace: Optional[bool] = False, + label_id: Text = TRAJ_ID, + max_dist_between_adj_points: float = 3000, + drop_single_points: bool = True, + label_new_tid: Text = TID_DIST, + inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Segments the trajectories based on distance. @@ -481,11 +481,11 @@ def by_max_dist( @timer_decorator def by_max_time( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - label_id: Optional[Text] = TRAJ_ID, - max_time_between_adj_points: Optional[float] = 900.0, - drop_single_points: Optional[bool] = True, - label_new_tid: Optional[Text] = TID_TIME, - inplace: Optional[bool] = False, + label_id: Text = TRAJ_ID, + max_time_between_adj_points: float = 900.0, + drop_single_points: bool = True, + label_new_tid: Text = TID_TIME, + inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Splits the trajectories into segments based on a maximum. @@ -549,12 +549,12 @@ def by_max_time( @timer_decorator def by_max_speed( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - label_id: Optional[Text] = TRAJ_ID, - max_speed_between_adj_points: Optional[float] = 50.0, - drop_single_points: Optional[bool] = True, - label_new_tid: Optional[Text] = TID_SPEED, - inplace: Optional[bool] = False, -) -> Union['PandasMoveDataFrame', 'DaskMoveDataFrame']: + label_id: Text = TRAJ_ID, + max_speed_between_adj_points: float = 50.0, + drop_single_points: bool = True, + label_new_tid: Text = TID_SPEED, + inplace: bool = False, +) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ 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 df92f40e..ba819f5f 100644 --- a/pymove/preprocessing/stay_point_detection.py +++ b/pymove/preprocessing/stay_point_detection.py @@ -30,11 +30,11 @@ @timer_decorator def create_or_update_move_stop_by_dist_time( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - dist_radius: Optional[float] = 30, - time_radius: Optional[float] = 900, - label_id: Optional[Text] = TRAJ_ID, - new_label: Optional[Text] = SEGMENT_STOP, - inplace: Optional[bool] = False + dist_radius: float = 30, + time_radius: float = 900, + label_id: Text = TRAJ_ID, + new_label: Text = SEGMENT_STOP, + inplace: bool = False ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Determines the stops and moves points of the dataframe. @@ -113,10 +113,10 @@ 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'], - radius: Optional[float] = 0, - target_label: Optional[Text] = DIST_TO_PREV, - new_label: Optional[Text] = SITUATION, - inplace: Optional[bool] = False, + radius: float = 0, + target_label: Text = DIST_TO_PREV, + new_label: Text = SITUATION, + inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Finds the stops and moves points of the dataframe. diff --git a/pymove/query/query.py b/pymove/query/query.py index 6dd641f5..3ea17ee2 100644 --- a/pymove/query/query.py +++ b/pymove/query/query.py @@ -6,7 +6,7 @@ """ -from typing import Optional, Text +from typing import Text import numpy as np import pandas as pd @@ -20,12 +20,12 @@ def range_query( traj: DataFrame, move_df: DataFrame, - _id: Optional[Text] = TRAJ_ID, - min_dist: Optional[float] = 1000, - distance: Optional[Text] = MEDP, - latitude: Optional[Text] = LATITUDE, - longitude: Optional[Text] = LONGITUDE, - datetime: Optional[Text] = DATETIME + _id: Text = TRAJ_ID, + min_dist: float = 1000, + distance: Text = MEDP, + latitude: Text = LATITUDE, + longitude: Text = LONGITUDE, + datetime: Text = DATETIME ) -> DataFrame: """ Returns all trajectories that have a distance equal to or less than the trajectory. @@ -93,12 +93,12 @@ def dist_measure(traj, this, latitude, longitude, datetime): def knn_query( traj: DataFrame, move_df: DataFrame, - k: Optional[int] = 5, - id_: Optional[Text] = TRAJ_ID, - distance: Optional[Text] = MEDP, - latitude: Optional[Text] = LATITUDE, - longitude: Optional[Text] = LONGITUDE, - datetime: Optional[Text] = DATETIME + k: int = 5, + id_: Text = TRAJ_ID, + distance: Text = MEDP, + latitude: Text = LATITUDE, + longitude: Text = LONGITUDE, + datetime: Text = DATETIME ) -> DataFrame: """ Returns the k neighboring trajectories closest to the trajectory. diff --git a/pymove/semantic/semantic.py b/pymove/semantic/semantic.py index 6416ab62..ab69f96d 100644 --- a/pymove/semantic/semantic.py +++ b/pymove/semantic/semantic.py @@ -109,10 +109,10 @@ def _process_simple_filter( @timer_decorator def outliers( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - jump_coefficient: Optional[float] = 3.0, - threshold: Optional[float] = 1, - new_label: Optional[Text] = OUTLIER, - inplace: Optional[bool] = False + jump_coefficient: float = 3.0, + threshold: float = 1, + new_label: Text = OUTLIER, + inplace: bool = False ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Create or update a boolean feature to detect outliers. @@ -174,8 +174,8 @@ def outliers( def create_or_update_out_of_the_bbox( move_data: DataFrame, bbox: Tuple[int, int, int, int], - new_label: Optional[Text] = OUT_BBOX, - inplace: Optional[bool] = False + new_label: Text = OUT_BBOX, + inplace: bool = False ) -> Optional[DataFrame]: """ Create or update a boolean feature to detect points out of the bbox. @@ -201,6 +201,10 @@ def create_or_update_out_of_the_bbox( Returns dataframe with a boolean feature with detected points out of the bbox, or None + Raises + ------ + ValueError + If feature generation fails """ if not inplace: move_data = move_data.copy() @@ -208,8 +212,12 @@ def create_or_update_out_of_the_bbox( logger.debug('\nCreate or update boolean feature to detect points out of the bbox') filtered_ = filters.by_bbox(move_data, bbox, filter_out=True) + if filtered_ is None: + raise ValueError('Filter bbox failed!') + logger.debug('...Creating a new label named as %s' % new_label) move_data[new_label] = False + if filtered_.shape[0] > 0: logger.debug('...Setting % as True\n' % new_label) move_data.at[filtered_.index, new_label] = True @@ -222,9 +230,9 @@ def create_or_update_out_of_the_bbox( @timer_decorator def create_or_update_gps_deactivated_signal( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - max_time_between_adj_points: Optional[float] = 7200, - new_label: Optional[Text] = DEACTIVATED, - inplace: Optional[bool] = False + max_time_between_adj_points: float = 7200, + new_label: Text = DEACTIVATED, + inplace: bool = False ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Creates a new feature that inform if point invalid. @@ -272,9 +280,9 @@ def create_or_update_gps_deactivated_signal( @timer_decorator def create_or_update_gps_jump( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - max_dist_between_adj_points: Optional[float] = 3000, - new_label: Optional[Text] = JUMP, - inplace: Optional[bool] = False + max_dist_between_adj_points: float = 3000, + new_label: Text = JUMP, + inplace: bool = False ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Creates a new feature that inform if point is a gps jump. @@ -321,13 +329,13 @@ def create_or_update_gps_jump( @timer_decorator def create_or_update_short_trajectory( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - max_dist_between_adj_points: Optional[float] = 3000, - max_time_between_adj_points: Optional[float] = 7200, - max_speed_between_adj_points: Optional[float] = 50, - k_segment_max: Optional[int] = 50, - label_tid: Optional[Text] = TID_PART, - new_label: Optional[Text] = SHORT, - inplace: Optional[bool] = False + 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, + inplace: bool = False ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Creates a new feature that inform if point belongs to a short trajectory. @@ -390,10 +398,10 @@ def create_or_update_short_trajectory( @timer_decorator def create_or_update_gps_block_signal( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - max_time_stop: Optional[float] = 7200, - new_label: Optional[Text] = BLOCK, - label_tid: Optional[Text] = TID_PART, - inplace: Optional[bool] = False + max_time_stop: float = 7200, + new_label: Text = BLOCK, + label_tid: Text = TID_PART, + inplace: bool = False ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Creates a new feature that inform segments with periods without moving. @@ -453,11 +461,11 @@ def create_or_update_gps_block_signal( @timer_decorator def filter_block_signal_by_repeated_amount_of_points( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - amount_max_of_points_stop: Optional[float] = 30.0, - max_time_stop: Optional[float] = 7200, - filter_out: Optional[bool] = False, - label_tid: Optional[Text] = TID_PART, - inplace: Optional[bool] = False + amount_max_of_points_stop: float = 30.0, + max_time_stop: float = 7200, + filter_out: bool = False, + label_tid: Text = TID_PART, + inplace: bool = False ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Filters from dataframe points with blocked signal by amount of points. @@ -514,10 +522,10 @@ def filter_block_signal_by_repeated_amount_of_points( @timer_decorator def filter_block_signal_by_time( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - max_time_stop: Optional[float] = 7200, - filter_out: Optional[bool] = False, - label_tid: Optional[Text] = TID_PART, - inplace: Optional[bool] = False + max_time_stop: float = 7200, + filter_out: bool = False, + label_tid: Text = TID_PART, + inplace: bool = False ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Filters from dataframe points with blocked signal by time. @@ -575,12 +583,12 @@ def filter_block_signal_by_time( @timer_decorator def filter_longer_time_to_stop_segment_by_id( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - dist_radius: Optional[float] = 30, - time_radius: Optional[float] = 900, - label_id: Optional[Text] = TRAJ_ID, - label_segment_stop: Optional[Text] = SEGMENT_STOP, - filter_out: Optional[bool] = False, - inplace: Optional[bool] = False + dist_radius: float = 30, + time_radius: float = 900, + label_id: Text = TRAJ_ID, + label_segment_stop: Text = SEGMENT_STOP, + filter_out: bool = False, + inplace: bool = False ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Filters from dataframe segment with longest stop time. diff --git a/pymove/tests/test_utils_mem.py b/pymove/tests/test_utils_mem.py index d9044f7f..65042f32 100644 --- a/pymove/tests/test_utils_mem.py +++ b/pymove/tests/test_utils_mem.py @@ -29,15 +29,13 @@ def test_reduce_mem_usage_automatic(): move_df = _default_move_df() - expected_initial_size = 280 - - expected_final_size = 232 - - assert abs(mem.total_size(move_df) - expected_initial_size) <= 20 + initial_size = mem.total_size(move_df) mem.reduce_mem_usage_automatic(move_df) - assert abs(mem.total_size(move_df) - expected_final_size) <= 20 + final_size = mem.total_size(move_df) + + assert initial_size > final_size def test_total_size(): diff --git a/pymove/utils/conversions.py b/pymove/utils/conversions.py index b17460c1..9cb45b84 100644 --- a/pymove/utils/conversions.py +++ b/pymove/utils/conversions.py @@ -30,6 +30,7 @@ from typing import TYPE_CHECKING, List, Optional, Text, Union import numpy as np +from numpy import ndarray from pandas import DataFrame from shapely.geometry import Point @@ -81,7 +82,7 @@ def lat_meters(lat: float) -> float: def meters_to_eps( - radius_meters: float, earth_radius: Optional[float] = EARTH_RADIUS + radius_meters: float, earth_radius: float = EARTH_RADIUS ) -> float: """ Converts radius in meters to eps. @@ -108,7 +109,7 @@ def meters_to_eps( return radius_meters / earth_radius -def list_to_str(input_list: List, delimiter: Optional[Text] = ',') -> Text: +def list_to_str(input_list: List, delimiter: Text = ',') -> Text: """ Concatenates a list elements, joining them by the separator `delimiter`. @@ -191,7 +192,7 @@ def list_to_svm_line(original_list: List) -> Text: return svm_line.rstrip() -def lon_to_x_spherical(lon: float) -> float: +def lon_to_x_spherical(lon: Union[float, ndarray]) -> Union[float, ndarray]: """ Convert longitude to X EPSG:3857 WGS 84/Pseudo-Mercator. @@ -221,7 +222,7 @@ def lon_to_x_spherical(lon: float) -> float: return 6378137 * np.radians(lon) -def lat_to_y_spherical(lat: float) -> float: +def lat_to_y_spherical(lat: Union[float, ndarray]) -> Union[float, ndarray]: """ Convert latitude to Y EPSG:3857 WGS 84/Pseudo-Mercator. @@ -251,7 +252,7 @@ def lat_to_y_spherical(lat: float) -> float: return 6378137 * np.log(np.tan(np.pi / 4 + np.radians(lat) / 2.0)) -def x_to_lon_spherical(x: float) -> float: +def x_to_lon_spherical(x: Union[float, ndarray]) -> Union[float, ndarray]: """ Convert X EPSG:3857 WGS 84 / Pseudo-Mercator to longitude. @@ -280,7 +281,7 @@ def x_to_lon_spherical(x: float) -> float: return np.degrees(x / 6378137.0) -def y_to_lat_spherical(y: float) -> float: +def y_to_lat_spherical(y: Union[float, ndarray]) -> Union[float, ndarray]: """ Convert Y EPSG:3857 WGS 84 / Pseudo-Mercator to latitude. @@ -311,9 +312,9 @@ def y_to_lat_spherical(y: float) -> float: def geometry_points_to_lat_and_lon( move_data: DataFrame, - geometry_label: Optional[Text] = GEOMETRY, - drop_geometry: Optional[bool] = False, - inplace: Optional[bool] = False + geometry_label: Text = GEOMETRY, + drop_geometry: bool = False, + inplace: bool = False ) -> DataFrame: """ Creates lat and lon columns from Points in geometry column. @@ -368,8 +369,8 @@ def geometry_points_to_lat_and_lon( def lat_and_lon_decimal_degrees_to_decimal( move_data: DataFrame, - latitude: Optional[Text] = LATITUDE, - longitude: Optional[Text] = LONGITUDE + latitude: Text = LATITUDE, + longitude: Text = LONGITUDE ) -> DataFrame: """ Converts latitude and longitude format from decimal degrees to decimal format. @@ -419,9 +420,9 @@ def _decimal_degree_to_decimal(row): def ms_to_kmh( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - label_speed: Optional[Text] = SPEED_TO_PREV, - new_label: Optional[Text] = None, - inplace: Optional[bool] = False, + label_speed: Text = SPEED_TO_PREV, + new_label: Text = None, + inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Convert values, in ms, in label_speed column to kmh. @@ -496,9 +497,9 @@ def ms_to_kmh( def kmh_to_ms( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - label_speed: Optional[Text] = SPEED_TO_PREV, + label_speed: Text = SPEED_TO_PREV, new_label: Optional[Text] = None, - inplace: Optional[bool] = False, + inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Convert values, in kmh, in label_speed column to ms. @@ -567,9 +568,9 @@ def kmh_to_ms( def meters_to_kilometers( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - label_distance: Optional[Text] = DIST_TO_PREV, + label_distance: Text = DIST_TO_PREV, new_label: Optional[Text] = None, - inplace: Optional[bool] = False, + inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Convert values, in meters, in label_distance column to kilometers. @@ -637,9 +638,9 @@ def meters_to_kilometers( def kilometers_to_meters( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - label_distance: Optional[Text] = DIST_TO_PREV, + label_distance: Text = DIST_TO_PREV, new_label: Optional[Text] = None, - inplace: Optional[bool] = False, + inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Convert values, in kilometers, in label_distance column to meters. @@ -708,9 +709,9 @@ def kilometers_to_meters( def seconds_to_minutes( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - label_time: Optional[Text] = TIME_TO_PREV, + label_time: Text = TIME_TO_PREV, new_label: Optional[Text] = None, - inplace: Optional[bool] = False, + inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Convert values, in seconds, in label_distance column to minutes. @@ -778,9 +779,9 @@ def seconds_to_minutes( def minute_to_seconds( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - label_time: Optional[Text] = TIME_TO_PREV, + label_time: Text = TIME_TO_PREV, new_label: Optional[Text] = None, - inplace: Optional[bool] = False, + inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Convert values, in minutes, in label_distance column to seconds. @@ -849,9 +850,9 @@ def minute_to_seconds( def minute_to_hours( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - label_time: Optional[Text] = TIME_TO_PREV, + label_time: Text = TIME_TO_PREV, new_label: Optional[Text] = None, - inplace: Optional[bool] = False, + inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Convert values, in minutes, in label_distance column to hours. @@ -921,9 +922,9 @@ def minute_to_hours( def hours_to_minute( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - label_time: Optional[Text] = TIME_TO_PREV, + label_time: Text = TIME_TO_PREV, new_label: Optional[Text] = None, - inplace: Optional[bool] = False, + inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Convert values, in hours, in label_distance column to minute. @@ -992,9 +993,9 @@ def hours_to_minute( def seconds_to_hours( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - label_time: Optional[Text] = TIME_TO_PREV, + label_time: Text = TIME_TO_PREV, new_label: Optional[Text] = None, - inplace: Optional[bool] = False, + inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ Convert values, in seconds, in label_distance column to hours. @@ -1063,9 +1064,9 @@ def seconds_to_hours( def hours_to_seconds( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - label_time: Optional[Text] = TIME_TO_PREV, + label_time: Text = TIME_TO_PREV, new_label: Optional[Text] = None, - inplace: Optional[bool] = False, + inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ 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 87c45960..d5f2e1b5 100644 --- a/pymove/utils/data_augmentation.py +++ b/pymove/utils/data_augmentation.py @@ -28,7 +28,9 @@ def append_row( - data: DataFrame, row: Optional[Series] = None, columns: Optional[Dict] = None + data: DataFrame, + row: Optional[Series] = None, + columns: Optional[Dict] = None ): """ Insert a new line in the dataframe with the information passed by parameter. @@ -103,7 +105,7 @@ def generate_trajectories_df( def generate_start_feature( - data: DataFrame, label_trajectory: Optional[Text] = TRAJECTORY + data: DataFrame, label_trajectory: Text = TRAJECTORY ): """ Removes the last point from the trajectory and adds it in a new column 'destiny'. @@ -123,7 +125,7 @@ def generate_start_feature( def generate_destiny_feature( - data: DataFrame, label_trajectory: Optional[Text] = TRAJECTORY + data: DataFrame, label_trajectory: Text = TRAJECTORY ): """ Removes the first point from the trajectory and adds it in a new column 'start'. @@ -143,7 +145,7 @@ def generate_destiny_feature( def split_crossover( - sequence_a: List, sequence_b: List, frac: Optional[float] = 0.5 + sequence_a: List, sequence_b: List, frac: float = 0.5 ) -> Tuple[List, List]: """ Divides two arrays in the indicated ratio and exchange their halves. @@ -178,7 +180,7 @@ def split_crossover( return sequence_a, sequence_b -def _augmentation(data: DataFrame, aug_df: DataFrame, frac: Optional[float] = 0.5): +def _augmentation(data: DataFrame, aug_df: DataFrame, frac: float = 0.5): """ Generates new data with unobserved trajectories. @@ -223,8 +225,8 @@ def _augmentation(data: DataFrame, aug_df: DataFrame, frac: Optional[float] = 0. value2 = data.at[idx_, col] if isinstance(value1, str) and isinstance(value2, str): - sequences1.append(value1 + '_' + value2) - sequences2.append(value2 + '_' + value1) + sequences1.append(value1 + '_' + value2) # type: ignore + sequences2.append(value2 + '_' + value1) # type: ignore else: sequences1.append(value1) sequences2.append(value2) @@ -238,10 +240,10 @@ def _augmentation(data: DataFrame, aug_df: DataFrame, frac: Optional[float] = 0. def augmentation_trajectories_df( data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - restriction: Optional[Text] = 'destination only', - label_trajectory: Optional[Text] = TRAJECTORY, - insert_at_df: Optional[bool] = False, - frac: Optional[float] = 0.5, + restriction: Text = 'destination only', + label_trajectory: Text = TRAJECTORY, + insert_at_df: bool = False, + frac: float = 0.5, ) -> DataFrame: """ Generates new data from unobserved trajectories, given a specific restriction. @@ -334,9 +336,9 @@ def insert_points_in_df(data: DataFrame, aug_df: DataFrame): def instance_crossover_augmentation( data: DataFrame, - restriction: Optional[Text] = 'destination only', - label_trajectory: Optional[Text] = TRAJECTORY, - frac: Optional[float] = 0.5 + restriction: Text = 'destination only', + label_trajectory: Text = TRAJECTORY, + frac: float = 0.5 ): """ Generates new data from unobserved trajectories, with a specific restriction. diff --git a/pymove/utils/datetime.py b/pymove/utils/datetime.py index 523ffdac..7bc6a61a 100644 --- a/pymove/utils/datetime.py +++ b/pymove/utils/datetime.py @@ -22,7 +22,7 @@ """ -from datetime import date, datetime +from datetime import datetime from typing import Optional, Text, Union import holidays @@ -222,7 +222,7 @@ def to_day_of_week_int(dt: datetime) -> int: def working_day( dt: Union[Text, datetime], - country: Optional[Text] = 'BR', + country: Text = 'BR', state: Optional[Text] = None ) -> bool: """ @@ -267,7 +267,7 @@ def working_day( dt = str_to_datetime(dt) if isinstance(dt, datetime): - dt = date(dt.year, dt.month, dt.day) + dt = datetime(dt.year, dt.month, dt.day) if dt in holidays.CountryHoliday(country=country, prov=None, state=state): result = False @@ -489,11 +489,11 @@ def diff_time(start_time: datetime, end_time: datetime) -> int: def create_time_slot_in_minute( data: DataFrame, - slot_interval: Optional[int] = 15, - initial_slot: Optional[int] = 0, - label_datetime: Optional[Text] = DATETIME, - label_time_slot: Optional[Text] = TIME_SLOT, - inplace: Optional[bool] = False + slot_interval: int = 15, + initial_slot: int = 0, + label_datetime: Text = DATETIME, + label_time_slot: Text = TIME_SLOT, + inplace: bool = False ) -> Optional[DataFrame]: """ Partitions the time in slot windows. @@ -548,7 +548,7 @@ def create_time_slot_in_minute( def generate_time_statistics( data: DataFrame, - local_label: Optional[Text] = LOCAL_LABEL + local_label: Text = LOCAL_LABEL ): """ Calculates time statistics of the pairwise local labels. @@ -637,9 +637,9 @@ def _calc_time_threshold(seg_mean: float, seg_std: float) -> float: def threshold_time_statistics( df_statistics: DataFrame, - mean_coef: Optional[float] = 1.0, - std_coef: Optional[float] = 1.0, - inplace: Optional[bool] = False + mean_coef: float = 1.0, + std_coef: float = 1.0, + inplace: bool = False ) -> Optional[DataFrame]: """ Calculates and creates the threshold column. diff --git a/pymove/utils/distances.py b/pymove/utils/distances.py index b21d6b76..ca9ef88c 100644 --- a/pymove/utils/distances.py +++ b/pymove/utils/distances.py @@ -8,7 +8,7 @@ medt """ -from typing import Optional, Text, Union +from typing import Text, Union import numpy as np import pandas as pd @@ -25,8 +25,8 @@ def haversine( lon1: Union[float, ndarray], lat2: Union[float, ndarray], lon2: Union[float, ndarray], - to_radians: Optional[bool] = True, - earth_radius: Optional[float] = EARTH_RADIUS + to_radians: bool = True, + earth_radius: float = EARTH_RADIUS ) -> Union[float, ndarray]: """ Calculates the great circle distance between two points on the earth. @@ -72,7 +72,7 @@ def haversine( """ if to_radians: - lat1, lon1, lat2, lon2 = np.radians([lat1, lon1, lat2, lon2]) + lat1, lon1, lat2, lon2 = np.radians([lat1, lon1, lat2, lon2]) # type: ignore a = ( np.sin((lat2 - lat1) / 2.0) ** 2 + np.cos(lat1) @@ -130,8 +130,8 @@ def euclidean_distance_in_meters( def nearest_points( traj1: DataFrame, traj2: DataFrame, - latitude: Optional[Text] = LATITUDE, - longitude: Optional[Text] = LONGITUDE, + latitude: Text = LATITUDE, + longitude: Text = 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: Optional[Text] = LATITUDE, - longitude: Optional[Text] = LONGITUDE + latitude: Text = LATITUDE, + longitude: Text = LONGITUDE ) -> float: """ Returns the Mean Euclidian Distance Predictive between two trajectories. @@ -243,9 +243,9 @@ def medp( def medt( traj1: DataFrame, traj2: DataFrame, - latitude: Optional[Text] = LATITUDE, - longitude: Optional[Text] = LONGITUDE, - datetime: Optional[Text] = DATETIME + latitude: Text = LATITUDE, + longitude: Text = LONGITUDE, + datetime: Text = DATETIME ) -> float: """ Returns the Mean Euclidian Distance Trajectory between two trajectories. @@ -286,7 +286,7 @@ def medt( >>> medt(traj_1, traj_2) 6.592419887747872e-05 """ - soma = 0 + soma = 0. proportion = 1000000000 if(len(traj2) < len(traj1)): traj1, traj2 = traj2, traj1 @@ -307,6 +307,7 @@ def medt( soma = soma + this_distance for j in range(len(traj1) + 1, len(traj2)): soma = soma + \ - float(utils.datetime.timestamp_to_millis( - traj2[datetime].iloc[j])) / proportion + float( + utils.datetime.timestamp_to_millis(traj2[datetime].iloc[j]) + ) / proportion return soma diff --git a/pymove/utils/geoutils.py b/pymove/utils/geoutils.py index 8f068eb8..0b414165 100644 --- a/pymove/utils/geoutils.py +++ b/pymove/utils/geoutils.py @@ -8,7 +8,7 @@ """ -from typing import Optional, Text, Tuple +from typing import Text, Tuple import geohash2 as gh import numpy as np @@ -69,7 +69,7 @@ def v_color(ob: BaseGeometry) -> Text: return COLORS[ob.is_simple + 33] -def _encode(lat: float, lon: float, precision: Optional[float] = 15) -> Text: +def _encode(lat: float, lon: float, precision: float = 15) -> Text: """ Encodes latitude/longitude to geohash. @@ -131,7 +131,7 @@ def _decode(geohash: Text) -> Tuple[float, float]: return gh.decode(geohash) -def _bin_geohash(lat: float, lon: float, precision: Optional[float] = 15) -> ndarray: +def _bin_geohash(lat: float, lon: float, precision: float = 15) -> ndarray: """ Transforms a point's geohash into a binary array. @@ -168,7 +168,7 @@ def _bin_geohash(lat: float, lon: float, precision: Optional[float] = 15) -> nda def _reset_and_create_arrays_none( - data: DataFrame, reset_index: Optional[bool] = True + data: DataFrame, reset_index: bool = True ) -> Tuple[ndarray, ndarray, ndarray, ndarray]: """ Reset the df index and create arrays of none values. @@ -218,7 +218,7 @@ def _reset_and_create_arrays_none( return latitudes, longitudes, geohash, bin_geohash -def create_geohash_df(data: DataFrame, precision: Optional[float] = 15): +def create_geohash_df(data: DataFrame, precision: float = 15): """ Create geohash from geographic coordinates and integrate with df. @@ -263,7 +263,7 @@ def create_geohash_df(data: DataFrame, precision: Optional[float] = 15): data[GEOHASH] = geohash -def create_bin_geohash_df(data: DataFrame, precision: Optional[float] = 15): +def create_bin_geohash_df(data: DataFrame, precision: float = 15): """ Create trajectory geohash binaries and integrate with df. @@ -310,8 +310,8 @@ def create_bin_geohash_df(data: DataFrame, precision: Optional[float] = 15): def decode_geohash_to_latlon( data: DataFrame, - label_geohash: Optional[Text] = GEOHASH, - reset_index: Optional[bool] = True + label_geohash: Text = GEOHASH, + reset_index: bool = True ): """ Decode feature with hash of trajectories back to geographic coordinates. diff --git a/pymove/utils/integration.py b/pymove/utils/integration.py index fd320af9..7fdf07e8 100644 --- a/pymove/utils/integration.py +++ b/pymove/utils/integration.py @@ -49,7 +49,7 @@ from pymove.utils.log import logger, progress_bar -def union_poi_bank(data: DataFrame, label_poi: Optional[Text] = TYPE_POI): +def union_poi_bank(data: DataFrame, label_poi: Text = TYPE_POI): """ Performs the union between the different bank categories. @@ -76,7 +76,7 @@ def union_poi_bank(data: DataFrame, label_poi: Optional[Text] = TYPE_POI): data.at[data[filter_bank].index, label_poi] = 'banks' -def union_poi_bus_station(data: DataFrame, label_poi: Optional[Text] = TYPE_POI): +def union_poi_bus_station(data: DataFrame, label_poi: Text = TYPE_POI): """ Performs the union between the different bus station categories. @@ -97,7 +97,7 @@ def union_poi_bus_station(data: DataFrame, label_poi: Optional[Text] = TYPE_POI) data.at[data[filter_bus_station].index, label_poi] = 'bus_station' -def union_poi_bar_restaurant(data: DataFrame, label_poi: Optional[Text] = TYPE_POI): +def union_poi_bar_restaurant(data: DataFrame, label_poi: Text = TYPE_POI): """ Performs the union between bar and restaurant categories. @@ -116,7 +116,7 @@ def union_poi_bar_restaurant(data: DataFrame, label_poi: Optional[Text] = TYPE_P data.at[data[filter_bar_restaurant].index, label_poi] = 'bar-restaurant' -def union_poi_parks(data: DataFrame, label_poi: Optional[Text] = TYPE_POI): +def union_poi_parks(data: DataFrame, label_poi: Text = TYPE_POI): """ Performs the union between park categories. @@ -135,7 +135,7 @@ def union_poi_parks(data: DataFrame, label_poi: Optional[Text] = TYPE_POI): data.at[data[filter_parks].index, label_poi] = 'parks' -def union_poi_police(data: DataFrame, label_poi: Optional[Text] = TYPE_POI): +def union_poi_police(data: DataFrame, label_poi: Text = TYPE_POI): """ Performs the union between police categories. @@ -155,7 +155,7 @@ def union_poi_police(data: DataFrame, label_poi: Optional[Text] = TYPE_POI): def join_collective_areas( - gdf_: DataFrame, gdf_rules_: DataFrame, label_geometry: Optional[Text] = GEOMETRY + gdf_: DataFrame, gdf_rules_: DataFrame, label_geometry: Text = GEOMETRY ): """ Performs the integration between trajectories and collective areas. @@ -187,9 +187,9 @@ def join_collective_areas( def _reset_and_creates_id_and_lat_lon( data: DataFrame, df_pois: DataFrame, - lat_lon_poi: Optional[bool] = True, - reset_index: Optional[bool] = True -) -> Tuple[ndarray, ndarray, ndarray, ndarray]: + lat_lon_poi: bool = True, + reset_index: bool = True +) -> Tuple[ndarray, ndarray, ndarray, ndarray, ndarray]: """ Resets the indexes of the dataframes. @@ -284,7 +284,7 @@ def _reset_set_window__and_creates_event_id_type( def _reset_set_window_and_creates_event_id_type_all( - data: DataFrame, df_events: DataFrame, label_date: Text, time_window: int + data: DataFrame, df_events: DataFrame, label_date: Text, time_window: float ) -> Tuple[Series, Series, ndarray, ndarray, ndarray]: """ Resets the indexes of the dataframes. @@ -301,7 +301,7 @@ def _reset_set_window_and_creates_event_id_type_all( The input event point of interest data. label_date : str Label of data referring to the datetime. - time_window : Int + time_window : float Number of seconds of the time window. Returns @@ -330,9 +330,9 @@ def _reset_set_window_and_creates_event_id_type_all( def join_with_pois( data: DataFrame, df_pois: DataFrame, - label_id: Optional[Text] = TRAJ_ID, - label_poi_name: Optional[Text] = NAME_POI, - reset_index: Optional[Text] = True + label_id: Text = TRAJ_ID, + label_poi_name: Text = NAME_POI, + reset_index: bool = True ): """ Performs the integration between trajectories and points of interest. @@ -394,10 +394,10 @@ def join_with_pois( def join_with_pois_optimizer( data, df_pois: DataFrame, - label_id: Optional[Text] = TRAJ_ID, - label_poi_name: Optional[Text] = NAME_POI, + label_id: Text = TRAJ_ID, + label_poi_name: Text = NAME_POI, dist_poi: Optional[List] = None, - reset_index: Optional[Text] = True + reset_index: bool = True ): """ Performs the integration between trajectories and points of interest. @@ -426,6 +426,8 @@ def join_with_pois_optimizer( by default True """ + if dist_poi is None: + dist_poi = [] if len(df_pois[label_poi_name].unique()) == len(dist_poi): values = _reset_and_creates_id_and_lat_lon(data, df_pois, False, reset_index) minimum_distances, ids_pois, tag_pois, lat_poi, lon_poi = values @@ -444,7 +446,7 @@ def join_with_pois_optimizer( # First iteration is minimum distances if idx == 0: - minimum_distances = np.float64( + minimum_distances = np.array( haversine( lat_poi, lon_poi, @@ -486,8 +488,8 @@ def join_with_pois_optimizer( def join_with_pois_by_category( data: DataFrame, df_pois: DataFrame, - label_category: Optional[Text] = TYPE_POI, - label_id: Optional[Text] = TRAJ_ID + label_category: Text = TYPE_POI, + label_id: Text = TRAJ_ID ): """ Performs the integration between trajectories and points of interest. @@ -561,10 +563,10 @@ def join_with_pois_by_category( def join_with_poi_datetime( data: DataFrame, df_events: DataFrame, - label_date: Optional[Text] = DATETIME, - time_window: Optional[int] = 900, - label_event_id: Optional[Text] = EVENT_ID, - label_event_type: Optional[Text] = EVENT_TYPE + label_date: Text = DATETIME, + time_window: int = 900, + label_event_id: Text = EVENT_ID, + label_event_type: Text = EVENT_TYPE ): """ Performs the integration between trajectories and points of interest. @@ -591,6 +593,11 @@ def join_with_poi_datetime( label_event_type : str, optional Label of df_events referring to the type of the event, by default EVENT_TYPE + Raises + ------ + ValueError + If feature generation fails + """ values = _reset_set_window__and_creates_event_id_type( data, df_events, label_date, time_window @@ -602,6 +609,10 @@ def join_with_poi_datetime( df_filtered = filters.by_datetime( df_events, window_starts[idx], window_ends[idx] ) + + if df_filtered is None: + raise ValueError('Filter datetime failed!') + size_filter = df_filtered.shape[0] if size_filter > 0: @@ -638,10 +649,10 @@ def join_with_poi_datetime( def join_with_poi_datetime_optimizer( data: DataFrame, df_events: DataFrame, - label_date: Optional[Text] = DATETIME, - time_window: Optional[int] = 900, - label_event_id: Optional[Text] = EVENT_ID, - label_event_type: Optional[Text] = EVENT_TYPE + label_date: Text = DATETIME, + time_window: int = 900, + label_event_id: Text = EVENT_ID, + label_event_type: Text = EVENT_TYPE ): """ Performs a optimized integration between trajectories and points of events. @@ -668,6 +679,11 @@ def join_with_poi_datetime_optimizer( label_event_type : str, optional Label of df_events referring to the type of the event, by default EVENT_TYPE + Raises + ------ + ValueError + If feature generation fails + """ values = _reset_set_window__and_creates_event_id_type( data, df_events, label_date, time_window @@ -691,6 +707,9 @@ def join_with_poi_datetime_optimizer( data, window_starts[idx], window_ends[idx] ) + if df_filtered is None: + raise ValueError('Filtering datetime failed!') + size_filter = df_filtered.shape[0] if size_filter > 0: @@ -737,11 +756,11 @@ def join_with_poi_datetime_optimizer( def join_with_pois_by_dist_and_datetime( data: DataFrame, df_pois: DataFrame, - label_date: Optional[Text] = DATETIME, - label_event_id: Optional[Text] = EVENT_ID, - label_event_type: Optional[Text] = EVENT_TYPE, - time_window: Optional[float] = 3600, - radius: Optional[float] = 1000, + label_date: Text = DATETIME, + label_event_id: Text = EVENT_ID, + label_event_type: Text = EVENT_TYPE, + time_window: float = 3600, + radius: float = 1000, ): """ Performs the integration between trajectories and points of interest. @@ -769,6 +788,11 @@ def join_with_pois_by_dist_and_datetime( radius: float, optional maximum radius of pois, by default 1000 + Raises + ------ + ValueError + If feature generation fails + """ if label_date not in df_pois: raise KeyError("POI's DataFrame must contain a %s column" % label_date) @@ -789,9 +813,12 @@ def join_with_pois_by_dist_and_datetime( # filter event by radius df_filtered = filters.by_bbox( - df_pois, bbox + df_pois, bbox, inplace=False ) + if df_filtered is None: + raise ValueError('Filtering bbox failed') + # filter event by datetime filters.by_datetime( df_filtered, @@ -836,10 +863,10 @@ def join_with_pois_by_dist_and_datetime( def join_with_home_by_id( data: DataFrame, df_home: DataFrame, - label_id: Optional[Text] = TRAJ_ID, - label_address: Optional[Text] = ADDRESS, - label_city: Optional[Text] = CITY, - drop_id_without_home: Optional[bool] = False, + label_id: Text = TRAJ_ID, + label_address: Text = ADDRESS, + label_city: Text = CITY, + drop_id_without_home: bool = False, ): """ Performs the integration between trajectories and home points. @@ -913,12 +940,12 @@ def join_with_home_by_id( def merge_home_with_poi( data: DataFrame, - label_dist_poi: Optional[Text] = DIST_POI, - label_name_poi: Optional[Text] = NAME_POI, - label_id_poi: Optional[Text] = ID_POI, - label_home: Optional[Text] = HOME, - label_dist_home: Optional[Text] = DIST_HOME, - drop_columns: Optional[bool] = True, + 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, + drop_columns: bool = True, ): """ Performs or merges the points of interest and the trajectories. diff --git a/pymove/utils/log.py b/pymove/utils/log.py index 053f5f0d..c8fed867 100644 --- a/pymove/utils/log.py +++ b/pymove/utils/log.py @@ -34,7 +34,7 @@ def set_verbosity(level): shell_handler.setLevel(level) -def timer_decorator(func: Callable) -> wraps: +def timer_decorator(func: Callable) -> Callable: """A decorator that prints how long a function took to run.""" @wraps(func) @@ -75,7 +75,7 @@ def _log_progress( is_iterator = False if total is None: try: - total = len(sequence) + total = len(sequence) # type: ignore except TypeError: is_iterator = True if total is not None: diff --git a/pymove/utils/math.py b/pymove/utils/math.py index 0fb4019b..14dd4b94 100644 --- a/pymove/utils/math.py +++ b/pymove/utils/math.py @@ -203,7 +203,7 @@ def arrays_avg( 'values_array and qt_array must have the same number of rows' ) - result = 0 + result = 0. for i, j in zip(values_array, weights_array): result += i * j @@ -238,8 +238,8 @@ def array_stats(values_array: List[float]) -> Tuple[float, float, int]: >>> print(array_stats(list), type(array_stats(list))) (39.5, 327.25, 5) """ - sum_ = 0 - sum_sq = 0 + sum_ = 0. + sum_sq = 0. n = 0 for item in values_array: sum_ += item diff --git a/pymove/utils/mem.py b/pymove/utils/mem.py index d14e74f5..f67b26ae 100644 --- a/pymove/utils/mem.py +++ b/pymove/utils/mem.py @@ -11,11 +11,12 @@ """ import os +import re import time from collections import deque from itertools import chain from sys import getsizeof -from typing import Callable, Dict, Optional, Text +from typing import Dict, Text import numpy as np import psutil @@ -55,7 +56,7 @@ def reduce_mem_usage_automatic(df: DataFrame): for col in df.columns: col_type = df[col].dtype - if str(col_type) == 'int': + if re.match('int', str(col_type)): c_min = df[col].min() c_max = df[col].max() if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max: @@ -95,7 +96,7 @@ def reduce_mem_usage_automatic(df: DataFrame): and c_max < np.iinfo(np.uint64).max ): df[col] = df[col].astype(np.uint64) - elif col_type == np.float: + elif re.match('float', str(col_type)): c_min = df[col].min() c_max = df[col].max() if ( @@ -119,7 +120,7 @@ def reduce_mem_usage_automatic(df: DataFrame): def total_size( - o: object, handlers: Dict = None, verbose: Optional[bool] = True + o: object, handlers: Dict = None, verbose: bool = True ) -> float: """ Calculates the approximate memory footprint of an given object. @@ -268,13 +269,13 @@ def end_operation(operation: Dict) -> Dict: } -def sizeof_fmt(mem_usage: int, suffix: Optional[Text] = 'B') -> Text: +def sizeof_fmt(mem_usage: float, suffix: Text = 'B') -> Text: """ Returns the memory usage calculation of the last function. Parameters ---------- - mem_usage : int + mem_usage : float memory usage in bytes suffix: string, optional @@ -300,7 +301,7 @@ def sizeof_fmt(mem_usage: int, suffix: Optional[Text] = 'B') -> Text: def top_mem_vars( - variables: Callable, n: Optional[int] = 10, hide_private=True + variables: Dict, n: int = 10, hide_private=True ) -> DataFrame: """ Shows the sizes of the active variables. @@ -332,7 +333,7 @@ def top_mem_vars( 3 top_mem_vars 136.0 B 4 np 72.0 B """ - vars_ = ((name, getsizeof(value)) for name, value in variables.items()) + vars_ = iter([(name, getsizeof(value)) for name, value in variables.items()]) if hide_private: vars_ = filter(lambda x: not x[0].startswith('_'), vars_) top_vars = DataFrame( diff --git a/pymove/utils/trajectories.py b/pymove/utils/trajectories.py index ff822616..7b2036a9 100644 --- a/pymove/utils/trajectories.py +++ b/pymove/utils/trajectories.py @@ -14,7 +14,7 @@ from itertools import chain -from typing import Any, Dict, List, Optional, Text, Union +from typing import Any, Dict, List, Optional, Text, Tuple, Union import numpy as np from numpy import ndarray @@ -29,12 +29,12 @@ def read_csv( filepath_or_buffer: FilePathOrBuffer, - latitude: Optional[Text] = LATITUDE, - longitude: Optional[Text] = LONGITUDE, - datetime: Optional[Text] = DATETIME, - traj_id: Optional[Text] = TRAJ_ID, - type_: Optional[Text] = TYPE_PANDAS, - n_partitions: Optional[int] = 1, + latitude: Text = LATITUDE, + longitude: Text = LONGITUDE, + datetime: Text = DATETIME, + traj_id: Text = TRAJ_ID, + type_: Text = TYPE_PANDAS, + n_partitions: int = 1, **kwargs ) -> MoveDataFrame: """ @@ -119,7 +119,9 @@ def invert_dict(d: Dict) -> Dict: def flatten_dict( - d: Dict, parent_key: Optional[Text] = '', sep: Optional[Text] = '_' + d: Dict, + parent_key: Text = '', + sep: Text = '_' ) -> Dict: """ Flattens a nested dictionary. @@ -151,9 +153,9 @@ def flatten_dict( """ if not isinstance(d, dict): return {parent_key: d} - items = [] + items: List[Tuple[Text, Any]] = [] for k, v in d.items(): - new_key = parent_key + sep + k if parent_key else k + new_key = f'{parent_key}{sep}{k}' if parent_key else k if isinstance(v, dict): items.extend(flatten_dict(v, new_key, sep=sep).items()) else: @@ -264,6 +266,8 @@ def shift( [2 3 4 5 6 7 0] """ result = np.empty_like(arr) + arr = np.array(arr) + if fill_value is None: dtype = result.dtype if np.issubdtype(dtype, np.bool_): diff --git a/pymove/utils/visual.py b/pymove/utils/visual.py index 2599960d..2355b7ab 100644 --- a/pymove/utils/visual.py +++ b/pymove/utils/visual.py @@ -11,7 +11,7 @@ """ -from typing import List, Optional, Text, Tuple +from typing import List, Text, Tuple from branca.element import MacroElement, Template from folium import Map @@ -329,7 +329,7 @@ def get_cmap(cmap: Text) -> Colormap: def save_wkt( - move_data: DataFrame, filename: Text, label_id: Optional[Text] = TRAJ_ID + move_data: DataFrame, filename: Text, label_id: Text = TRAJ_ID ): """ Save a visualization in a map in a new file .wkt. diff --git a/pymove/visualization/folium.py b/pymove/visualization/folium.py index aa24b06c..35560a6f 100644 --- a/pymove/visualization/folium.py +++ b/pymove/visualization/folium.py @@ -64,10 +64,10 @@ def save_map( move_data: DataFrame, filename: Text, - tiles: Optional[Text] = TILES[0], - label_id: Optional[Text] = TRAJ_ID, - cmap: Optional[Text] = 'Set1', - return_map: Optional[bool] = False + tiles: Text = TILES[0], + label_id: Text = TRAJ_ID, + cmap: Text = 'Set1', + return_map: bool = False ) -> Optional[Map]: """ Save a visualization in a map in a new file. @@ -123,8 +123,8 @@ def create_base_map( move_data: DataFrame, lat_origin: Optional[float] = None, lon_origin: Optional[float] = None, - tile: Optional[Text] = TILES[0], - default_zoom_start: Optional[float] = 12, + tile: Text = TILES[0], + default_zoom_start: float = 12, ) -> Map: """ Generates a folium map. @@ -164,12 +164,12 @@ def heatmap( n_rows: Optional[int] = None, lat_origin: Optional[float] = None, lon_origin: Optional[float] = None, - zoom_start: Optional[float] = 12, - radius: Optional[float] = 8, + zoom_start: float = 12, + radius: float = 8, base_map: Optional[Map] = None, - tile: Optional[Text] = TILES[0], - save_as_html: Optional[bool] = False, - filename: Optional[Text] = 'heatmap.html', + tile: Text = TILES[0], + save_as_html: bool = False, + filename: Text = 'heatmap.html', ) -> Map: """ Generate visualization of Heat Map using folium plugin. @@ -237,14 +237,14 @@ def heatmap_with_time( n_rows: Optional[int] = None, lat_origin: Optional[float] = None, lon_origin: Optional[float] = None, - zoom_start: Optional[float] = 12, - radius: Optional[float] = 8, - min_opacity: Optional[float] = 0.5, - max_opacity: Optional[float] = 0.8, + zoom_start: float = 12, + radius: float = 8, + min_opacity: float = 0.5, + max_opacity: float = 0.8, base_map: Optional[Map] = None, - tile: Optional[Text] = TILES[0], - save_as_html: Optional[bool] = False, - filename: Optional[Text] = 'heatmap_time.html', + tile: Text = TILES[0], + save_as_html: bool = False, + filename: Text = 'heatmap_time.html', ) -> Map: """ Generate visualization of Heat Map using folium plugin. @@ -329,11 +329,11 @@ def cluster( n_rows: Optional[int] = None, lat_origin: Optional[float] = None, lon_origin: Optional[float] = None, - zoom_start: Optional[float] = 12, + zoom_start: float = 12, base_map: Optional[Map] = None, - tile: Optional[Text] = TILES[0], - save_as_html: Optional[bool] = False, - filename: Optional[Text] = 'cluster.html', + tile: Text = TILES[0], + save_as_html: bool = False, + filename: Text = 'cluster.html', ) -> Map: """ Generate visualization of Heat Map using folium plugin. @@ -407,11 +407,11 @@ def faster_cluster( n_rows: Optional[int] = None, lat_origin: Optional[float] = None, lon_origin: Optional[float] = None, - zoom_start: Optional[float] = 12, + zoom_start: float = 12, base_map: Optional[Map] = None, - tile: Optional[Text] = TILES[0], - save_as_html: Optional[bool] = False, - filename: Optional[Text] = 'faster_cluster.html', + tile: Text = TILES[0], + save_as_html: bool = False, + filename: Text = 'faster_cluster.html', ) -> Map: """ Generate visualization of Heat Map using folium plugin. @@ -480,11 +480,11 @@ def plot_markers( n_rows: Optional[int] = None, lat_origin: Optional[float] = None, lon_origin: Optional[float] = None, - zoom_start: Optional[float] = 12, + zoom_start: float = 12, base_map: Optional[Map] = None, - tile: Optional[Text] = TILES[0], - save_as_html: Optional[bool] = False, - filename: Optional[Text] = 'markers.html', + tile: Text = TILES[0], + save_as_html: bool = False, + filename: Text = 'markers.html', ) -> Map: """ Generate visualization of Heat Map using folium plugin. @@ -729,9 +729,9 @@ def _add_trajectories_to_folium_map( move_data: DataFrame, items: Tuple, base_map: Map, - legend: Optional[bool] = True, - save_as_html: Optional[bool] = True, - filename: Optional[Text] = 'map.html', + legend: bool = True, + save_as_html: bool = True, + filename: Text = 'map.html', ): """ Adds a trajectory to a folium map with begin and end markers. @@ -773,14 +773,14 @@ def plot_trajectories_with_folium( n_rows: Optional[int] = None, lat_origin: Optional[float] = None, lon_origin: Optional[float] = None, - zoom_start: Optional[float] = 12, - legend: Optional[bool] = True, + zoom_start: float = 12, + legend: bool = True, base_map: Optional[Map] = None, - tile: Optional[Text] = TILES[0], - save_as_html: Optional[bool] = False, + tile: Text = TILES[0], + save_as_html: bool = False, color: Optional[Union[Text, List[Text]]] = None, color_by_id: Optional[Dict] = None, - filename: Optional[Text] = 'plot_trajectories_with_folium.html', + filename: Text = 'plot_trajectories_with_folium.html', ) -> Map: """ Generate visualization of all trajectories with folium. @@ -851,13 +851,13 @@ def plot_trajectory_by_id_folium( n_rows: Optional[int] = None, lat_origin: Optional[float] = None, lon_origin: Optional[float] = None, - zoom_start: Optional[float] = 12, - legend: Optional[bool] = True, + zoom_start: float = 12, + legend: bool = True, base_map: Optional[Map] = None, - tile: Optional[Text] = TILES[0], - save_as_html: Optional[bool] = False, + tile: Text = TILES[0], + save_as_html: bool = False, color: Optional[Union[Text, List[Text]]] = None, - filename: Optional[Text] = 'plot_trajectories_with_folium.html', + filename: Text = 'plot_trajectories_with_folium.html', ) -> Map: """ Generate visualization of all trajectories with folium. @@ -930,14 +930,14 @@ def plot_trajectory_by_period( n_rows: Optional[int] = None, lat_origin: Optional[float] = None, lon_origin: Optional[float] = None, - zoom_start: Optional[float] = 12, - legend: Optional[bool] = True, + zoom_start: float = 12, + legend: bool = True, base_map: Optional[Map] = None, - tile: Optional[Text] = TILES[0], - save_as_html: Optional[bool] = False, + tile: Text = TILES[0], + save_as_html: bool = False, color: Optional[Union[Text, List[Text]]] = None, color_by_id: Optional[Dict] = None, - filename: Optional[Text] = 'plot_trajectories_by_period.html', + filename: Text = 'plot_trajectories_by_period.html', ) -> Map: """ Generate visualization of all trajectories with folium. @@ -1021,14 +1021,14 @@ def plot_trajectory_by_day_week( n_rows: Optional[int] = None, lat_origin: Optional[float] = None, lon_origin: Optional[float] = None, - zoom_start: Optional[float] = 12, - legend: Optional[bool] = True, + zoom_start: float = 12, + legend: bool = True, base_map: Optional[Map] = None, - tile: Optional[Text] = TILES[0], - save_as_html: Optional[bool] = False, + tile: Text = TILES[0], + save_as_html: bool = False, color: Optional[Union[Text, List[Text]]] = None, color_by_id: Optional[Dict] = None, - filename: Optional[Text] = 'plot_trajectories_by_day_week.html', + filename: Text = 'plot_trajectories_by_day_week.html', ) -> Map: """ Generate visualization of all trajectories with folium. @@ -1113,14 +1113,14 @@ def plot_trajectory_by_date( n_rows: Optional[int] = None, lat_origin: Optional[float] = None, lon_origin: Optional[float] = None, - zoom_start: Optional[float] = 12, - legend: Optional[bool] = True, + zoom_start: float = 12, + legend: bool = True, base_map: Optional[Map] = None, - tile: Optional[Text] = TILES[0], - save_as_html: Optional[bool] = False, + tile: Text = TILES[0], + save_as_html: bool = False, color: Optional[Union[Text, List[Text]]] = None, color_by_id: Optional[Dict] = None, - filename: Optional[Text] = 'plot_trajectories_by_date.html', + filename: Text = 'plot_trajectories_by_date.html', ) -> Map: """ Generate visualization of all trajectories with folium. @@ -1213,14 +1213,14 @@ def plot_trajectory_by_hour( n_rows: Optional[int] = None, lat_origin: Optional[float] = None, lon_origin: Optional[float] = None, - zoom_start: Optional[float] = 12, - legend: Optional[bool] = True, + zoom_start: float = 12, + legend: bool = True, base_map: Optional[Map] = None, - tile: Optional[Text] = TILES[0], - save_as_html: Optional[bool] = False, + tile: Text = TILES[0], + save_as_html: bool = False, color: Optional[Union[Text, List[Text]]] = None, color_by_id: Optional[Dict] = None, - filename: Optional[Text] = 'plot_trajectories_by_hour.html', + filename: Text = 'plot_trajectories_by_hour.html', ) -> Map: """ Generate visualization of all trajectories with folium. @@ -1301,19 +1301,19 @@ def plot_trajectory_by_hour( def plot_stops( move_data: DataFrame, - radius: Optional[float] = 0, - weight: Optional[float] = 3, + 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, - zoom_start: Optional[float] = 12, - legend: Optional[bool] = True, + zoom_start: float = 12, + legend: bool = True, base_map: Optional[Map] = None, - tile: Optional[Text] = TILES[0], - save_as_html: Optional[bool] = False, + tile: Text = TILES[0], + save_as_html: bool = False, color: Optional[Union[Text, List[Text]]] = None, - filename: Optional[Text] = 'plot_stops.html', + filename: Text = 'plot_stops.html', ) -> Map: """ Generate visualization of all trajectories with folium. @@ -1411,10 +1411,10 @@ def plot_stops( def plot_bbox( bbox_tuple: Tuple[float, float, float, float], base_map: Optional[Map] = None, - tiles: Optional[Text] = TILES[0], - color: Optional[Text] = 'red', - save_as_html: Optional[bool] = False, - filename: Optional[Text] = 'bbox.html' + tiles: Text = TILES[0], + color: Text = 'red', + save_as_html: bool = False, + filename: Text = 'bbox.html' ) -> Map: """ Plots a bbox using Folium. @@ -1528,15 +1528,15 @@ def _circle_maker( def plot_points_folium( move_data: DataFrame, - user_lat: Optional[Text] = LATITUDE, - user_lon: Optional[Text] = LONGITUDE, - user_point: Optional[Text] = USER_POINT, - radius: Optional[float] = 2, + user_lat: Text = LATITUDE, + user_lon: Text = LONGITUDE, + user_point: Text = USER_POINT, + radius: float = 2, base_map: Optional[Map] = None, slice_tags: Optional[List] = None, - tiles: Optional[Text] = TILES[0], - save_as_html: Optional[bool] = False, - filename: Optional[Text] = 'points.html' + tiles: Text = TILES[0], + save_as_html: bool = False, + filename: Text = 'points.html' ) -> Map: """ Generates a folium map with the trajectories plots and a point. @@ -1614,8 +1614,8 @@ def plot_poi_folium( base_map=None, slice_tags=None, tiles=TILES[0], - save_as_html: Optional[bool] = False, - filename: Optional[Text] = 'pois.html' + save_as_html: bool = False, + filename: Text = 'pois.html' ) -> Map: """ Receives a MoveDataFrame and returns a folium map with poi points. @@ -1671,8 +1671,8 @@ def plot_event_folium( base_map=None, slice_tags=None, tiles=TILES[0], - save_as_html: Optional[bool] = False, - filename: Optional[Text] = 'events.html' + save_as_html: bool = False, + filename: Text = 'events.html' ) -> Map: """ Receives a MoveDataFrame and returns a folium map with events. @@ -1722,17 +1722,17 @@ def show_trajs_with_event( df_event: DataFrame, window_time_event: float, radius: float, - event_lat: Optional[Text] = LATITUDE, - event_lon: Optional[Text] = LONGITUDE, - event_datetime: Optional[Text] = DATETIME, - user_lat: Optional[Text] = LATITUDE, - user_lon: Optional[Text] = LONGITUDE, - user_datetime: Optional[Text] = DATETIME, - event_id: Optional[Text] = EVENT_ID, - event_point: Optional[Text] = EVENT_POINT, - user_id: Optional[Text] = UID, - user_point: Optional[Text] = USER_POINT, - line_color: Optional[Text] = LINE_COLOR, + event_lat: Text = LATITUDE, + event_lon: Text = LONGITUDE, + event_datetime: Text = DATETIME, + user_lat: Text = LATITUDE, + user_lon: Text = LONGITUDE, + user_datetime: Text = DATETIME, + event_id: Text = EVENT_ID, + event_point: Text = EVENT_POINT, + user_id: Text = UID, + user_point: Text = USER_POINT, + line_color: Text = LINE_COLOR, slice_event_show: Optional[int] = None, slice_subject_show: Optional[int] = None, ) -> List[Map]: @@ -1904,17 +1904,17 @@ def show_traj_id_with_event( window_time_event: float, radius: float, subject_id: int, - event_lat: Optional[Text] = LATITUDE, - event_lon: Optional[Text] = LONGITUDE, - event_datetime: Optional[Text] = DATETIME, - user_lat: Optional[Text] = LATITUDE, - user_lon: Optional[Text] = LONGITUDE, - user_datetime: Optional[Text] = DATETIME, - event_id: Optional[Text] = EVENT_ID, - event_point: Optional[Text] = EVENT_POINT, - user_id: Optional[Text] = UID, - user_point: Optional[Text] = USER_POINT, - line_color: Optional[Text] = LINE_COLOR, + event_lat: Text = LATITUDE, + event_lon: Text = LONGITUDE, + event_datetime: Text = DATETIME, + user_lat: Text = LATITUDE, + user_lon: Text = LONGITUDE, + user_datetime: Text = DATETIME, + event_id: Text = EVENT_ID, + event_point: Text = EVENT_POINT, + user_id: Text = UID, + user_point: Text = USER_POINT, + line_color: Text = LINE_COLOR, slice_event_show: Optional[int] = None, slice_subject_show: Optional[int] = None, ) -> Map: @@ -1991,9 +1991,9 @@ def show_traj_id_with_event( def _create_geojson_features_line( move_data: DataFrame, - label_lat: Optional[Text] = LATITUDE, - label_lon: Optional[Text] = LONGITUDE, - label_datetime: Optional[Text] = DATETIME + label_lat: Text = LATITUDE, + label_lon: Text = LONGITUDE, + label_datetime: Text = DATETIME ) -> List: """ Create geojson features. @@ -2063,8 +2063,8 @@ def plot_traj_timestamp_geo_json( label_lon=LONGITUDE, label_datetime=DATETIME, tiles=TILES[0], - save_as_html: Optional[bool] = False, - filename: Optional[Text] = 'events.html' + save_as_html: bool = False, + filename: Text = 'events.html' ) -> Map: """ Plot trajectories wit geo_json. diff --git a/pymove/visualization/matplotlib.py b/pymove/visualization/matplotlib.py index 60559fb0..a2105cdb 100644 --- a/pymove/visualization/matplotlib.py +++ b/pymove/visualization/matplotlib.py @@ -37,12 +37,12 @@ def show_object_id_by_date( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], - create_features: Optional[bool] = True, + create_features: bool = True, kind: Optional[List] = None, - figsize: Optional[Tuple[float, float]] = (21, 9), - return_fig: Optional[bool] = True, - save_fig: Optional[bool] = True, - name: Optional[Text] = 'shot_points_by_date.png', + figsize: Tuple[float, float] = (21, 9), + return_fig: bool = True, + save_fig: bool = True, + name: Text = 'shot_points_by_date.png', ) -> Optional[figure]: """ Generates four visualizations based on datetime feature. @@ -120,12 +120,12 @@ def show_object_id_by_date( def plot_trajectories( move_data: DataFrame, - markers: Optional[Text] = 'o', - markersize: Optional[float] = 12, - figsize: Optional[Tuple[float, float]] = (10, 10), - return_fig: Optional[bool] = True, - save_fig: Optional[bool] = True, - name: Optional[Text] = 'trajectories.png', + markers: Text = 'o', + markersize: float = 12, + figsize: Tuple[float, float] = (10, 10), + return_fig: bool = True, + save_fig: bool = True, + name: Text = 'trajectories.png', ) -> Optional[figure]: """ Generate a visualization that show trajectories. @@ -174,14 +174,14 @@ def plot_trajectories( def plot_traj_by_id( move_data: DataFrame, id_: Union[int, Text], - label: Optional[Text] = TID, + label: Text = TID, feature: Optional[Text] = None, value: Optional[Any] = None, - linewidth: Optional[float] = 3, - markersize: Optional[float] = 20, - figsize: Optional[Tuple[float, float]] = (10, 10), - return_fig: Optional[bool] = True, - save_fig: Optional[bool] = True, + linewidth: float = 3, + markersize: float = 20, + figsize: Tuple[float, float] = (10, 10), + return_fig: bool = True, + save_fig: bool = True, name: Optional[Text] = None, ) -> Optional[figure]: """ @@ -272,11 +272,11 @@ def plot_traj_by_id( def plot_all_features( move_data: DataFrame, - dtype: Optional[Callable] = float, - figsize: Optional[Tuple[float, float]] = (21, 15), - return_fig: Optional[bool] = True, - save_fig: Optional[bool] = True, - name: Optional[Text] = 'features.png', + dtype: Callable = float, + figsize: Tuple[float, float] = (21, 15), + return_fig: bool = True, + save_fig: bool = True, + name: Text = 'features.png', ) -> Optional[figure]: """ Generate a visualization for each columns that type is equal dtype. @@ -326,7 +326,7 @@ def plot_all_features( return fig -def plot_coords(ax: axes, ob: BaseGeometry, color: Optional[Text] = 'r'): +def plot_coords(ax: axes, ob: BaseGeometry, color: Text = 'r'): """ Plot the coordinates of each point of the object in a 2D chart. @@ -370,11 +370,11 @@ def plot_bounds(ax: axes, ob: Union[LineString, MultiLineString], color='b'): def plot_line( ax: axes, ob: LineString, - color: Optional[Text] = 'r', - alpha: Optional[float] = 0.7, - linewidth: Optional[float] = 3, - solid_capstyle: Optional[Text] = 'round', - zorder: Optional[float] = 2 + color: Text = 'r', + alpha: float = 0.7, + linewidth: float = 3, + solid_capstyle: Text = 'round', + zorder: float = 2 ): """ Plot a LineString. diff --git a/setup.cfg b/setup.cfg index 64dc7c24..7b4e4f12 100644 --- a/setup.cfg +++ b/setup.cfg @@ -6,6 +6,10 @@ select = B,C,E,D,N,F,W exclude = pymove/core/interface.py, pymove/tests/* docstring-convention = numpy +[mypy] +ignore_missing_imports = True +no_warn_no_return = True + [isort] multi_line_output = 3 include_trailing_comma = True From 39c884221326e99087436741bba0cee9a0a5efea Mon Sep 17 00:00:00 2001 From: flych3r Date: Tue, 8 Jun 2021 16:41:28 -0300 Subject: [PATCH 2/4] fix mypy errors --- .pre-commit-config.yaml | 8 +- Makefile | 7 +- pymove/preprocessing/filters.py | 10 +-- pymove/utils/visual.py | 4 +- pymove/visualization/folium.py | 127 +++++++++++++++++--------------- 5 files changed, 81 insertions(+), 75 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 34dc62dd..a9b80b57 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -32,7 +32,7 @@ repos: 'flake8-docstrings==1.6.0', 'pep8-naming==0.11.1' ] -# - repo: https://github.com/pre-commit/mirrors-mypy -# rev: 'v0.812' -# hooks: -# - id: mypy +- repo: https://github.com/pre-commit/mirrors-mypy + rev: 'v0.812' + hooks: + - id: mypy diff --git a/Makefile b/Makefile index 5904aeb8..d0059a0f 100644 --- a/Makefile +++ b/Makefile @@ -19,14 +19,15 @@ clean: rm -f .coverage test: clean - pytest + pytest pymove coverage: clean - coverage run -m pytest + coverage run -m pytest pymove coverage report lint: clean - flake8 + flake8 pymove + mypy pymove docs: clean cp docs/examples/notebooks.rst docs diff --git a/pymove/preprocessing/filters.py b/pymove/preprocessing/filters.py index 0f2c9d28..052881d4 100644 --- a/pymove/preprocessing/filters.py +++ b/pymove/preprocessing/filters.py @@ -77,7 +77,7 @@ def get_bbox_by_radius( lonmin = lon - delta_lon lonmax = lon + delta_lon - return tuple(np.rad2deg([latmin, lonmin, latmax, lonmax])) + return tuple(np.rad2deg([latmin, lonmin, latmax, lonmax])) # type: ignore def by_bbox( @@ -378,7 +378,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. @@ -420,7 +420,7 @@ def _filter_data(move_data: DataFrame, f: callable, kwargs: Dict): return filter_data_points, rows_to_drop -def _clean_gps(move_data: DataFrame, f: callable, **kwargs): +def _clean_gps(move_data: DataFrame, f: Callable, **kwargs): """ Cleans gps points from a dataframe using condition from given function. @@ -470,7 +470,7 @@ def clean_gps_jumps_by_distance( label_id: Text = TRAJ_ID, jump_coefficient: float = 3.0, threshold: float = 1, - label_dtype: callable = np.float64, + label_dtype: Callable = np.float64, inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ @@ -527,7 +527,7 @@ def clean_gps_nearby_points_by_distances( move_data: Union['PandasMoveDataFrame', 'DaskMoveDataFrame'], label_id: Text = TRAJ_ID, radius_area: float = 10.0, - label_dtype: callable = np.float64, + label_dtype: Callable = np.float64, inplace: bool = False, ) -> Optional[Union['PandasMoveDataFrame', 'DaskMoveDataFrame']]: """ diff --git a/pymove/utils/visual.py b/pymove/utils/visual.py index 2355b7ab..80d0a36f 100644 --- a/pymove/utils/visual.py +++ b/pymove/utils/visual.py @@ -11,7 +11,7 @@ """ -from typing import List, Text, Tuple +from typing import Sequence, Text, Tuple, Union from branca.element import MacroElement, Template from folium import Map @@ -23,7 +23,7 @@ from pymove.utils.constants import COLORS, LATITUDE, LONGITUDE, TRAJ_ID -def add_map_legend(m: Map, title: Text, items: List[Tuple]): +def add_map_legend(m: Map, title: Text, items: Union[Tuple, Sequence[Tuple]]): """ Adds a legend for a folium map. diff --git a/pymove/visualization/folium.py b/pymove/visualization/folium.py index 35560a6f..99b3a01e 100644 --- a/pymove/visualization/folium.py +++ b/pymove/visualization/folium.py @@ -25,7 +25,8 @@ """ -from typing import Any, Dict, List, Optional, Text, Tuple, Union +from datetime import date +from typing import Any, Dict, List, Optional, Sequence, Text, Tuple, Union import folium import numpy as np @@ -567,9 +568,9 @@ def _filter_and_generate_colors( move_data: DataFrame, id_: Optional[int] = None, n_rows: Optional[int] = None, - color: Optional[Text] = None, + color: Optional[Union[Text, List[Text]]] = None, color_by_id: Optional[Dict] = None -) -> Tuple[DataFrame, List[Tuple]]: +) -> Tuple[DataFrame, List[Tuple[Any, Any]]]: """ Filters the dataframe and generate colors for folium map. @@ -599,13 +600,13 @@ def _filter_and_generate_colors( n_rows = move_data.shape[0] if id_ is not None: - mv_df = move_data[move_data[TRAJ_ID] == id_].iloc[:n_rows][ + mv_df = move_data[move_data[TRAJ_ID] == id_].head(n_rows)[ [LATITUDE, LONGITUDE, DATETIME, TRAJ_ID] ] if not len(mv_df): raise IndexError('No user with id %s in dataframe' % id_) else: - mv_df = move_data.iloc[:n_rows][ + mv_df = move_data.head(n_rows)[ [LATITUDE, LONGITUDE, DATETIME, TRAJ_ID] ] @@ -727,7 +728,7 @@ def _add_begin_end_markers_to_folium_map( def _add_trajectories_to_folium_map( move_data: DataFrame, - items: Tuple, + items: Sequence[Tuple], base_map: Map, legend: bool = True, save_as_html: bool = True, @@ -1107,8 +1108,8 @@ def plot_trajectory_by_day_week( def plot_trajectory_by_date( move_data: DataFrame, - start_date: Text, - end_date: Text, + start_date: Union[Text, date], + end_date: Union[Text, date], id_: Optional[int] = None, n_rows: Optional[int] = None, lat_origin: Optional[float] = None, @@ -1463,7 +1464,7 @@ def plot_bbox( return base_map -def _format_tags(line, slice_): +def _format_tags(line: Union[List, Dict], slice_: List) -> Text: """ Create or format tags. @@ -1484,13 +1485,13 @@ def _format_tags(line, slice_): def _circle_maker( - iter_tuple, - user_lat, - user_lon, - slice_tags, - user_point, - radius, - map_ + iter_tuple: DataFrame, + user_lat: Text, + user_lon: Text, + slice_tags: List, + user_point: Text, + radius: float, + map_: Map ): """ Return a circle. @@ -1502,7 +1503,7 @@ def _circle_maker( Latitude column name. user_lon: str. Longitude column name. - slice_tags: + slice_tags: list or iterable user_point: str. Point color. @@ -1571,8 +1572,8 @@ def plot_points_folium( Map A folium map """ - if not slice_tags: - slice_tags = move_data.columns + if slice_tags is None: + slice_tags = list(move_data.columns) # If not have a map a map is create with mean to lat and lon if not base_map: @@ -1585,20 +1586,16 @@ def plot_points_folium( tile=tiles ) - list( - map( - lambda x: _circle_maker( - x, - user_lat, - user_lon, - slice_tags, - user_point, - radius, - base_map - ), - move_data.iterrows() + for row in move_data.iterrows(): + _circle_maker( + row, + user_lat, + user_lon, + slice_tags, + user_point, + radius, + base_map ) - ) if save_as_html: base_map.save(outfile=filename) @@ -1606,14 +1603,14 @@ def plot_points_folium( def plot_poi_folium( - move_data, - poi_lat=LATITUDE, - poi_lon=LONGITUDE, - poi_point=POI_POINT, - radius=2, - base_map=None, - slice_tags=None, - tiles=TILES[0], + move_data: DataFrame, + poi_lat: Text = LATITUDE, + poi_lon: Text = LONGITUDE, + poi_point: Text = POI_POINT, + radius: float = 2, + base_map: Optional[Map] = None, + slice_tags: Optional[List] = None, + tiles: Text = TILES[0], save_as_html: bool = False, filename: Text = 'pois.html' ) -> Map: @@ -1663,14 +1660,14 @@ def plot_poi_folium( def plot_event_folium( - move_data, - event_lat=LATITUDE, - event_lon=LONGITUDE, - event_point=EVENT_POINT, - radius=2, - base_map=None, - slice_tags=None, - tiles=TILES[0], + move_data: DataFrame, + event_lat: Text = LATITUDE, + event_lon: Text = LONGITUDE, + event_point: Text = EVENT_POINT, + radius: float = 2, + base_map: Optional[Map] = None, + slice_tags: Optional[List] = None, + tiles: Text = TILES[0], save_as_html: bool = False, filename: Text = 'events.html' ) -> Map: @@ -1733,8 +1730,8 @@ def show_trajs_with_event( user_id: Text = UID, user_point: Text = USER_POINT, line_color: Text = LINE_COLOR, - slice_event_show: Optional[int] = None, - slice_subject_show: Optional[int] = None, + slice_event_show: Optional[List] = None, + slice_subject_show: Optional[List] = None, ) -> List[Map]: """ Plot a trajectory, including your user_points lat lon and your tags. @@ -1771,15 +1768,20 @@ def show_trajs_with_event( User point color, by default USER_POINT. line_color: str, optional Line color, by default 'blue'. - slice_event_show: int, optional + slice_event_show: list, optional by default None. - slice_subject_show: int, optional + slice_subject_show: list, optional by default None. Returns ------- list of Map A list of folium maps. + + Raises + ------ + ValueError + If feature generation fails """ # building structure for deltas delta_event = pd.to_timedelta(window_time_event, unit='s') @@ -1814,6 +1816,9 @@ def show_trajs_with_event( end_datetime=end_time ) + if df_filtered is None: + raise ValueError('Filter datetime failed!') + # length of df_temp len_df_temp = df_filtered.shape[0] @@ -1915,8 +1920,8 @@ def show_traj_id_with_event( user_id: Text = UID, user_point: Text = USER_POINT, line_color: Text = LINE_COLOR, - slice_event_show: Optional[int] = None, - slice_subject_show: Optional[int] = None, + slice_event_show: Optional[List] = None, + slice_subject_show: Optional[List] = None, ) -> Map: """ Plot a trajectory, including your user_points lat lon and your tags. @@ -1955,9 +1960,9 @@ def show_traj_id_with_event( User point color, by default USER_POINT. line_color: str, optional Line color, by default 'blue'. - slice_event_show: int, optional + slice_event_show: list, optional by default None. - slice_subject_show: int, optional + slice_subject_show: list, optional by default None. Returns @@ -2058,11 +2063,11 @@ def _create_geojson_features_line( def plot_traj_timestamp_geo_json( - move_data, - label_lat=LATITUDE, - label_lon=LONGITUDE, - label_datetime=DATETIME, - tiles=TILES[0], + move_data: DataFrame, + label_lat: Text = LATITUDE, + label_lon: Text = LONGITUDE, + label_datetime: Text = DATETIME, + tiles: Text = TILES[0], save_as_html: bool = False, filename: Text = 'events.html' ) -> Map: From a434c15c5a6892f736f701c36cb79d911c0aa6a1 Mon Sep 17 00:00:00 2001 From: flych3r Date: Tue, 8 Jun 2021 16:44:13 -0300 Subject: [PATCH 3/4] added mypy to requirements-dev --- requirements-dev.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements-dev.txt b/requirements-dev.txt index 853862e7..2969b829 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,6 +4,7 @@ flake8 flake8-bugbear flake8-docstrings geopandas +mypy pep8-naming pre-commit pytest From 359467de4ca5335a32737082aab248411e16833b Mon Sep 17 00:00:00 2001 From: flych3r Date: Tue, 8 Jun 2021 16:53:21 -0300 Subject: [PATCH 4/4] pinned mypy version to requirements-dev --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 2969b829..dd74c405 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,7 +4,7 @@ flake8 flake8-bugbear flake8-docstrings geopandas -mypy +mypy==0.812 pep8-naming pre-commit pytest