Zonal - A Workspace for Analysis Tools and Workflows.

Zonal

class madina.zonal.zonal.Zonal

Bases: object

A class to manage and organize urban data into layers and networks, acting as a workspace that manages data and facilitate interoperability across tools. A Zonal object populated with a veriety of data layeers and network could be used as input toi many urban analysis tools. Please look at the examples to see a gallery of use cases.

Example:
>>> shaqra = Zonal()
>>> shaqra.add_layer(name='streets', source='streets.geojson')
>>> shaqra.create_map(save_as='street_map.html', basemap=False)
clear_nodes() None

Erase the existing origins and destinations from the current network, but retains the network nodes and edges

create_graph(light_graph: bool = True, d_graph: bool = True, od_graph: bool = False) None

After creating a street network, adding origin nodes, and destination nodes, this function must be called to construct a NetworkX object internally. This is needed to run UNA tools.

Parameters:
  • light_graph (bool, optional) – contains only network nodes and edges, defaults to True

  • d_graph (bool, optional) – contains all destination nodes and network intersectionsa. This is needed to run UNA tools, defaults to True

  • od_graph (bool, optional) – contains all origin, destination, network, etc. nodes, defaults to False

Example:
>>> shaqra = Zonal()  # Create a Zonal object.
>>> shaqra.load_layer('streets', 'streets.geojson') # load streets layer
>>> shaqra.create_street_network("streets")  # Create a street network
>>> shaqra.load_layer('homes', 'homes.geojson')
>>> shaqra.insert_node('homes', label="origin", weight_attribute="residents")
>>> shaqra.load_layer('schools', 'schools.geojson')
>>> shaqra.insert_node('schools', label="destination", weight_attribute="school_enrollment")
>>> shaqra.create_graph()
# The zonal object now have everything it needs to be used as input in a UNA tool.
create_map(layer_list: list = None, save_as: str = None, basemap: bool = False) Deck

Create a map visualization using the specified layers within the Zonal object.

Parameters:
  • layer_list (list, optional) – A list of dictionaries, each containing a ‘gdf’ key with a GeoDataFrame, defaults to None. If None, the method includes all visible layers from the Zonal object.

  • save_as (str, optional) – The filename to save the map visualization. Default is None (not saved)., defaults to None

  • basemap (bool, optional) – Include a basemap in the map if True. Default is False.

Returns:

returns a PyDeck’s Deck object that can be visualized in Jupyter notebooks.

Return type:

pdk.Deck

Example:
>>> zonal = Zonal()  # Create a Zonal object.
>>> zonal.load_layer("streets", "streets.geojson")  # load streets layer.
>>> zonal.load_layer("homes", "homes.geojson")  # load homes layer.
>>> zonal.create_map(layer_list=[{"gdf": zonal.layers["streets"].gdf}], save_as="map.html", basemap=True)
# Create a map visualization with a custom layer and a basemap, and save it as an HTML file.
create_street_network(source_layer: str, weight_attribute: str = None, node_snapping_tolerance: int | float = 0, redundant_edge_treatment: str = 'discard', turn_threshold_degree: int | float = 45, turn_penalty_amount: int | float = 30) None

Create a topologically connected street network from a specified layer in the Zonal object.

Parameters:
  • source_layer (str) – The name of the source layer to create the network from. Layer must be loaded using ‘load_layer()’ first.

  • weight_attribute (str, optional) – Name of the attribute to use as percieved diatance. Given name must exist in layer attributes. Default is None, and the network cost would be calculated using geometric distance.

  • node_snapping_tolerance (int | float, optional) – Tolerance for snapping nodes. Default is 0.0 assuming that line geometries that are connected share identical common start/end points, defaults to 0.0

  • redundant_edge_treatment (str, optional) – Due to current limitations, only one edge can exist between a pair of nodes. Three options: “keep”: redundant edges will be kept, posing a risk for error in network construction/calculations. “discard”: The shortest edge of redundant edges will be kept. others are discarded. is kept if set to True. “split”: Split redundant edges by thier centroids into non-redundant segments. Default “split”.

  • turn_threshold_degree (int | float, optional) – Degree threshold for considering a turn. Default is 45. This threshold would only be used whem enabling turn penalty in UNA operations. The angle is measured as the deviation from a straight line. Can only be between 0-180. 90 degrees means a right or left turn, a 180 degree means a full U-turn

  • turn_penalty_amount (int | float, optional) – Penalty amount for turns. Default is 30. This penalty (in the units of the layers’ CRS) would be used as turn cost when enabling turn penalty in UNA operations. Cannot b e negative. defaults to 30

