better pep8

This commit is contained in:
Helldragon67 2024-12-04 19:23:26 +01:00
parent 37fb0f2183
commit a4c435c398
4 changed files with 89 additions and 41 deletions

@ -1,23 +0,0 @@
from typing import Literal, Optional
from pydantic import BaseModel
class ShoppingLocation(BaseModel):
""""
A classe representing an interesting area for shopping.
It can represent either a general area or a specifc route with start and end point.
The importance represents the number of shops found in this cluster.
Attributes:
type : either a 'street' or 'area' (representing a denser field of shops).
importance : size of the cluster (number of points).
centroid : center of the cluster.
start : if the type is a street it goes from here...
end : ...to here
"""
type: Literal['street', 'area']
importance: int
centroid: tuple
start: Optional[list] = None
end: Optional[list] = None

@ -11,13 +11,28 @@ from ..structs.landmark import Landmark
from ..utils.get_time_separation import get_distance from ..utils.get_time_separation import get_distance
from ..constants import AMENITY_SELECTORS_PATH, LANDMARK_PARAMETERS_PATH, OPTIMIZER_PARAMETERS_PATH, OSM_CACHE_DIR from ..constants import AMENITY_SELECTORS_PATH, LANDMARK_PARAMETERS_PATH, OPTIMIZER_PARAMETERS_PATH, OSM_CACHE_DIR
class ShoppingLocation(BaseModel): class ShoppingLocation(BaseModel):
""""
A classe representing an interesting area for shopping.
It can represent either a general area or a specifc route with start and end point.
The importance represents the number of shops found in this cluster.
Attributes:
type : either a 'street' or 'area' (representing a denser field of shops).
importance : size of the cluster (number of points).
centroid : center of the cluster.
start : if the type is a street it goes from here...
end : ...to here
"""
type: Literal['street', 'area'] type: Literal['street', 'area']
importance: int importance: int
centroid: tuple centroid: tuple
# start: Optional[list] = None # for later use if we want to have streets as well # start: Optional[list] = None # for later use if we want to have streets as well
# end: Optional[list] = None # end: Optional[list] = None
class ShoppingManager: class ShoppingManager:
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -31,7 +46,11 @@ class ShoppingManager:
def __init__(self, bbox: tuple) -> None: def __init__(self, bbox: tuple) -> None:
""" """
Upon intialization, generate the list of shops used for cluster points. Upon intialization, generate the point cloud used for cluster detection.
The points represent bag/clothes shops and general boutiques.
Args:
bbox: The bounding box coordinates (around:radius, center_lat, center_lon).
""" """
# Initialize overpass and cache # Initialize overpass and cache
@ -52,8 +71,10 @@ class ShoppingManager:
except Exception as e: except Exception as e:
self.logger.error(f"Error fetching landmarks: {e}") self.logger.error(f"Error fetching landmarks: {e}")
if len(result.elements()) > 0 : if len(result.elements()) == 0 :
self.valid = False
else :
points = [] points = []
for elem in result.elements() : for elem in result.elements() :
points.append(tuple((elem.lat(), elem.lon()))) points.append(tuple((elem.lat(), elem.lon())))
@ -61,18 +82,23 @@ class ShoppingManager:
self.all_points = np.array(points) self.all_points = np.array(points)
self.valid = True self.valid = True
else :
self.valid = False
def generate_shopping_landmarks(self) -> list[Landmark]: def generate_shopping_landmarks(self) -> list[Landmark]:
"""
Generate shopping landmarks based on clustered locations.
This method first generates clusters of locations and then extracts shopping-related
locations from these clusters. It transforms each shopping location into a `Landmark` object.
Returns:
list[Landmark]: A list of `Landmark` objects representing shopping locations.
Returns an empty list if no clusters are found.
"""
# First generate the clusters
self.generate_clusters() self.generate_clusters()
# Return empty list if no clusters were found
if len(set(self.cluster_labels)) == 0 : if len(set(self.cluster_labels)) == 0 :
return [] return [] # Return empty list if no clusters were found
# Then generate the shopping locations # Then generate the shopping locations
self.generate_shopping_locations() self.generate_shopping_locations()
@ -87,6 +113,19 @@ class ShoppingManager:
def generate_clusters(self) : def generate_clusters(self) :
"""
Generate clusters of points using DBSCAN.
This method applies the DBSCAN clustering algorithm with different
parameters depending on the size of the city (number of points).
It filters out noise points and keeps only the largest clusters.
The method updates:
- `self.cluster_points`: The points belonging to clusters.
- `self.cluster_labels`: The labels for the points in clusters.
The method also calls `filter_clusters()` to retain only the largest clusters.
"""
# Apply DBSCAN to find clusters. Choose different settings for different cities. # Apply DBSCAN to find clusters. Choose different settings for different cities.
if len(self.all_points) > 200 : if len(self.all_points) > 200 :
@ -105,6 +144,19 @@ class ShoppingManager:
def generate_shopping_locations(self) : def generate_shopping_locations(self) :
"""
Generate shopping locations based on clustered points.
This method iterates over the different clusters, calculates the centroid
(as the mean of the points within each cluster), and assigns an importance
based on the size of the cluster.
The generated shopping locations are stored in `self.shopping_locations`
as a list of `ShoppingLocation` objects, each with:
- `type`: Set to 'area'.
- `centroid`: The calculated centroid of the cluster.
- `importance`: The number of points in the cluster.
"""
locations = [] locations = []
@ -127,6 +179,21 @@ class ShoppingManager:
def create_landmark(self, shopping_location: ShoppingLocation) -> Landmark: def create_landmark(self, shopping_location: ShoppingLocation) -> Landmark:
"""
Create a Landmark object based on the given shopping location.
This method queries the Overpass API for nearby neighborhoods and shopping malls
within a 1000m radius around the shopping location centroid. It selects the closest
result and creates a landmark with the associated details such as name, type, and OSM ID.
Parameters:
shopping_location (ShoppingLocation): A ShoppingLocation object containing
the centroid and importance of the area.
Returns:
Landmark: A Landmark object containing details such as the name, type,
location, attractiveness, and OSM details.
"""
# Define the bounding box for a given radius around the coordinates # Define the bounding box for a given radius around the coordinates
lat, lon = shopping_location.centroid lat, lon = shopping_location.centroid
@ -153,10 +220,10 @@ class ShoppingManager:
try: try:
result = self.overpass.query(query) result = self.overpass.query(query)
except Exception as e: except Exception as e:
raise Exception("query unsuccessful") self.logger.error(f"Error fetching landmarks: {e}")
continue
for elem in result.elements(): for elem in result.elements():
location = (elem.centerLat(), elem.centerLon()) location = (elem.centerLat(), elem.centerLon())
if location[0] is None : if location[0] is None :
@ -171,7 +238,7 @@ class ShoppingManager:
osm_type = elem.type() # Add type: 'way' or 'relation' osm_type = elem.type() # Add type: 'way' or 'relation'
osm_id = elem.id() # Add OSM id osm_id = elem.id() # Add OSM id
# add english name if it exists # Add english name if it exists
try : try :
new_name_en = elem.tag('name:en') new_name_en = elem.tag('name:en')
except: except:
@ -191,7 +258,11 @@ class ShoppingManager:
def filter_clusters(self): def filter_clusters(self):
""" """
Remove clusters of lesser importance. Filter clusters to retain only the 5 largest clusters by point count.
This method calculates the size of each cluster and filters out all but the
5 largest clusters. It then updates the cluster points and labels to reflect
only those from the top 5 clusters.
""" """
label_counts = np.bincount(self.cluster_labels) label_counts = np.bincount(self.cluster_labels)

@ -184,7 +184,7 @@ class LandmarkManager:
Fetches landmarks of a specified type from OpenStreetMap (OSM) within a bounding box centered on given coordinates. Fetches landmarks of a specified type from OpenStreetMap (OSM) within a bounding box centered on given coordinates.
Args: Args:
bbox (tuple[float, float, float, float]): The bounding box coordinates (min_lat, min_lon, max_lat, max_lon). bbox (tuple[float, float, float, float]): The bounding box coordinates (around:radius, center_lat, center_lon).
amenity_selector (dict): The Overpass API query selector for the desired landmark type. amenity_selector (dict): The Overpass API query selector for the desired landmark type.
landmarktype (str): The type of the landmark (e.g., 'sightseeing', 'nature', 'shopping'). landmarktype (str): The type of the landmark (e.g., 'sightseeing', 'nature', 'shopping').
score_function (callable): The function to compute the score of the landmark based on its attributes. score_function (callable): The function to compute the score of the landmark based on its attributes.