Source code for aequilibrae.project.network.nodes

from copy import deepcopy

import geopandas as gpd
import pandas as pd

from aequilibrae.project.basic_table import BasicTable
from aequilibrae.project.data_loader import DataLoader
from aequilibrae.project.network.node import Node
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 Nodes(BasicTable): """ Access to the API resources to manipulate the nodes table in the network .. code-block:: python >>> project = create_example(project_path) >>> all_nodes = project.network.nodes # We can just get one link in specific >>> node = all_nodes.get(21) # We can save changes for all nodes we have edited so far >>> all_nodes.save() """ #: Query sql for retrieving nodes sql = ""
[docs] def __init__(self, net): super().__init__(net.project) self.__table_type__ = "nodes" self.__items = {} self.__fields = [] if self.sql == "": self.refresh_fields()
[docs] def get(self, node_id: int) -> Node: """Get a node from the network by its ``node_id`` It raises an error if ``node_id`` does not exist :Arguments: **node_id** (:obj:`int`): ID of a node to retrieve :Returns: **node** (:obj:`Node`): Node object for requested ``node_id`` """ if node_id in self.__items: node = self.__items[node_id] # If this element has not been renumbered, we return it. Otherwise we # store the object under its new number and carry on if node.node_id == node_id: return node else: self.__items[node.node_id] = self.__items.pop(node_id) with commit_and_close(connect_spatialite(self.project.path_to_file)) as conn: data = conn.execute(f"{self.sql} where node_id=?", [node_id]).fetchone() if data: data = dict(zip(self.__fields, data)) node = Node(data, self.project) self.__items[node.node_id] = node return node raise ValueError(f"Node {node_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, "nodes") self.sql = tl.sql self.__fields = deepcopy(tl.fields)
[docs] def refresh(self): """Refreshes all the nodes in memory""" lst = list(self.__items.keys()) for k in lst: del self.__items[k]
[docs] def new_centroid(self, node_id: int) -> Node: """Creates a new centroid with a given ID :Arguments: **node_id** (:obj:`int`): ID of the centroid to be created """ with commit_and_close(connect_spatialite(self.project.path_to_file)) as conn: ct = conn.execute("select count(*) from nodes where node_id=?", [node_id]).fetchone()[0] if ct > 0: raise Exception("Node_id already exists. Failed to create it") data = {key: None for key in self.__fields} data["node_id"] = node_id data["is_centroid"] = 1 node = Node(data, self.project) self.__items[node_id] = node return node
[docs] def save(self): for item in self.__items.values(): item.save()
@property def data(self) -> gpd.GeoDataFrame: """Returns all nodes data as a Pandas DataFrame :Returns: **table** (:obj:`GeoDataFrame`): GeoPandas GeoDataFrame with all the nodes """ dl = DataLoader(self.project.path_to_file, "nodes") return dl.load_table() @property def lonlat(self) -> pd.DataFrame: """Returns all nodes lon/lat coords as a Pandas DataFrame :Returns: **table** (:obj:`DataFrame`): Pandas DataFrame with all the nodes, with geometry as lon/lat """ with commit_and_close(connect_spatialite(self.project.path_to_file)) as conn: df = pd.read_sql("SELECT node_id, ST_X(geometry) AS lon, ST_Y(geometry) AS lat FROM nodes", conn) return df def __del__(self): self.__items.clear()