Example 7: Source Spectrum
This example demonstrates how GeoDataFrames (gdfs) and V3_dataframe created by PT3S can be used with matplotlib to create an interactive depiction of a source spectrum.
PT3S Release
[52]:
#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).[53]:
!pip install -q shapely ipywidgets
Imports
[54]:
import os
import logging
import pandas as pd
from pandas import Timestamp
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import geopandas as gpd
from shapely.geometry import LineString, Point
from matplotlib.patches import Circle
import ipywidgets as widgets
#...
try:
from PT3S import dxAndMxHelperFcts
except:
import dxAndMxHelperFcts
try:
from PT3S import Rm
except:
import Rm
try:
from PT3S import ncd
except:
import ncd
#...
[55]:
import importlib
from importlib import resources
[56]:
#importlib.reload(ncd)
Logging
[57]:
logger = logging.getLogger()
if not logger.handlers:
logFileName = r"Example7.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
[58]:
dbFilename="Example5"
dbFile = resources.files("PT3S").joinpath("Examples", f"{dbFilename}.db3")
[ ]:
m=dxAndMxHelperFcts.readDxAndMx(dbFile=dbFile
,preventPklDump=True
,maxRecords=-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\PT3S\Examples\Example5.db3 exists readable ...
INFO ; PT3S.dxAndMxHelperFcts.readDxAndMx: Model is being recalculated using C:\3S\SIR 3S\SirCalc-90-14-02-10_Potsdam\SirCalc.exe
INFO ; Mx.setResultsToMxsFile: Mxs: ..\PT3S\Examples\WDExample5\B1\V0\BZ1\M-1-0-1.1.MXS reading ...
INFO ; dxWithMx.__init__: Example5: processing dx and mx ...
Preparing Data
[60]:
dfKNOT=m.V3_KNOT
[61]:
dfROHR=m.gdf_ROHR
[62]:
# Get soure signatures for start and end knot
dfROHR['srcvector_fkKI'] = dfROHR['fkKI'].map(dfKNOT.set_index('tk')['srcvector'])
dfROHR['srcvector_fkKK'] = dfROHR['fkKK'].map(dfKNOT.set_index('tk')['srcvector'])
[63]:
QM=('STAT',
'ROHR~*~*~*~QMAV',
Timestamp('2024-01-09 23:00:00'),
Timestamp('2024-01-09 23:00:00'))
[64]:
dfROHR['srcvector_plot'] = np.where(dfROHR[QM] > 0, dfROHR['srcvector_fkKI'], dfROHR['srcvector_fkKK'])
[65]:
dfROHR = dfROHR[dfROHR['KVR'] != 2.0]
Plotting
[66]:
colors = [np.array([255, 0, 0]), np.array([0, 0, 255])]
[67]:
fig, ax = plt.subplots(figsize=Rm.DINA3q)
ncd.plot_src_spectrum(ax, dfROHR,'srcvector_plot', colors)
plt.show()
xlim = ax.get_xlim()
ylim = ax.get_ylim()
canvas_center = ((xlim[0] + xlim[1]) / 2, (ylim[0] + ylim[1]) / 2)
fig.savefig('Example7_Output_1.pdf')

Plot with Pie Charts
Prepara Data
[68]:
dfROHR['srcvector_plot'] = dfROHR['srcvector_plot'].apply(lambda x: tuple(x) if isinstance(x, list) else x)
[69]:
unique_values = dfROHR['srcvector_plot'].unique()
[70]:
df = pd.DataFrame({
'srcvector_plot': unique_values,
'geometry': [dfROHR[dfROHR['srcvector_plot'] == value]['geometry'].iloc[0] for value in unique_values]
})
[71]:
df[['left', 'right']] = pd.DataFrame(df['srcvector_plot'].tolist(), index=df.index)
df['left'] = df['left'].astype(int)
df['right'] = df['right'].astype(int)
[72]:
df['pos'] = df['geometry'].apply(lambda geom: geom.interpolate(0.5) if isinstance(geom, LineString) else None)
[73]:
def create_offset_point_away_from_midpoint(midpoint, canvas_center, scale=0.5):
if midpoint is not None:
# Calculate the direction vector from the canvas center to the midpoint
direction_vector = Point(midpoint.x - canvas_center[0], midpoint.y - canvas_center[1])
# Normalize the direction vector
magnitude = (direction_vector.x**2 + direction_vector.y**2)**0.5
normalized_vector = Point(direction_vector.x / magnitude, direction_vector.y / magnitude)
# Create a point away from the midpoint in the direction away from the canvas center
offset_point = Point(midpoint.x + normalized_vector.x * scale, midpoint.y + normalized_vector.y * scale)
return offset_point
return None
[74]:
df['offset_point'] = df['pos'].apply(lambda pos: create_offset_point_away_from_midpoint(pos, canvas_center, scale=3000))
[75]:
def create_circle_around_offset_point(offset_point, radius=1000):
if offset_point is not None:
return Point(offset_point.x, offset_point.y).buffer(radius)
return None
[76]:
df['circle'] = df['offset_point'].apply(lambda offset_point: create_circle_around_offset_point(offset_point, radius=1000))
[77]:
#df.head()
[78]:
df['helper_line'] = df.apply(lambda row: LineString([row['pos'], row['offset_point'].representative_point()]) if row['offset_point'] is not None else None, axis=1)
[79]:
df = df.sort_values(by='left', ascending=True)
[80]:
colors2=['red','blue']
Plotting Functions
Version 1 interactive
[81]:
def plot_pie_charts_v1(ax, indexes, size=0.3, font_size=10, alpha=0.5):
for index in indexes:
if index < 0 or index >= len(df):
print(f"Index {index} out of range")
continue
x = df['left'].iloc[index]
y = df['right'].iloc[index]
pos = df['pos'].iloc[index]
x = int(x)
y = int(y)
# Only plot if both x and y are at least 15 or both are 0
#if (x >= 15 and y >= 15) or (x == 0 and y == 0):
if pos is not None:
# Place the pie chart at the midpoint of the line
inset_ax = ax.inset_axes([pos.x, pos.y, size, size], transform=ax.transData)
pie_wedges, texts, autotexts = inset_ax.pie([x, y], labels=[' ', ' '], autopct='%1.1f%%', colors=colors2, textprops={'fontsize': font_size})
# Set the alpha value for the pie chart wedges
for wedge in pie_wedges:
wedge.set_alpha(alpha)
Version 1 output
[82]:
def plot_pie_charts_v1_output(ax, indexes, size=0.3, font_size=10, alpha=0.5):
for index in indexes:
if index < 0 or index >= len(df):
print(f"Index {index} out of range")
continue
x = df['left'].iloc[index]
y = df['right'].iloc[index]
pos = df['pos'].iloc[index]
x = int(x)
y = int(y)
if pos is not None:
# Place the pie chart at the midpoint of the line
inset_ax = ax.inset_axes([pos.x, pos.y, size, size], transform=ax.transData)
pie_wedges, texts, autotexts = inset_ax.pie([x, y], labels=[' ', ' '], autopct='%1.1f%%', colors=colors2, textprops={'fontsize': font_size})
# Set the alpha value for the pie chart wedges
for wedge in pie_wedges:
wedge.set_alpha(alpha)
fig.savefig('Example7_Output_2.pdf')
Version 2 interactive
[83]:
def plot_pie_charts_v2(ax, indexes, size=0.3, font_size=10, alpha=0.5):
for index in indexes:
if index < 0 or index >= len(df):
print(f"Index {index} out of range")
continue
x = df['left'].iloc[index]
y = df['right'].iloc[index]
pos = df['pos'].iloc[index]
x = int(x)
y = int(y)
circle = df['circle'].iloc[index]
helper_line = df['helper_line'].iloc[index]
if circle is not None:
# Get the centroid of the circle to place the pie chart
centroid = circle.centroid
# Place the pie chart at the centroid of the circle
inset_ax = ax.inset_axes([centroid.x, centroid.y, size, size], transform=ax.transData)
pie_wedges, texts, autotexts = inset_ax.pie([x, y], labels=[' ', ' '], autopct='%1.1f%%', colors=colors2, textprops={'fontsize': font_size})
# Set the alpha value for the pie chart wedges
for wedge in pie_wedges:
wedge.set_alpha(alpha)
# Plot the helper line from the midpoint to the pie chart
if helper_line is not None:
ax.plot(*helper_line.xy, 'k--', transform=ax.transData)
# Plot all offset points
offset_points = df['offset_point'].dropna()
ax.scatter([point.x for point in offset_points], [point.y for point in offset_points], color='red', label='Offset Points')
Version 2 output
[84]:
def plot_pie_charts_v2_output(ax, indexes, size=0.3, font_size=10, alpha=0.5):
for index in indexes:
if index < 0 or index >= len(df):
print(f"Index {index} out of range")
continue
x = df['left'].iloc[index]
y = df['right'].iloc[index]
pos = df['pos'].iloc[index]
x = int(x)
y = int(y)
circle = df['circle'].iloc[index]
helper_line = df['helper_line'].iloc[index]
if circle is not None:
# Get the centroid of the circle to place the pie chart
centroid = circle.centroid
# Place the pie chart at the centroid of the circle
inset_ax = ax.inset_axes([centroid.x, centroid.y, size, size], transform=ax.transData)
pie_wedges, texts, autotexts = inset_ax.pie([x, y], labels=[' ', ' '], autopct='%1.1f%%', colors=colors2, textprops={'fontsize': font_size})
# Set the alpha value for the pie chart wedges
for wedge in pie_wedges:
wedge.set_alpha(alpha)
# Plot the helper line from the midpoint to the pie chart
if helper_line is not None:
ax.plot(*helper_line.xy, 'k--', transform=ax.transData)
fig.savefig('Example7_Output_3.pdf')
Plotting
Version 1 interactive
[85]:
#count = len(df[((df['left'] >= 15) & (df['right'] >= 15)) | ((df['left'] == 0) & (df['right'] == 0))])
[86]:
def interactive_plot(**kwargs):
fig, ax = plt.subplots(figsize=Rm.DINA3q)
ncd.plot_src_spectrum(ax, dfROHR, 'srcvector_plot', colors)
for i in range(21):
if kwargs[f'Index_{i}']:
plot_pie_charts_v1(ax, [i], size=750, alpha=0.5)
plt.show()
[87]:
checkboxes = {f'Index_{i}': widgets.Checkbox(value=False, description=f'{i}: {df["left"].iloc[i]}/{df["right"].iloc[i]}') for i in range(21)}
<Figure size 640x480 with 0 Axes>

<Figure size 640x480 with 0 Axes>

[ ]:
widgets_interact = widgets.interactive(interactive_plot, **checkboxes)
<Figure size 640x480 with 0 Axes>

<Figure size 640x480 with 0 Axes>

[89]:
def update_plot(change):
plt.clf()
interactive_plot(**{key: checkboxes[key].value for key in checkboxes})
[90]:
for key in checkboxes:
checkboxes[key].observe(update_plot, names='value')
[91]:
display(widgets_interact)
Version 1 output
[92]:
indexes_to_plot = [0, 5, 6, 9, 13, 20]
[93]:
fig, ax = plt.subplots(figsize=Rm.DINA3q)
ncd.plot_src_spectrum(ax, dfROHR,'srcvector_plot', colors)
plot_pie_charts_v1_output(ax, indexes_to_plot, size=750, alpha=0.5)
plt.show()

Version 2 interactive
[94]:
def interactive_plot_2(**kwargs):
fig, ax = plt.subplots(figsize=Rm.DINA3q)
ncd.plot_src_spectrum(ax, dfROHR, 'srcvector_plot', colors)
for i in range(len(df)):
if kwargs.get(f'Index_{i}', False):
plot_pie_charts_v2(ax, [i], size=750)
plt.show()
[95]:
# Create checkboxes with proportions and index as descriptions
checkboxes_2 = {f'Index_{i}': widgets.Checkbox(value=False, description=f'{i}: {df["left"].iloc[i]}/{df["right"].iloc[i]}') for i in range(21)}
[96]:
widgets_interact_2 = widgets.interactive(interactive_plot_2, **checkboxes_2)
[97]:
def update_plot_2(change):
plt.clf()
interactive_plot_2(**{key: checkboxes_2[key].value for key in checkboxes_2})
[98]:
for key in checkboxes_2:
checkboxes_2[key].observe(update_plot_2, names='value')
[99]:
display(widgets_interact_2)
Version 2 output
[100]:
indexes_to_plot = [0, 5, 6, 13, 20]
[101]:
fig, ax = plt.subplots(figsize=Rm.DINA3q)
ncd.plot_src_spectrum(ax, dfROHR,'srcvector_plot', colors)
plot_pie_charts_v2_output(ax, indexes_to_plot, size=750, alpha=0.5)
plt.show()

[ ]: