Tutorial 61: nx-Graph

This example demonstrates how to use the SIR_3S_to_nx_graph() of the SIR 3S Toolkit to generate a nx-Graph based on a SIR 3S model.

SIR 3S Installation

[1]:
SIR3S_SIRGRAF_DIR = r"C:\3S\SIR 3S\SirGraf-90-15-00-20x64_Quebec-Upd1" #change to local path

Imports

Note: The SIR 3S Toolkit requires the Sir3S_Toolkit.dll included in SIR 3S installations (version Quebec and higher).

[2]:
import sir3stoolkit

The core of sir3stoolkit is a Python wrapper around basic functionality of SIR 3S, offering a low-level access to the creation, modification and simulation of SIR 3S models. In the future pure python subpackages may be added.

[3]:
from sir3stoolkit.core import wrapper
[4]:
from sir3stoolkit.mantle.alternative_models import SIR3S_Model_Alternative_Models
[5]:
sir3stoolkit
[5]:
<module 'sir3stoolkit' from 'C:\\Users\\aUsername\\3S\\sir3stoolkit\\src\\sir3stoolkit\\__init__.py'>

The wrapper package has to be initialized with reference to a SIR 3S (SirGraf) installation.

[6]:
wrapper.Initialize_Toolkit(SIR3S_SIRGRAF_DIR)

Additional imports

[7]:
import os
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
import logging

Initialization

[8]:
s3s = SIR3S_Model_Alternative_Models()
Initialization complete

Open Model

[9]:
dbFilePath=r"C:\Users\aUsername\3S\PT3S\PT3S\Examples\Example5.db3"
[10]:
s3s.OpenModel(dbName=dbFilePath,
              providerType=s3s.ProviderTypes.SQLite,
              Mid="M-1-0-1",
              saveCurrentlyOpenModel=False,
              namedInstance="",
              userID="",
              password="")
Model is open for further operation

Generate nx Graph

We can use the SIR_3S_to_nx_graph() method to create a nx graph representing a SIR 3S model.

[11]:
logging.disable(logging.INFO)
[12]:
G=s3s.SIR_3S_to_nx_graph()
[2026-01-19 16:17:52,835] WARNING in sir3stoolkit.mantle.dataframes: [model_data] Spatial Reference Identifier (SRID) not defined in model. DataFrame cannot be transformed to GeoDataFrame but geometry column can be created independently of SRID. Returning regular DataFrame with a geometry column.
[2026-01-19 16:17:53,625] WARNING in sir3stoolkit.mantle.dataframes: [model_data] Spatial Reference Identifier (SRID) not defined in model. DataFrame cannot be transformed to GeoDataFrame but geometry column can be created independently of SRID. Returning regular DataFrame with a geometry column.
[2026-01-19 16:17:54,077] WARNING in sir3stoolkit.mantle.dataframes: [model_data] Spatial Reference Identifier (SRID) not defined in model. DataFrame cannot be transformed to GeoDataFrame but geometry column can be created independently of SRID. Returning regular DataFrame with a geometry column.
[2026-01-19 16:17:54,094] WARNING in sir3stoolkit.mantle.dataframes: [model_data] Spatial Reference Identifier (SRID) not defined in model. DataFrame cannot be transformed to GeoDataFrame but geometry column can be created independently of SRID. Returning regular DataFrame with a geometry column.
[2026-01-19 16:17:54,122] WARNING in sir3stoolkit.mantle.dataframes: [model_data] Spatial Reference Identifier (SRID) not defined in model. DataFrame cannot be transformed to GeoDataFrame but geometry column can be created independently of SRID. Returning regular DataFrame with a geometry column.
[2026-01-19 16:17:54,318] WARNING in sir3stoolkit.mantle.dataframes: [model_data] Spatial Reference Identifier (SRID) not defined in model. DataFrame cannot be transformed to GeoDataFrame but geometry column can be created independently of SRID. Returning regular DataFrame with a geometry column.
[2026-01-19 16:17:54,456] WARNING in sir3stoolkit.mantle.dataframes: [model_data] Spatial Reference Identifier (SRID) not defined in model. DataFrame cannot be transformed to GeoDataFrame but geometry column can be created independently of SRID. Returning regular DataFrame with a geometry column.
[2026-01-19 16:17:54,487] WARNING in sir3stoolkit.mantle.dataframes: [model_data] Spatial Reference Identifier (SRID) not defined in model. DataFrame cannot be transformed to GeoDataFrame but geometry column can be created independently of SRID. Returning regular DataFrame with a geometry column.
[13]:
logging.disable(logging.NOTSET)

