Example 3: Longitudinal Sections

This example demonstrates how longitudinal sections data read by PT3S can be accessed and used to create plots with Matplotlib.

PT3S Release

[1]:
#pip install PT3S -U --no-deps

Necessary packages for this Example

When running this example for the first time on your machine, please execute the cell below. Afterward, you may need to restart the kernel (using the ‘fast-forward’ button).
[2]:
pip install -q bokeh
Note: you may need to restart the kernel to use updated packages.

Imports

[3]:
import os
import logging
import pandas as pd
import datetime
import numpy as np
import subprocess

import matplotlib
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.gridspec as gridspec
import matplotlib.ticker as ticker
import matplotlib.colors as mcolors
from matplotlib.pyplot import Polygon
from matplotlib.ticker import FuncFormatter
from matplotlib.dates import DateFormatter, MinuteLocator
import matplotlib.ticker as ticker

from bokeh.plotting import figure, show
from bokeh.io import output_notebook
from bokeh.models import CustomJS, ColumnDataSource, CheckboxGroup, LinearAxis, Range1d
from bokeh.layouts import column


try:
    from PT3S import dxAndMxHelperFcts
except:
    import dxAndMxHelperFcts

try:
    from PT3S import Rm
except:
    import Rm
[ ]:
import importlib
from importlib import resources
[5]:
#importlib.reload(dxAndMxHelperFcts)

Logging

[ ]:
logger = logging.getLogger()

if not logger.handlers:
    logFileName = r"Example3.log"
    loglevel = logging.DEBUG

    logging.basicConfig(
        filename=logFileName,
        filemode='w',
        level=loglevel,
        format="%(asctime)s ; %(name)-60s ; %(levelname)-7s ; %(message)s"
    )

    fileHandler = logging.FileHandler(logFileName)
    logger.addHandler(fileHandler)

    consoleHandler = logging.StreamHandler()
    consoleHandler.setFormatter(logging.Formatter("%(levelname)-7s ; %(message)s"))
    consoleHandler.setLevel(logging.INFO)
    logger.addHandler(consoleHandler)

Read Model and Results

[ ]:
dbFilename="Example3"
dbFile = resources.files("PT3S").joinpath("Examples", f"{dbFilename}.db3")
[ ]:
m=dxAndMxHelperFcts.readDxAndMx(dbFile=dbFile
                                ,preventPklDump=True
                                ,maxRecords=-1
                                ,mxsVecsResults2MxDfVecAggs=[7,13,19,-1]
                                #,SirCalcExePath=r"C:\3S\SIR 3S\SirCalc-90-14-02-10_Potsdam\SirCalc.exe"
)
INFO    ; Dx.__init__: dbFile (abspath): c:\users\aUserName\3s\pt3s\Examples\Example3.db3 exists readable ...
INFO    ; dxAndMxHelperFcts.readDxAndMx: Model is being recalculated using C:\3S\SIR 3S\SirCalc-90-14-02-10_Potsdam\SirCalc.exe
INFO    ; Mx.setResultsToMxsFile: Mxs: ..\Examples\WDExample3\B1\V0\BZ1\M-1-0-1.1.MXS reading ...
INFO    ; dxWithMx.__init__: Example3: processing dx and mx ...

Longitudinal Sections: V3_AGSN

