add custom plot export to CSV

compare_results
Theophile Terraz 2024-09-20 14:02:12 +02:00
parent f755b7ce74
commit 9d01ab0e16
5 changed files with 222 additions and 77 deletions

View File

@ -263,6 +263,7 @@ class InitialConditionsWindow(PamhyrWindow):
workdir = os.path.dirname(self._study.filename) workdir = os.path.dirname(self._study.filename)
return self.file_dialog( return self.file_dialog(
select_file=True,
callback=lambda d: self._import_from_file(d[0]), callback=lambda d: self._import_from_file(d[0]),
directory=workdir, directory=workdir,
default_suffix=".BIN", default_suffix=".BIN",

View File

@ -45,6 +45,7 @@ class CustomPlotValuesSelectionDialog(PamhyrDialog):
self.setup_check_boxs() self.setup_check_boxs()
self.value = None self.value = None
self.export_to_csv = False
def setup_radio_buttons(self): def setup_radio_buttons(self):
self._radio = [] self._radio = []
@ -95,4 +96,6 @@ class CustomPlotValuesSelectionDialog(PamhyrDialog):
) )
self.value = x, y self.value = x, y
self.export_to_csv = self.find(QCheckBox,
"checkBox_export").isChecked()
super().accept() super().accept()

View File

