i38e-utils
i38e-utils is a collection of utility functions and classes that I use in my BI projects. It is a work in progress and will be updated as I add more functionality.
The utilities are designed to work with Django, OpenStreetMaps and NetworkX
Currently, it includes the following:
- DfHelper: A class designed to facilitate data handling and operations within a Django project, particularly focusing on loading data from both parquet files and a database, and potentially saving data to parquet format.
- GeoLocationService: A class that provides a set of utility functions for working with GeoPy and Nominatim.
- OsmxHelper: A class that provides a set of utility functions for working with Osmnx maps.
- data_utils: A set of utility functions/classes for working with data.
- date_utils: A set of utility functions for working with dates.
- df_utils: A set of utility functions for working with pandas DataFrames.
- file_utils: A set of utility functions for working with files.
- log_utils: A set of utility functions for working with logs.
Installation
To install this project, follow these steps:
pip install i38e-utils
Usage
DfHelper: Dataframe Helper Class
DfHelper is designed to be subclassed. For example, the following use case, connects to a table containing gps transactions and encapsulates data cleaning operations. The resulting object can be queried via the "load" method using Django's query language syntax. The object can also be instantiated in debug and verbose mode.
The object returns Dataframe objects either as pandas (by default) or dask. It is recommended to use dask for large datasets which may benefit from dask parallelization architecture. Scenarios:
- Connect to a database table using a Django's ORM connection, query, transform and convert the data to a pandas DataFrame.
import pandas as pd
import numpy as np
from i38e_utils.df_helper import DfHelper
phone_mobile_gps_fields = {
'id_tracking': 'id',
'id_producto': 'product_id',
'pk_empleado': 'associate_id',
'latitud': 'latitude',
'longitud': 'longitude',
'fecha_hora_servidor': 'server_dt',
'fecha_hora': 'date_time',
'accion': 'action',
'descripcion': 'description',
'imei': 'imei'
}
class GpsCube(DfHelper):
df: pd.DataFrame = None
live: bool = False
save_parquet = True
config={
'connection_name': 'replica',
'table': 'asm_tracking_movil_gps',
'field_map': phone_mobile_gps_fields,
'legacy_filters': True,
}
def __init__(self, **opts):
config = {**self.config, **opts}
super().__init__(**config)
def load(self, **kwargs):
self.df = super().load(**kwargs)
self.fix_data()
return self.df
def fix_data(self):
self.df['latitude'] = self.df['latitude'].astype(np.float64)
self.df['longitude'] = self.df['longitude'].astype(np.float64)```python
gps_cube=GpsCube(live=True, debug=False,df_as_dask=True)
df=gps_cube.load(date_time__date='2023-03-04').compute()
# to save to a parquet file
gps_cube.save_to_parquet(df, parquet_full_path='gpscube.parquet')
- Use a parquet storage file or folder structure to load data and perform some transformations.
import pandas as pd
from i38e_utils.df_helper import DfHelper
class GpsParquetCube(DfHelper):
df: pd.DataFrame = None
config={
'use_parquet': True,
'df_as_dask': True,
'parquet_storage_path': '/storage/data/parquet/gps',
'parquet_start_date': '2024-01-01',
'parquet_end_date': '2024-03-31',
}
def __init__(self, **opts):
config = {**self.config, **opts}
super().__init__(**config)
def load(self, **kwargs):
self.df = super().load(**kwargs)
return self.df
# The following example would load all the parquet files in the folder structure described in parquet_storage_path matching the date range and return a single dask dataframe for associate_id 27 for the month of March.
# The class converts Django style filters to dask compatible filters.
# The class also converts the parquet files to a dask dataframe for faster processing.
params = {
'associate_id': 27,
'date_time__date__range': ['2024-03-01','2024-03-31']
}
dask_df = GpsParquetCube().load(**params)
# to convert to a pandas dataframe
df = dask_df.compute()
Usage
osmnx_helper: Base Map and Utilities
Use case: Create a heat map with time using a DfHelper cube with gps data
from i38e_utils.osmnx_helper import BaseOsmMap
from i38e_utils.osmnx_helper.utils import get_graph
import folium
options = {
'ox_files_save_path': 'path/to/pbf/files',
'network_type': 'all',
'place': 'Costa Rica',
'files_prefix': 'costa-rica-',
'rebuild': False,
'verbose': False
}
class ActivityHeatMapWithTime(BaseOsmMap):
def __init__(self, df, **kwargs):
kwargs.setdefault('dt_field', 'date_time')
G, _, _ = get_graph(**options)
self.heat_time_index = []
super().__init__(G, df, **kwargs)
def process_map(self):
self.heat_time_index = sorted(list(self.df[self.dt_field].dt.hour.unique()))
heat_data_time = [[[row[self.lat_col], row[self.lon_col]] for index, row in
self.df[self.df[self.dt_field].apply(lambda x: x.hour == j)].iterrows()] for j in self.heat_time_index]
hm = folium.plugins.HeatMapWithTime(heat_data_time, index=self.heat_time_index)
# hm = HeatMap(gps_points)
hm.add_to(self.osm_map)
to create a heatmap using a Dataframe of GPS Data
df=GpsCube().load(date_time__date="2024-06-30")
map_options={}
map_options.setdefault("map_html_title","Activity Heatmap")
map_options.setdefault("dt_field", "date_time")
map_options.setdefault("max_bounds", False)
heat_map=ActivityHeatMapWithTime(df, **map_options)
heat_map.generate_map()
Metadata
Release files for i38e-utils 1.0.48
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| i38e_utils-1.0.48.tar.gz | 34.4 kB | Without provenance | Details for i38e_utils-1.0.48.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| i38e_utils-1.0.48-py3-none-any.whl | Python 3 | none | any | Details for i38e_utils-1.0.48-py3-none-any.whl |
Total release size: 74.3 kB
Release files / i38e_utils-1.0.48.tar.gz
| Download URL | i38e_utils-1.0.48.tar.gz |
|---|---|
| Size | 34.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c5c7825975bb4e71649dca2f3acf6771c4eb55eab2cb2db4ce6a39e3b304492b
|
|
BLAKE2b-256 checksum How to use checksums |
1e2c8b5ac66637ccda006b4edba0fddfd982af58e80541d727339cd6135e6bb5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.8.2 CPython/3.11.2 Darwin/24.0.0
|
Release files / i38e_utils-1.0.48-py3-none-any.whl
| Download URL | i38e_utils-1.0.48-py3-none-any.whl |
|---|---|
| Size | 40.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a9b9d840a4468b0b4da79aaf08815e43bb0dd0d3b572f0bbdf282c523c1cbc54
|
|
BLAKE2b-256 checksum How to use checksums |
30e506a3ee694a73f1a050710cc9711bf4afe6d41fae2466699ea3e57ab815a6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.8.2 CPython/3.11.2 Darwin/24.0.0
|
Security for i38e-utils 1.0.48
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.