[9]:
m.V3_AGSN.head()
[9]:
Pos pk tk LFDNR NAME XL compNr nextNODE OBJTYPE OBJID ... RHO_n mlc_n ('STAT', 'mlc', Timestamp('2023-02-12 23:00:00'), Timestamp('2023-02-12 23:00:00'))_n ('TIME', 'mlc', Timestamp('2023-02-12 23:00:00'), Timestamp('2023-02-12 23:00:00'))_n ('TMIN', 'mlc', Timestamp('2023-02-12 23:00:00'), Timestamp('2023-02-13 23:00:00'))_n ('TMAX', 'mlc', Timestamp('2023-02-12 23:00:00'), Timestamp('2023-02-13 23:00:00'))_n ('TIME', 'mlc', Timestamp('2023-02-13 06:00:00'), Timestamp('2023-02-13 06:00:00'))_n ('TIME', 'mlc', Timestamp('2023-02-13 12:00:00'), Timestamp('2023-02-13 12:00:00'))_n ('TIME', 'mlc', Timestamp('2023-02-13 18:00:00'), Timestamp('2023-02-13 18:00:00'))_n ('TIME', 'mlc', Timestamp('2023-02-13 23:00:00'), Timestamp('2023-02-13 23:00:00'))_n
0 -1 5755933101669454049 5755933101669454049 1.0 Längsschnitt 0 1 V-E0 ROHR 5691533564979419761 ... 965.700012 592.984993 592.958713 592.962286 592.958738 602.48758 602.03723 599.532769 602.487611 593.486796
0 0 5755933101669454049 5755933101669454049 1.0 Längsschnitt 0 1 V-K1683S ROHR 5691533564979419761 ... 965.701172 592.958713 592.958713 592.962286 592.958738 602.48758 602.03723 599.532769 602.487611 593.486796
1 1 5755933101669454049 5755933101669454049 1.0 Längsschnitt 0 1 V-K1693S ROHR 5048873293262650113 ... 965.702148 592.937202 592.937202 592.941546 592.937253 602.419501 601.971421 599.479587 602.419561 593.464211
2 2 5755933101669454049 5755933101669454049 1.0 Längsschnitt 0 1 V-K2163S ROHR 5715081934973525403 ... 965.702637 592.926449 592.926449 592.931165 592.926512 602.385399 601.938456 599.452945 602.385474 593.452897
3 3 5755933101669454049 5755933101669454049 1.0 Längsschnitt 0 1 V-K2043S ROHR 5413647981880727734 ... 965.703735 592.901884 592.901884 592.907361 592.901971 602.306951 601.862619 599.391653 602.307055 593.426847

5 rows × 85 columns

Plot Section No. 1

Define Axes

[10]:
def fyPH(ax,offset=0):
    ax.spines["left"].set_position(("outward", offset))
    ax.set_ylabel('PH Druck in bar')
    #ax.set_ylim(1,6)
    #ax.set_yticks(sorted(np.append(np.linspace(1,6,11),[])))
    ax.yaxis.set_ticks_position('left')
    ax.yaxis.set_label_position('left')

def fymlc(ax,offset=60):
    ax.spines["left"].set_position(("outward", offset))
    ax.set_ylabel('mlc Druckhöhe in mlc')
    #ax.set_ylim(1,6)
    #ax.set_yticks(sorted(np.append(np.linspace(1,6,11),[])))
    ax.yaxis.set_ticks_position('left')
    ax.yaxis.set_label_position('left')

def fybarBzg(ax,offset=120):
    ax.spines["left"].set_position(("outward", offset))
    ax.set_ylabel('H Druck in barBzg')
    #ax.set_ylim(1,6)
    #ax.set_yticks(sorted(np.append(np.linspace(1,6,11),[])))
    ax.yaxis.set_ticks_position('left')
    ax.yaxis.set_label_position('left')

def fyM(ax,offset=180):
    Rm.pltLDSHelperY(ax)
    ax.spines["left"].set_position(("outward",offset))
    ax.set_ylabel('QM Massenstrom in t/h')
    #ax.set_ylim(500,550)
    #ax.set_yticks(sorted(np.append(np.linspace(500,550,11),[])))
    ax.yaxis.set_ticks_position('left')
    ax.yaxis.set_label_position('left')

def fyT(ax,offset=240):
    Rm.pltLDSHelperY(ax)
    ax.spines["left"].set_position(("outward",offset))
    ax.set_ylabel('T Tempertatur in °C')
    ax.set_ylim(55,95)
    #ax.set_yticks(sorted(np.append(np.linspace(0,95,11),[])))
    ax.yaxis.set_ticks_position('left')
    ax.yaxis.set_label_position('left')

Plotfunction