@ -20,6 +20,8 @@ import os
import csv import csv
import logging import logging
from numpy import sqrt
from datetime import datetime from datetime import datetime
from tools import trace, timer, logger_exception from tools import trace, timer, logger_exception
@ -489,12 +491,17 @@ class ResultsWindow(PamhyrWindow):
dlg = CustomPlotValuesSelectionDialog(parent=self) dlg = CustomPlotValuesSelectionDialog(parent=self)
if dlg.exec(): if dlg.exec():
x, y = dlg.value x, y = dlg.value
self.create_new_tab_custom_plot(x, y) export = dlg.export_to_csv
self.create_new_tab_custom_plot(x, y, export)
def create_new_tab_custom_plot(self, x: str, y: list): def create_new_tab_custom_plot(self, x: str, y: list, export: bool):
name = f"{x}: {','.join(y)}" name = f"{x}: {','.join(y)}"
wname = f"tab_custom_{x}_{y}" wname = f"tab_custom_{x}_{y}"
if export:
self.export(x, y)
return
tab_widget = self.find(QTabWidget, f"tabWidget") tab_widget = self.find(QTabWidget, f"tabWidget")
# This plot already exists # This plot already exists
@ -534,6 +541,7 @@ class ResultsWindow(PamhyrWindow):
grid.addWidget(canvas, 1, 0) grid.addWidget(canvas, 1, 0)
widget.setLayout(grid) widget.setLayout(grid)
tab_widget.addTab(widget, name) tab_widget.addTab(widget, name)
tab_widget.setCurrentWidget(widget)
def _copy(self): def _copy(self):
logger.info("TODO: copy") logger.info("TODO: copy")
@ -582,18 +590,28 @@ class ResultsWindow(PamhyrWindow):
self._button_last.setEnabled(True) self._button_last.setEnabled(True)
self._button_play.setIcon(self._icon_start) self._button_play.setIcon(self._icon_start)
def export(self): def export(self, x: str, y: list):
logger.debug(
"Export custom plot for: " +
f"{x} -> {','.join(y)}"
)
self.file_dialog( self.file_dialog(
select_file=False, callback=lambda f: self.export_to(f[0], x, y),
callback=lambda d: self.export_to(d[0]) default_suffix=".csv",
file_filter=["CSV (*.csv)"],
) )
def export_to(self, directory): def export_to(self, filename, x, y):
timestamps = sorted(self._results.get("timestamps")) timestamps = sorted(self._results.get("timestamps"))
for reach in self._results.river.reachs: if x == "rk":
self.export_reach(reach, directory, timestamps) timestamp = self._get_current_timestamp()
self._export_rk(timestamp, y, filename)
elif x == "time":
profile = self._get_current_profile()
self._export_time(profile, y, filename)
def export_reach(self, reach, directory, timestamps): def export_all(self, reach, directory, timestamps):
name = reach.name name = reach.name
name = name.replace(" ", "-") name = name.replace(" ", "-")
if len(timestamps) == 1: if len(timestamps) == 1:
@ -607,25 +625,6 @@ class ResultsWindow(PamhyrWindow):
with open(file_name, 'w', newline='') as csvfile: with open(file_name, 'w', newline='') as csvfile:
writer = csv.writer(csvfile, delimiter=',', writer = csv.writer(csvfile, delimiter=',',
quotechar='|', quoting=csv.QUOTE_MINIMAL) quotechar='|', quoting=csv.QUOTE_MINIMAL)
if len(timestamps) > 1:
writer.writerow(["name", "rk", "data-file"])
for profile in reach.profiles:
p_file_name = os.path.join(
directory,
f"cs_{profile.geometry.id}.csv"
)
writer.writerow([
profile.name,
profile.rk,
p_file_name
])
self.export_profile(reach,
profile,
p_file_name,
timestamps)
else:
ts = timestamps[0] ts = timestamps[0]
writer.writerow(self._table["raw_data"]._headers) writer.writerow(self._table["raw_data"]._headers)
for row in range(self._table["raw_data"].rowCount()): for row in range(self._table["raw_data"].rowCount()):
@ -635,20 +634,6 @@ class ResultsWindow(PamhyrWindow):
line.append(self._table["raw_data"].data(index)) line.append(self._table["raw_data"].data(index))
writer.writerow(line) writer.writerow(line)
def export_profile(self, reach, profile, file_name, timestamps):
with open(file_name, 'w', newline='') as csvfile:
writer = csv.writer(csvfile, delimiter=',',
quotechar='|', quoting=csv.QUOTE_MINIMAL)
writer.writerow(["timestamp", "z", "q"])
for ts in timestamps:
writer.writerow([
ts,
profile.get_ts_key(ts, "Z"),
profile.get_ts_key(ts, "Q"),
])
def export_current(self): def export_current(self):
self.file_dialog( self.file_dialog(
select_file=False, select_file=False,
@ -657,9 +642,144 @@ class ResultsWindow(PamhyrWindow):
def export_current_to(self, directory): def export_current_to(self, directory):
reach = self._results.river.reachs[self._get_current_reach()] reach = self._results.river.reachs[self._get_current_reach()]
self.export_reach(reach, directory, [self._get_current_timestamp()]) self.export_all(reach, directory, [self._get_current_timestamp()])
def delete_tab(self, index): def delete_tab(self, index):
tab_widget = self.find(QTabWidget, f"tabWidget") tab_widget = self.find(QTabWidget, f"tabWidget")
self._additional_plot.pop(tab_widget.tabText(index)) self._additional_plot.pop(tab_widget.tabText(index))
tab_widget.removeTab(index) tab_widget.removeTab(index)
def _export_rk(self, timestamp, y, filename):
reach = self._results.river.reachs[self._get_current_reach()]
rk = reach.geometry.get_rk()
my_dict = {}
if "elevation" in y:
my_dict["elevation"] = reach.geometry.get_z_min()
if "discharge" in y:
my_dict["discharge"] = list(
map(
lambda p: p.get_ts_key(timestamp, "Q"),
reach.profiles
)
)
if "water_elevation" in y:
my_dict["water_elevation"] = list(
map(
lambda p: p.get_ts_key(timestamp, "Z"),
reach.profiles
)
)
if "velocity" in y:
my_dict["velocity"] = list(
map(
lambda p: p.geometry.speed(
p.get_ts_key(timestamp, "Q"),
p.get_ts_key(timestamp, "Z")),
reach.profiles
)
)
if "depth" in y:
my_dict["depth"] = list(
map(
lambda p: p.geometry.max_water_depth(
p.get_ts_key(timestamp, "Z")),
reach.profiles
)
)
if "mean_depth" in y:
my_dict["mean_depth"] = list(
map(
lambda p: p.geometry.mean_water_depth(
p.get_ts_key(timestamp, "Z")),
reach.profiles
)
)
if "froude" in y:
my_dict["froude"] = list(
map(
lambda p:
p.geometry.speed(
p.get_ts_key(timestamp, "Q"),
p.get_ts_key(timestamp, "Z")) /
sqrt(9.81 * (
p.geometry.wet_area(
p.get_ts_key(timestamp, "Z")) /
p.geometry.wet_width(
p.get_ts_key(timestamp, "Z"))
)),
reach.profiles
)
)
if "wet_area" in y:
my_dict["wet_area"] = list(
map(
lambda p: p.geometry.wet_area(
p.get_ts_key(timestamp, "Z")),
reach.profiles
)
)
with open(filename, 'w', newline='') as csvfile:
writer = csv.writer(csvfile, delimiter=',',
quotechar='|', quoting=csv.QUOTE_MINIMAL)
header = ["rk"] + y
writer.writerow(header)
for row in range(len(rk)):
line = [rk[row]]
for var in y:
line.append(my_dict[var][row])
writer.writerow(line)
def _export_time(self, profile, y, filename):
reach = self._results.river.reachs[self._get_current_reach()]
profile = reach.profile(profile)
ts = list(self._results.get("timestamps"))
ts.sort()
my_dict = {}
z = profile.get_key("Z")
q = profile.get_key("Q")
if "elevation" in y:
my_dict["elevation"] = [profile.geometry.z_min()] * len(ts)
if "discharge" in y:
my_dict["discharge"] = q
if "water_elevation" in y:
my_dict["water_elevation"] = z
if "velocity" in y:
my_dict["velocity"] = list(
map(
lambda q, z: profile.geometry.speed(q, z),
q, z
)
)
if "depth" in y:
my_dict["depth"] = list(
map(lambda z: profile.geometry.max_water_depth(z), z)
)
if "mean_depth" in y:
my_dict["mean_depth"] = list(
map(lambda z: profile.geometry.mean_water_depth(z), z)
)
if "froude" in y:
my_dict["froude"] = list(
map(lambda z, q:
profile.geometry.speed(q, z) /
sqrt(9.81 * (
profile.geometry.wet_area(z) /
profile.geometry.wet_width(z))
), z, q)
)
if "wet_area" in y:
my_dict["wet_area"] = list(
map(lambda z: profile.geometry.wet_area(z), z)
)
with open(filename, 'w', newline='') as csvfile:
writer = csv.writer(csvfile, delimiter=',',
quotechar='|', quoting=csv.QUOTE_MINIMAL)
header = ["time"] + y
writer.writerow(header)
for row in range(len(ts)):
line = [ts[row]]
for var in y:
line.append(my_dict[var][row])
writer.writerow(line)

View File

@ -85,7 +85,7 @@ class WindowToolKit(object):
return header, values return header, values
def file_dialog(self, select_file=True, def file_dialog(self, select_file=None,
callback=lambda x: None, callback=lambda x: None,
directory=None, directory=None,
default_suffix=None, default_suffix=None,
@ -107,16 +107,19 @@ class WindowToolKit(object):
dialog = QFileDialog(self, options=options) dialog = QFileDialog(self, options=options)
if select_file is not None:
if select_file: if select_file:
mode = QFileDialog.FileMode.ExistingFile mode = QFileDialog.FileMode.ExistingFile
else: else:
mode = QFileDialog.FileMode.Directory mode = QFileDialog.FileMode.Directory
else:
mode = QFileDialog.FileMode.AnyFile
dialog.setFileMode(mode) dialog.setFileMode(mode)
if directory is not None: if directory is not None:
dialog.setDirectory(directory) dialog.setDirectory(directory)
if select_file: if select_file is not False:
if default_suffix is not None: if default_suffix is not None:
dialog.setDefaultSuffix(default_suffix) dialog.setDefaultSuffix(default_suffix)

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>414</width> <width>414</width>
<height>482</height> <height>81</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -44,6 +44,22 @@
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QCheckBox" name="checkBox_export">
<property name="text">
<string>Export to CSV</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox"> <widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
@ -54,25 +70,11 @@
</widget> </widget>
</item> </item>
</layout> </layout>
</item>
</layout>
</widget> </widget>
<resources/> <resources/>
<connections> <connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Dialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection> <connection>
<sender>buttonBox</sender> <sender>buttonBox</sender>
<signal>rejected()</signal> <signal>rejected()</signal>
@ -89,5 +91,21 @@
</hint> </hint>
</hints> </hints>
</connection> </connection>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Dialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections> </connections>
</ui> </ui>