View generated Graph

As you can see below the graph does not contain any additional properties or result values.

[14]:
node_attrs = {n: data for n, data in G.nodes(data=True)}
[15]:
node_attrs[4680103632661687203]
[15]:
{'tk': 4680103632661687203,
 'Fkcont': 5478326535335532120,
 'geometry': <POINT (55176.324 98780.495)>}
[16]:
edge_attrs = {(u, v): data for u, v, data in G.edges(data=True)}
[17]:
edge_attrs[(4680103632661687203, 5432609004919372061)]['Fkcont']
[17]:
5478326535335532120
[18]:
nx.is_weakly_connected(G) # Is connected as an undirected graph
[18]:
True
[19]:
def plot_nx_graph(G, main_container):
    # Extract node positions from geometry and filter by Fkcont
    pos = {
        node_id: (data['geometry'].x, data['geometry'].y)
        for node_id, data in G.nodes(data=True)
        if 'geometry' in data and hasattr(data['geometry'], 'x') and hasattr(data['geometry'], 'y')
        and data.get('Fkcont') == main_container
    }

    # Extract edges with valid geometry and both nodes in pos
    edges = [
        (u, v, data) for u, v, data in G.edges(data=True)
        if u in pos and v in pos and 'geometry' in data and data['geometry'].geom_type != 'Point'
    ]

    # Plot
    plt.figure(figsize=(20, 14))
    for _, _, data in edges:
        geom = data['geometry']
        x, y = geom.xy
        plt.plot(x, y, color='black', linewidth=1)

    # Only draw nodes that have positions
    nx.draw_networkx_nodes(G, pos=pos, nodelist=list(pos.keys()), node_color='black', node_size=10)
    plt.title(f"nx-Graph'{main_container}'")
    plt.axis('equal')
    plt.show()
[20]:
plot_nx_graph(G, int(s3s.GetMainContainer()[0]))
../../_images/tutorials_SIR3S_Model_Mantle_ToolkitTutorial061_36_0.png

Add properities to graph

Now, we can model data properties and result properties to the nodes and edges.

[21]:
props_to_add = ["Kvr", "T", "BCIND"]
G = s3s.add_properties_to_graph(
    G=G,
    element_type="Node",
    properties=props_to_add,
)
[2026-01-19 16:17:56,616] INFO in sir3stoolkit.mantle.alternative_models: [graph] Enriching graph with properties for element_type='Node'
[2026-01-19 16:17:56,619] INFO in sir3stoolkit.mantle.alternative_models: [graph] Using 1 model_data props and 2 result props.
[2026-01-19 16:17:56,622] INFO in sir3stoolkit.mantle.dataframes: [model_data] Generating model_data dataframe for element type: ObjectTypes.Node
[2026-01-19 16:17:56,626] INFO in sir3stoolkit.mantle.dataframes: [model_data] Retrieved 1559 element(s) of element type ObjectTypes.Node.
[2026-01-19 16:17:56,627] INFO in sir3stoolkit.mantle.dataframes: [Resolving model_data Properties] Using 1 model_data properties.
[2026-01-19 16:17:56,628] INFO in sir3stoolkit.mantle.dataframes: [model_data] Retrieving model_data properties ['Kvr']...
[2026-01-19 16:17:56,732] INFO in sir3stoolkit.mantle.dataframes: [model_data] Done. Shape: (1559, 2)
[2026-01-19 16:17:56,958] INFO in sir3stoolkit.mantle.dataframes: [results] Generating results dataframe for element type: ObjectTypes.Node
[2026-01-19 16:17:57,239] INFO in sir3stoolkit.mantle.dataframes: [Resolving Timestamps] Only static timestamp 2025-09-24 00:00:00.000 +02:00 is used
[2026-01-19 16:17:57,239] INFO in sir3stoolkit.mantle.dataframes: [Resolving Timestamps] 1 valid timestamp(s) will be used.
[2026-01-19 16:17:57,245] INFO in sir3stoolkit.mantle.dataframes: [Resolving tks] Retrieved 1559 element(s) of element type ObjectTypes.Node.
[2026-01-19 16:17:57,248] INFO in sir3stoolkit.mantle.dataframes: [results] Using 2 result properties.
[2026-01-19 16:17:57,304] INFO in sir3stoolkit.mantle.dataframes: [results] Retrieving result values...
[2026-01-19 16:17:57,985] INFO in sir3stoolkit.mantle.dataframes: [results] Done. Shape: (1, 3118)
[2026-01-19 16:17:57,991] DEBUG in sir3stoolkit.mantle.alternative_models: Index(['tk', 'Kvr', 'BCIND', 'T'], dtype='object')
[2026-01-19 16:17:58,002] INFO in sir3stoolkit.mantle.alternative_models: [graph] Enrichment summary for element_type='Node': nodes_updated=1559; edges_updated=0; cols_added=['Kvr', 'T', 'BCIND']
[22]:
node_attrs = {n: data for n, data in G.nodes(data=True)}
[23]:
node_attrs[4680103632661687203]
[23]:
{'tk': 4680103632661687203,
 'Fkcont': 5478326535335532120,
 'geometry': <POINT (55176.324 98780.495)>,
 'Kvr': 1,
 'T': 125.03,
 'BCIND': 17.0}