[11]:
def plot(dfAGSN=pd.DataFrame()
        ,dfAGSNRL=pd.DataFrame()
        ,PHCol='PH_n'
        ,mlcCol='mlc_n'
        ,zKoorCol='ZKOR_n'
        ,barBzgCol='H_n'
        ,QMCol='QM'
        ,TCol='T_n'
        ,xCol='LSum'

):

    fig, ax0 = plt.subplots(figsize=Rm.DINA3q)

    ax0.set_yticks(np.linspace(0, 10, 21))
    ax0.yaxis.set_ticklabels([])
    ax0.grid()

    #PH
    ax1 = ax0.twinx()
    fyPH(ax1)
    PH_SL=ax1.plot(dfAGSN[xCol], dfAGSN[PHCol], color='red', label='PH SL',ls='dotted')
    PH_RL=ax1.plot(dfAGSNRL[xCol], dfAGSNRL[PHCol], color='blue', label='PH RL',ls='dotted')

    #mlc
    ax11 = ax0.twinx()
    fymlc(ax11)
    mlc_SL=ax11.plot(dfAGSN[xCol], dfAGSN[mlcCol], color='red', label='mlc SL')
    mlc_RL=ax11.plot(dfAGSNRL[xCol], dfAGSNRL[mlcCol], color='blue', label='mlc RL')

    z=ax11.plot(dfAGSN[xCol], dfAGSN[zKoorCol], color='black', label='z',ls='dashed',alpha=.5)

    #barBZG
    ax12 = ax0.twinx()
    fybarBzg(ax12)
    barB_SL=ax12.plot(dfAGSN[xCol], dfAGSN[barBzgCol], color='red', label='H SL',ls='dashdot')
    barB_RL=ax12.plot(dfAGSNRL[xCol], dfAGSNRL[barBzgCol], color='blue', label='H RL',ls='dashdot')

    #M
    ax2 = ax0.twinx()
    fyM(ax2)
    QM_SL=ax2.step(dfAGSN[xCol], dfAGSN[QMCol]*dfAGSN['direction'], color='orange', label='M SL')
    QM_RL=ax2.step(dfAGSNRL[xCol], dfAGSNRL[QMCol]*dfAGSNRL['direction'], color='cyan', label='M RL',ls='--')

    #T
    ax3 = ax0.twinx()
    fyT(ax3)
    T_SL=ax3.plot(dfAGSN[xCol], dfAGSN[TCol], color='pink', label='T SL')
    T_RL=ax3.plot(dfAGSNRL[xCol], dfAGSNRL[TCol], color='lavender', label='T RL')

    ax0.set_title('Longitudinal Section for '+dbFilename)

    # added these three lines
    lns =  PH_SL+ PH_RL + mlc_SL+ mlc_RL + barB_SL+ barB_RL+ QM_SL+ QM_RL + T_SL+ T_RL + z
    labs = [l.get_label() for l in lns]
    ax0.legend(lns, labs)#, loc=0)

    plt.show()

Plot without vector data

[12]:
dfAGSN=m.V3_AGSN[
    (m.V3_AGSN['LFDNR']==1)
    &
    (m.V3_AGSN['XL']==1)
]
[13]:
dfAGSNRL=m.V3_AGSN[
    (m.V3_AGSN['LFDNR']==1)
    &
    (m.V3_AGSN['XL']==2)
]
[14]:
plot(dfAGSN,dfAGSNRL)
_images/Example3_26_0.png

Plot with vector data (with pipe interior points)

[15]:
dfAGSNVec=m.V3_AGSNVEC[
    (m.V3_AGSNVEC['LFDNR']==1)
    &
    (m.V3_AGSNVEC['XL']==1)
]

[16]:
dfAGSNVecRL=m.V3_AGSNVEC[
 (m.V3_AGSNVEC['LFDNR']==1)
    &
    (m.V3_AGSNVEC['XL']==2)
]
[17]:
t0rVec=pd.Timestamp(m.mx.df.index[0].strftime('%Y-%m-%d %X'))#.%f'))
[18]:
manPVEC=('STAT',
                      'manPVEC',
                      t0rVec,
                      t0rVec)
[19]:
manPVEC
[19]:
('STAT',
 'manPVEC',
 Timestamp('2023-02-12 23:00:00'),
 Timestamp('2023-02-12 23:00:00'))
[20]:
# for convenient colnames in celloutput
dfAGSNVec['manPVEC']=dfAGSNVec[manPVEC]
dfAGSNVecRL['manPVEC']=dfAGSNVecRL[manPVEC]
[21]:
mlcPVEC=('STAT',
                      'mlcPVEC',
                      t0rVec,
                      t0rVec)