Raises:

ValueError – if the source layer did not exist in the object.

Example:
>>> zonal = Zonal()  # Create a Zonal object.
>>> zonal.create_street_network(
...     source_layer="streets",
...     weight_attribute="length",
...     node_snapping_tolerance=0.001,
... )
# Create a street network using 'streets' layer and allowing geometries to be atr most 0.001 CRS units apart to form a node.
describe() None

prints a textual representation of the zonal objecgt, listing and describing layers

Example:
>>> zshaqra = Zonal()
>>> shaqra.describe()
>>> shaqra.load_layer('homes', 'homes.geojson')
>>> shaqra.describe()
a string representation of the `Zonal` object, a list of layers if any exists. 
insert_node(layer_name: str, label: str, weight_attribute: str = None) None

Insert “origin” and “destination” nodes into the network. This function must be called aftet the ‘create_street_network’ function is called, and the corresponding layer have already been loaded by calling ‘load_layer’

Parameters:
  • layer_name (str) – The name of the layer to insert the nodes from.

  • label (str) – The label for the new node. Could either be “origin” or “destination”.

  • weight_attribute (str, optional) – Name of the attribute to use as the node’s weight. Default is None. If no weight is given, all nodes are weighted equally (Assigned a weight of 1). The attribute name must exist in the layer.

Example:
>>> shaqra = Zonal()  # Create a Zonal object.
>>> shaqra.load_layer('streets', 'streets.geojson') # load streets layer
>>> shaqra.create_street_network("streets")  # Create a street network
>>> shaqra.load_layer('homes', 'homes.geojson')
>>> shaqra.insert_node('homes', label="origin", weight_attribute="residents")
>>> shaqra.load_layer('schools', 'schools.geojson')
>>> shaqra.insert_node('schools', label="destination", weight_attribute="school_enrollment")
# Insert a homes as origins, schools as destinations into the 'shgaqra' Zonal object
load_layer(name: str, source: str | Path | GeoDataFrame, pos: int = None, first: bool = False, before: str = None, after: str = None) None

Loads a new layer from the given source with the specified layer name.

Parameters:
  • name (str) – A name for the layer the new layer.

  • source (str | Path | gpd.GeoDataFrame) – The data source of this layer. Could either be an existing GeoDataFrame, or a path to an acceptable file. Supported types are ‘.geojson’, ‘.shp’, or any file accepted by geopanda’s read_file()

  • pos (int, optional) – position of this layer in the list of layers, defaults adding a layer at the end of the list.

  • first (bool, optional) – if True, inserts this layer at the top of the list, defaults to False

  • before (str, optional) – insert before the specified layer name if specified

  • after (str, optional) – insert after the specified layer name if specified

Raises:
  • TypeError – _description_

  • TypeError – _description_

Example:
>>> shaqra = Zonal()  # Create a Zonal object.
>>> zonal.load_layer("streets", "path/to/streets.geojson", first=True) # Load a new layer at the beginning of the layers list.
set_turn_parameters(turn_threshold_degree: int | float, turn_penalty_amount: int | float) None

Set the turn penalty threshold and turn penalty amount for use when turn penalty is enabled in analysis tools. :param turn_threshold_degree: Degree threshold for considering a turn. Default is 45. This threshold would only be used whem enabling turn penalty in UNA operations. The angle is measured as the deviation from a straight line. Can only be between 0-180. 90 degrees means a right or left turn, a 180 degree means a full U-turn :type turn_threshold_degree: int | float :param turn_penalty_amount: Penalty amount for turns. Default is 30. This penalty (in the units of the layers’ CRS) would be used as turn cost when enabling turn penalty in UNA operations. Cannot b e negative. defaults to 30 :type turn_penalty_amount: int | float :raises TypeError: if parameter turn_threshold_degree is not int or float :raises ValueError: if parameter turn_threshold_degree is not between 0 and 180 degrees. :raises TypeError: if parameter turn_penalty_amount is not int or float :raises ValueError: if parameter turn_penalty_amount is negative