Tutorial 73: Network Color Depiction

This example demonstrates how to plot network color depictions (ncd).

SIR 3S Installation

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

Imports

[2]:
from sir3stoolkit.core import wrapper
[3]:
from sir3stoolkit.mantle import mantle

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

[4]:
wrapper.Initialize_Toolkit(SIR3S_SIRGRAF_DIR)

Additional imports

[5]:
import os
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
import contextily as cx

Initialization

[6]:
s3s = mantle.SIR3S_Model_Mantle()
Initialization complete

Open Model

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

Prep Data

District Heating consumers

[9]:
df_district_heating_consumer_model_data = s3s.generate_element_model_data_dataframe(s3s.ObjectTypes.DistrictHeatingConsumer
                                                                        ,properties=[]
                                                                        ,geometry=True)
[2026-01-10 17:39:48,781] INFO in sir3stoolkit.mantle.dataframes: [model_data] Generating model_data dataframe for element type: ObjectTypes.DistrictHeatingConsumer
[2026-01-10 17:39:48,789] INFO in sir3stoolkit.mantle.dataframes: [model_data] Retrieved 656 element(s) of element type ObjectTypes.DistrictHeatingConsumer.
[2026-01-10 17:39:48,812] INFO in sir3stoolkit.mantle.dataframes: [Resolving model_data Properties] Using 0 model_data properties.
[2026-01-10 17:39:48,812] INFO in sir3stoolkit.mantle.dataframes: [model_data] Retrieving geometry...
[2026-01-10 17:39:48,875] 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-10 17:39:48,875] INFO in sir3stoolkit.mantle.dataframes: [model_data] Done. Shape: (656, 2)
[10]:
df_district_heating_consumer_results=s3s.generate_element_results_dataframe(element_type=s3s.ObjectTypes.DistrictHeatingConsumer
                                                           ,properties=["QM"]
                                                           ,timestamps=[0])
[2026-01-10 17:39:48,890] INFO in sir3stoolkit.mantle.dataframes: [results] Generating results dataframe for element type: ObjectTypes.DistrictHeatingConsumer
[2026-01-10 17:39:49,107] INFO in sir3stoolkit.mantle.dataframes: [Resolving Timestamps] Only static timestamp 2025-09-24 00:00:00.000 +02:00 is used
[2026-01-10 17:39:49,108] INFO in sir3stoolkit.mantle.dataframes: [Resolving Timestamps] 1 valid timestamp(s) will be used.
[2026-01-10 17:39:49,111] INFO in sir3stoolkit.mantle.dataframes: [Resolving tks] Retrieved 656 element(s) of element type ObjectTypes.DistrictHeatingConsumer.
[2026-01-10 17:39:49,112] INFO in sir3stoolkit.mantle.dataframes: [results] Using 1 result properties.
[2026-01-10 17:39:49,528] INFO in sir3stoolkit.mantle.dataframes: [results] Retrieving result values...
[2026-01-10 17:39:49,665] INFO in sir3stoolkit.mantle.dataframes: [results] Done. Shape: (1, 656)
[11]:
df_district_heating_consumer_results.columns = df_district_heating_consumer_results.columns.droplevel([1, 2])
df_district_heating_consumer_results = df_district_heating_consumer_results.T.unstack(level=0).T
df_district_heating_consumer_results = df_district_heating_consumer_results.droplevel(0, axis=0)
df_district_heating_consumer = df_district_heating_consumer_model_data.merge(on="tk",
                    how="outer",
                    right=df_district_heating_consumer_results)
[12]:
df_district_heating_consumer.head(3)
[12]:
tk geometry QM
0 4615167946623235098 POINT (48964.78656816362 97889.18677734208) 9.808820
1 4615393182465694100 POINT (46651.60694166463 97713.81722454002) 8.018323
2 4616022158288753538 POINT (54845.39768749467 97480.83261120686) 3.134198

Pipes

[13]:
df_pipes_model_data=s3s.generate_element_model_data_dataframe(s3s.ObjectTypes.Pipe
                                                   ,properties=["DN"]
                                                   ,geometry=True)
[2026-01-10 17:39:49,712] INFO in sir3stoolkit.mantle.dataframes: [model_data] Generating model_data dataframe for element type: ObjectTypes.Pipe
[2026-01-10 17:39:49,716] INFO in sir3stoolkit.mantle.dataframes: [model_data] Retrieved 1672 element(s) of element type ObjectTypes.Pipe.
[2026-01-10 17:39:49,717] INFO in sir3stoolkit.mantle.dataframes: [Resolving model_data Properties] Using 1 model_data properties.
[2026-01-10 17:39:49,719] INFO in sir3stoolkit.mantle.dataframes: [model_data] Retrieving model_data properties ['DN'], geometry...
[2026-01-10 17:39:49,935] 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-10 17:39:49,935] INFO in sir3stoolkit.mantle.dataframes: [model_data] Done. Shape: (1672, 3)
[14]:
df_pipes_results=s3s.generate_element_results_dataframe(element_type=s3s.ObjectTypes.Pipe
                                                           ,properties=["QMAV"]
                                                           ,timestamps=[0])
[2026-01-10 17:39:49,948] INFO in sir3stoolkit.mantle.dataframes: [results] Generating results dataframe for element type: ObjectTypes.Pipe
[2026-01-10 17:39:50,152] INFO in sir3stoolkit.mantle.dataframes: [Resolving Timestamps] Only static timestamp 2025-09-24 00:00:00.000 +02:00 is used
[2026-01-10 17:39:50,154] INFO in sir3stoolkit.mantle.dataframes: [Resolving Timestamps] 1 valid timestamp(s) will be used.
[2026-01-10 17:39:50,158] INFO in sir3stoolkit.mantle.dataframes: [Resolving tks] Retrieved 1672 element(s) of element type ObjectTypes.Pipe.
[2026-01-10 17:39:50,159] INFO in sir3stoolkit.mantle.dataframes: [results] Using 1 result properties.
[2026-01-10 17:39:50,239] INFO in sir3stoolkit.mantle.dataframes: [results] Retrieving result values...
[2026-01-10 17:39:50,611] INFO in sir3stoolkit.mantle.dataframes: [results] Done. Shape: (1, 1672)
[15]:
df_pipes_results.columns = df_pipes_results.columns.droplevel([1, 2])
df_pipes_results = df_pipes_results.T.unstack(level=0).T
df_pipes_results = df_pipes_results.droplevel(0, axis=0)
df_pipes = df_pipes_model_data.merge(on="tk",
                                    how="outer",
                                    right=df_pipes_results)
[16]:
df_pipes['QMAVAbs'] = df_pipes['QMAV'].abs()
[17]:
df_pipes.head(3)
[17]:
tk DN geometry QMAV QMAVAbs
0 4613765641349500151 150 LINESTRING (47478.00263683735 97484.9974701480... -10.61157 10.61157
1 4614040293856762696 200 LINESTRING (49756.350183295086 97621.546860662... -135.87620 135.87620
2 4614199490723616754 150 LINESTRING (50941.63085419123 97450.3987353445... 19.20712 19.20712

Plotting

plot_node_layer()

plot_pipe_layer

[18]:
def plot_Result_ncd(df_pipes, df_district_heating_consumer, axTitle='ncd'):
    fig, ax = plt.subplots(figsize=(16.54, 11.69))

    # Nodes (size+color by QM)
    nodes_patches_1 = s3s.plot_node_layer(
        ax=ax,
        gdf=df_district_heating_consumer,
        attribute='QM',
        colors=['cyan', 'teal'],
        marker_style='p',
        marker_size_factor=3000,
        legend_fmt='{:4.0f} t/h',
        legend_values=[0, 25, 50, 75, 100],
        zorder=1
    )

    # Pipes layer 1 (size+color by DN)
    pipes_patches_2 = s3s.plot_pipe_layer(
        ax=ax,
        gdf=df_pipes,
        attribute='DN',
        colors=['lightgray', 'dimgray'],
        legend_fmt='{:4.0f} mm',
        line_width_factor=25,
        legend_values=[0, 250, 500, 750],
        zorder=2
    )
    # Pipes layer 2 (size+color by QMAVAbs)
    pipes_patches_3 = s3s.plot_pipe_layer(
        ax=ax,
        gdf=df_pipes,
        attribute='QMAVAbs',
        colors=['darkgreen', 'magenta'],
        legend_fmt='{:4.0f} t/h',
        line_width_factor=20,
        legend_values=[0, 500, 1000, 1500, 2000],
        zorder=3
    )

    # Combine handles
    handles = []
    for h in (nodes_patches_1, pipes_patches_2, pipes_patches_3):
        if h:
            handles.extend(h)

    # Deduplicate legend by label
    if handles:
        seen = set()
        unique = []
        for h in handles:
            if h.get_label() not in seen:
                unique.append(h)
                seen.add(h.get_label())
        ax.legend(handles=unique, loc='best')

    ax.set_title(axTitle)
    plt.tight_layout()

[19]:
plot_Result_ncd(df_pipes, df_district_heating_consumer)
[2026-01-10 17:39:50,764] INFO in sir3stoolkit.mantle.plotting: [plot] Plotting nodes (size='None', color='None', attr='QM')
[2026-01-10 17:39:50,781] INFO in sir3stoolkit.mantle.plotting: [plot] Nodes: plotted 656 points.
[2026-01-10 17:39:50,791] INFO in sir3stoolkit.mantle.plotting: [plot] Plotting pipes (width='None', color='None', attr='DN')
[2026-01-10 17:39:50,869] INFO in sir3stoolkit.mantle.plotting: [plot] Pipes: plotted 1672 segments.
[2026-01-10 17:39:50,876] INFO in sir3stoolkit.mantle.plotting: [plot] Plotting pipes (width='None', color='None', attr='QMAVAbs')
[2026-01-10 17:39:50,945] INFO in sir3stoolkit.mantle.plotting: [plot] Pipes: plotted 1672 segments.
../../_images/tutorials_SIR3S_Model_Mantle_ToolkitTutorial073_33_1.png