Source code for aequilibrae.project.network.periods

from copy import deepcopy

import pandas as pd

from aequilibrae.project.basic_table import BasicTable
from aequilibrae.project.data_loader import DataLoader
from aequilibrae.project.network.period import Period
from aequilibrae.project.table_loader import TableLoader
from aequilibrae.utils.db_utils import commit_and_close
from aequilibrae.utils.spatialite_utils import connect_spatialite


[docs] class Periods(BasicTable): """Access to the API resources to manipulate the periods table in the network .. code-block:: python >>> project = create_example(project_path, "coquimbo") >>> all_periods = project.network.periods # We can just get one link in specific >>> period = all_periods.get(1) # We can save changes for all periods we have edited so far >>> all_periods.save() """ #: Query sql for retrieving periods sql = ""
[docs] def __init__(self, net): super().__init__(net.project) self.__table_type__ = "periods" self.__items = {} self.__fields = [] if self.sql == "": self.refresh_fields()
[docs] def extent(self): # FIXME: This is not real subclassing, the extent function needs to be moved out of BasicTable # This hack will do for now raise NotImplementedError("Not applicable to Periods class")
[docs] def get(self, period_id: int) -> Period: """Get a period from the network by its **period_id** It raises an error if period_id does not exist :Arguments: **period_id** (:obj:`int`): Id of a period to retrieve :Returns: **period** (:obj:`Period`): Period object for requested period_id """ if period_id in self.__items: period = self.__items[period_id] # If this element has not been renumbered, we return it. Otherwise we # store the object under its new number and carry on if period.period_id == period_id: return period else: self.__items[period.period_id] = self.__items.pop(period_id) with commit_and_close(connect_spatialite(self.project.path_to_file)) as conn: data = conn.execute(f"{self.sql} where period_id=?", [period_id]).fetchone() if data: data = dict(zip(self.__fields, data)) period = Period(data, self.project) self.__items[period.period_id] = period return period raise ValueError(f"Period {period_id} does not exist in the model")
[docs] def refresh_fields(self) -> None: """After adding a field one needs to refresh all the fields recognized by the software""" tl = TableLoader() with commit_and_close(connect_spatialite(self.project.path_to_file)) as conn: tl.load_structure(conn, "periods") self.sql = tl.sql self.__fields = deepcopy(tl.fields)
[docs] def refresh(self): """Refreshes all the periods in memory""" lst = list(self.__items.keys()) for k in lst: del self.__items[k]
[docs] def new_period(self, period_id: int, start: int, end: int, description: str = None) -> Period: """Creates a new period with a given ID :Arguments: **period_id** (:obj:`int`): Id of the centroid to be created **start** (:obj:`int`): Start time of the period to be created **end** (:obj:`int`): End time of the period to be created **description** (:obj:`str`): Optional human readable description of the time period e.g. '1pm - 5pm' """ with commit_and_close(connect_spatialite(self.project.path_to_file)) as conn: dt = conn.execute("SELECT COUNT(*) FROM periods WHERE period_id=?", [period_id]).fetchone()[0] if dt > 0: raise Exception("period_id already exists. Failed to create it") data = {key: None for key in self.__fields} data["period_id"] = period_id data["period_start"] = start data["period_end"] = end data["period_description"] = description if description is not None else "" period = Period(data, self.project) self.__items[period_id] = period return period
[docs] def save(self): for item in self.__items.values(): item.save()
@property def data(self) -> pd.DataFrame: """Returns all periods data as a Pandas DataFrame :Returns: **table** (:obj:`DataFrame`): Pandas DataFrame with all the periods """ dl = DataLoader(self.project.path_to_file, "periods") return dl.load_table() def __del__(self): self.__items.clear() @property def default_period(self) -> Period: return self.get(1)