[24]:
props_to_add = ["DN", "L", "JV", "PHR"]
G = s3s.add_properties_to_graph(
    G=G,
    element_type="Pipe",
    properties=props_to_add,
)
[2026-01-19 16:17:58,083] INFO in sir3stoolkit.mantle.alternative_models: [graph] Enriching graph with properties for element_type='Pipe'
[2026-01-19 16:17:58,088] INFO in sir3stoolkit.mantle.alternative_models: [graph] Using 2 model_data props and 2 result props.
[2026-01-19 16:17:58,091] INFO in sir3stoolkit.mantle.dataframes: [model_data] Generating model_data dataframe for element type: ObjectTypes.Pipe
[2026-01-19 16:17:58,094] INFO in sir3stoolkit.mantle.dataframes: [model_data] Retrieved 1672 element(s) of element type ObjectTypes.Pipe.
[2026-01-19 16:17:58,098] INFO in sir3stoolkit.mantle.dataframes: [Resolving model_data Properties] Using 2 model_data properties.
[2026-01-19 16:17:58,099] INFO in sir3stoolkit.mantle.dataframes: [model_data] Retrieving model_data properties ['DN', 'L']...
[2026-01-19 16:17:58,356] INFO in sir3stoolkit.mantle.dataframes: [model_data] Done. Shape: (1672, 3)
[2026-01-19 16:17:58,707] INFO in sir3stoolkit.mantle.dataframes: [results] Generating results dataframe for element type: ObjectTypes.Pipe
[2026-01-19 16:17:59,010] INFO in sir3stoolkit.mantle.dataframes: [Resolving Timestamps] Only static timestamp 2025-09-24 00:00:00.000 +02:00 is used
[2026-01-19 16:17:59,010] INFO in sir3stoolkit.mantle.dataframes: [Resolving Timestamps] 1 valid timestamp(s) will be used.
[2026-01-19 16:17:59,013] INFO in sir3stoolkit.mantle.dataframes: [Resolving tks] Retrieved 1672 element(s) of element type ObjectTypes.Pipe.
[2026-01-19 16:17:59,018] INFO in sir3stoolkit.mantle.dataframes: [results] Using 2 result properties.
[2026-01-19 16:17:59,063] INFO in sir3stoolkit.mantle.dataframes: [results] Retrieving result values...
[2026-01-19 16:17:59,981] INFO in sir3stoolkit.mantle.dataframes: [results] Done. Shape: (1, 3344)
[2026-01-19 16:17:59,991] DEBUG in sir3stoolkit.mantle.alternative_models: Index(['tk', 'DN', 'L', 'JV', 'PHR'], dtype='object')
[2026-01-19 16:18:00,001] INFO in sir3stoolkit.mantle.alternative_models: [graph] Enrichment summary for element_type='Pipe': nodes_updated=0; edges_updated=1672; cols_added=['DN', 'L', 'JV', 'PHR']
[25]:
edge_attrs = {(u, v): data for u, v, data in G.edges(data=True)}
[26]:
edge_attrs[(4680103632661687203, 5432609004919372061)]
[26]:
{'tk': 5460759352148475007,
 'Fkcont': 5478326535335532120,
 'geometry': <LINESTRING (55176.324 98780.495, 55231.478 98824.335)>,
 'fkKI': 4680103632661687203,
 'fkKK': 5432609004919372061,
 'element type': 'Pipe',
 'DN': 125,
 'L': 75.0,
 'JV': 0.04940455,
 'PHR': 0.003705341}