[22]:
# for convenient colnames in celloutput
dfAGSNVec['mlcPVEC']=dfAGSNVec[mlcPVEC]
dfAGSNVecRL['mlcPVEC']=dfAGSNVecRL[mlcPVEC]
[23]:
QMVEC=('STAT',
                      'QMVEC',
                      t0rVec,
                      t0rVec)
[24]:
QMVEC=('STAT',
                      'QMVEC',
                      t0rVec,
                      t0rVec)
[25]:
# for convenient colnames in celloutput
dfAGSNVec['QMVEC']=dfAGSNVec[QMVEC]
dfAGSNVecRL['QMVEC']=dfAGSNVecRL[QMVEC]
[26]:
TVEC=('STAT',
'ROHR~*~*~*~TVEC',
t0rVec,
t0rVec)
[27]:
# for convenient colnames in celloutput
dfAGSNVec['TVEC']=dfAGSNVec[TVEC]
dfAGSNVecRL['TVEC']=dfAGSNVecRL[TVEC]
[28]:
plot(dfAGSNVec,dfAGSNVecRL
        ,PHCol=manPVEC
        ,mlcCol=mlcPVEC
        ,zKoorCol='ZVEC'
        ,barBzgCol='H_n'
        ,QMCol=QMVEC
        ,TCol=TVEC
        ,xCol='LSum'

    )
_images/Example3_41_0.png

Plot different timesteps with Bokeh

[29]:
def bokeh_plot(df, x_col, y_cols, y2_cols, y3_cols):
    output_notebook()

    p = figure(width=1366, height=768, title="Longitudinal Section for "+dbFilename+" at different timestamps", x_axis_label=x_col, y_axis_label="PH Druck in bar", tools="pan,wheel_zoom,box_zoom,reset", y_range=Range1d(start=0, end=6))

    # Define line styles and colors
    line_styles = ['solid', 'dashed', 'dotted']
    colors = ['blue', 'red', 'green']
    lines = []

    # lines for y
    for i, y_col in enumerate(y_cols):
        line = p.line(df[x_col], df[y_col], legend_label=f"{y_col} (06:00)" if i == 0 else f"{y_col} (12:00)" if i == 1 else f"{y_col} (18:00)", line_width=2, line_dash=line_styles[i % len(line_styles)], color=colors[0])
        lines.append(line)

    #second y-axis
    p.extra_y_ranges = {"y2": Range1d(start=0, end=600)}
    p.add_layout(LinearAxis(y_range_name="y2", axis_label="QM Massenstrom in t/h"), 'left')

    # lines for y2
    for i, y2_col in enumerate(y2_cols):
        line = p.line(df[x_col], df[y2_col], legend_label=f"{y2_col} (06:00)" if i == 0 else f"{y2_col} (12:00)" if i == 1 else f"{y2_col} (18:00)", line_width=2, line_dash=line_styles[i % len(line_styles)], color=colors[1], y_range_name="y2")
        lines.append(line)

    #third y-axis
    p.extra_y_ranges["y3"] = Range1d(start=590, end=610)
    p.add_layout(LinearAxis(y_range_name="y3", axis_label="mlc in m"), 'left')

    # lines for y3
    for i, y3_col in enumerate(y3_cols):
        line = p.line(df[x_col], df[y3_col], legend_label=f"{y3_col} (06:00)" if i == 0 else f"{y3_col} (12:00)" if i == 1 else f"{y3_col} (18:00)", line_width=2, line_dash=line_styles[i % len(line_styles)], color=colors[2], y_range_name="y3")
        lines.append(line)

    # Create a CheckboxGroup
    labels = [f"{y_col}" for i, y_col in enumerate(y_cols + y2_cols + y3_cols)]
    checkbox = CheckboxGroup(labels=labels, active=list(range(len(labels))))

    # CustomJS to toggle visibility
    checkbox.js_on_change('active', CustomJS(args=dict(lines=lines), code="""
        for (let i = 0; i < lines.length; i++) {
            lines[i].visible = this.active.includes(i);
        }
    """))

    show(column(p, checkbox))

[30]:
bokeh_plot(dfAGSNVec, 'LSum',['PH_n_1', 'PH_n_2', 'PH_n_3'], ['QM_1', 'QM_2', 'QM_3'], ['mlc_n_1', 'mlc_n_2', 'mlc_n_3'])
Loading BokehJS ...