wolfhece 2.1.97__py3-none-any.whl → 2.1.99__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wolfhece/PyConfig.py +5 -8
- wolfhece/PyDraw.py +598 -47
- wolfhece/PyParams.py +18 -8
- wolfhece/PyVertex.py +12 -5
- wolfhece/PyVertexvectors.py +30 -22
- wolfhece/Results2DGPU.py +23 -7
- wolfhece/analyze_vect.py +177 -0
- wolfhece/apps/version.py +1 -1
- wolfhece/matplotlib_fig.py +1980 -0
- wolfhece/scenario/config_manager.py +190 -82
- wolfhece/wolf_array.py +25 -6
- wolfhece/wolfresults_2D.py +35 -4
- {wolfhece-2.1.97.dist-info → wolfhece-2.1.99.dist-info}/METADATA +1 -1
- {wolfhece-2.1.97.dist-info → wolfhece-2.1.99.dist-info}/RECORD +17 -15
- {wolfhece-2.1.97.dist-info → wolfhece-2.1.99.dist-info}/WHEEL +1 -1
- {wolfhece-2.1.97.dist-info → wolfhece-2.1.99.dist-info}/entry_points.txt +0 -0
- {wolfhece-2.1.97.dist-info → wolfhece-2.1.99.dist-info}/top_level.txt +0 -0
wolfhece/PyDraw.py
CHANGED
@@ -24,6 +24,7 @@ try:
|
|
24
24
|
import json
|
25
25
|
import glob
|
26
26
|
import traceback
|
27
|
+
from datetime import datetime, timedelta
|
27
28
|
except ImportError as e:
|
28
29
|
print(e)
|
29
30
|
raise ImportError("Error importing wxPython, numpy, PIL, json, glob, traceback. Please check your installation.")
|
@@ -731,6 +732,372 @@ class DragdropFileTarget(wx.FileDropTarget):
|
|
731
732
|
|
732
733
|
return True
|
733
734
|
|
735
|
+
|
736
|
+
class Sim_Explorer(wx.Frame):
|
737
|
+
|
738
|
+
def __init__(self, parent, title, mapviewer:"WolfMapViewer", sim:Wolfresults_2D):
|
739
|
+
|
740
|
+
super(Sim_Explorer, self).__init__(parent, title=title, size=(150, 250), style = wx.DEFAULT_FRAME_STYLE & ~ (wx.MAXIMIZE_BOX | wx.MINIMIZE_BOX))
|
741
|
+
|
742
|
+
self._panel = wx.Panel(self)
|
743
|
+
|
744
|
+
self.mapviewer = mapviewer
|
745
|
+
self.active_res2d:Wolfresults_2D = sim
|
746
|
+
|
747
|
+
main_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
748
|
+
|
749
|
+
left_bar = wx.BoxSizer(wx.VERTICAL)
|
750
|
+
right_bar = wx.BoxSizer(wx.VERTICAL)
|
751
|
+
|
752
|
+
self._all_times_steps = self.active_res2d.get_times_steps()
|
753
|
+
|
754
|
+
# Right bar
|
755
|
+
# ---------
|
756
|
+
|
757
|
+
# Slider
|
758
|
+
self._slider_steps = wx.Slider(self._panel, minValue=1, maxValue=sim.get_nbresults(), style=wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_MIN_MAX_LABELS | wx.SL_LABELS)
|
759
|
+
self._slider_steps.Bind(wx.EVT_SLIDER, self.OnSliderSteps)
|
760
|
+
right_bar.Add(self._slider_steps, 1, wx.EXPAND | wx.ALL, 2)
|
761
|
+
|
762
|
+
# Explore by index
|
763
|
+
self._label_idx = wx.StaticText(self._panel, label=_('Index'))
|
764
|
+
right_bar.Add(self._label_idx, 1, wx.EXPAND | wx.ALL, 2)
|
765
|
+
|
766
|
+
self._step_idx = wx.ListBox(self._panel, choices=[str(i) for i in range(1, sim.get_nbresults()+1)], style=wx.LB_SINGLE)
|
767
|
+
self._step_idx.Bind(wx.EVT_LISTBOX, self.OnSelectIdxStep)
|
768
|
+
right_bar.Add(self._step_idx, 1, wx.EXPAND | wx.ALL, 5)
|
769
|
+
|
770
|
+
# Explore by time
|
771
|
+
self._label_time = wx.StaticText(self._panel, label=_('Time [s]'))
|
772
|
+
right_bar.Add(self._label_time, 1, wx.EXPAND | wx.ALL, 2)
|
773
|
+
|
774
|
+
_now = datetime.now()
|
775
|
+
self._starting_date = datetime(year=_now.year, month=_now.month, day=_now.day, hour=0, minute=0, second=0)
|
776
|
+
self._texttime = wx.TextCtrl(self._panel, value=self._starting_date.strftime('%Y-%m-%d %H:%M:%S'))
|
777
|
+
right_bar.Add(self._texttime, 1, wx.EXPAND | wx.ALL, 5)
|
778
|
+
self._texttime.Bind(wx.EVT_TEXT, self.OnTextTime)
|
779
|
+
|
780
|
+
self._step_time = wx.ListBox(self._panel, choices=['{:.3f} - {}'.format(i, datetime.strftime(self._starting_date + timedelta(seconds=i), '%Y-%m-%d %H:%M:%S')) for i in self._all_times_steps[0]], style=wx.LB_SINGLE)
|
781
|
+
self._step_time.Bind(wx.EVT_LISTBOX, self.OnSelectNumStep)
|
782
|
+
right_bar.Add(self._step_time, 1, wx.EXPAND | wx.ALL, 5)
|
783
|
+
|
784
|
+
# Explore by time step
|
785
|
+
self._label_steps = wx.StaticText(self._panel, label=_('Time step [-]'))
|
786
|
+
right_bar.Add(self._label_steps, 1, wx.EXPAND | wx.ALL, 2)
|
787
|
+
|
788
|
+
self._step_num = wx.ListBox(self._panel, choices=[str(i) for i in self._all_times_steps[1]], style=wx.LB_SINGLE)
|
789
|
+
self._step_num.Bind(wx.EVT_LISTBOX, self.OnSelectCurTime)
|
790
|
+
right_bar.Add(self._step_num, 1, wx.EXPAND | wx.ALL, 5)
|
791
|
+
|
792
|
+
# Left bar
|
793
|
+
# --------
|
794
|
+
|
795
|
+
# Apply selected step
|
796
|
+
self._cmd_apply = wx.Button(self._panel, wx.ID_APPLY, _('Apply'))
|
797
|
+
self._cmd_apply.SetToolTip(_('Apply the selected parameters to the map'))
|
798
|
+
self._cmd_apply.Bind(wx.EVT_BUTTON, self.OnApply)
|
799
|
+
left_bar.Add(self._cmd_apply, 1, wx.EXPAND | wx.ALL, 5)
|
800
|
+
|
801
|
+
# Update listbox from files on disk
|
802
|
+
self._cmd_update = wx.Button(self._panel, wx.ID_REFRESH, _('Update'))
|
803
|
+
self._cmd_update.SetToolTip(_('Update the list of available results based on the files on disk'))
|
804
|
+
self._cmd_update.Bind(wx.EVT_BUTTON, self.OnUpdate)
|
805
|
+
left_bar.Add(self._cmd_update, 1, wx.EXPAND | wx.ALL, 5)
|
806
|
+
|
807
|
+
#Plot
|
808
|
+
self._cmd_plot = wx.Button(self._panel, wx.ID_PREVIEW, _('Plot simulation informations'))
|
809
|
+
self._cmd_plot.SetToolTip(_('Plot synthesis of the simulation (computation time, time step, clock time, mostly dry mesh...)'))
|
810
|
+
self._cmd_plot.Bind(wx.EVT_BUTTON, self.OnPlot)
|
811
|
+
left_bar.Add(self._cmd_plot, 1, wx.EXPAND | wx.ALL, 5)
|
812
|
+
|
813
|
+
# Next step
|
814
|
+
self._cmd_next = wx.Button(self._panel, wx.ID_FORWARD, _('Next'))
|
815
|
+
self._cmd_next.SetToolTip(_('Go to the next step -- using the selected mode'))
|
816
|
+
self._cmd_next.Bind(wx.EVT_BUTTON, self.OnNext)
|
817
|
+
left_bar.Add(self._cmd_next, 1, wx.EXPAND | wx.ALL, 5)
|
818
|
+
|
819
|
+
# Previous step
|
820
|
+
self._cmd_prev = wx.Button(self._panel, wx.ID_BACKWARD, _('Previous'))
|
821
|
+
self._cmd_prev.SetToolTip(_('Go to the previous step -- using the selected mode'))
|
822
|
+
self._cmd_prev.Bind(wx.EVT_BUTTON, self.OnPrev)
|
823
|
+
left_bar.Add(self._cmd_prev, 1, wx.EXPAND | wx.ALL, 5)
|
824
|
+
|
825
|
+
# Check Mode movement
|
826
|
+
self._mode = wx.ListBox(self._panel, choices=['by time [s]', 'by time [hour]', 'by index', 'by time step'], style=wx.LB_SINGLE)
|
827
|
+
self._mode.SetToolTip(_('Select the mode to move through the simulation'))
|
828
|
+
self._mode.SetSelection(2)
|
829
|
+
self._interval = wx.TextCtrl(self._panel, value='1', style=wx.ALIGN_CENTER_HORIZONTAL)
|
830
|
+
self._interval.SetToolTip(_('Interval for the mode selected -- unit depends on the mode'))
|
831
|
+
self._interval.Bind(wx.EVT_TEXT, self.OnInterval)
|
832
|
+
|
833
|
+
left_bar.Add(self._mode, 1, wx.EXPAND | wx.ALL, 5)
|
834
|
+
left_bar.Add(self._interval, 0, wx.EXPAND | wx.ALL, 5)
|
835
|
+
|
836
|
+
self.Bind(wx.EVT_CLOSE, self.OnClose)
|
837
|
+
|
838
|
+
main_sizer.Add(left_bar, 1, wx.EXPAND | wx.ALL, 2)
|
839
|
+
main_sizer.Add(right_bar, 1, wx.EXPAND | wx.ALL, 2)
|
840
|
+
|
841
|
+
self._panel.SetSizer(main_sizer)
|
842
|
+
self._panel.SetAutoLayout(True)
|
843
|
+
|
844
|
+
self.MinSize = (450, 500)
|
845
|
+
|
846
|
+
self.Fit()
|
847
|
+
self.Show()
|
848
|
+
|
849
|
+
self.SetIcon(wx.Icon(str(Path(__file__).parent / "apps/wolf_logo2.bmp")))
|
850
|
+
|
851
|
+
self._set_all(0)
|
852
|
+
|
853
|
+
def OnPlot(self, event):
|
854
|
+
""" Create a scatter plot of all steps.
|
855
|
+
|
856
|
+
Major x_axis is time in seconds, Minor X-axis is time by date.
|
857
|
+
|
858
|
+
Plots:
|
859
|
+
- Computation time step (Dt)
|
860
|
+
- Computation steps (N)
|
861
|
+
- Clock time (s)
|
862
|
+
- Mostly dry mesh (N)
|
863
|
+
|
864
|
+
"""
|
865
|
+
|
866
|
+
main_x = self._all_times_steps[0]
|
867
|
+
second_x = [self._starting_date + timedelta(seconds=i) for i in main_x]
|
868
|
+
|
869
|
+
if isinstance(self.active_res2d, wolfres2DGPU):
|
870
|
+
|
871
|
+
ax:list[Axes]
|
872
|
+
fig, ax= plt.subplots(5, 1, figsize=(10, 8))
|
873
|
+
|
874
|
+
ax[0].plot(main_x, self._all_times_steps[1], 'o-')
|
875
|
+
ax[0].set_ylabel(_('Computation\ntime step (N)'), fontsize=8)
|
876
|
+
ax[0].ticklabel_format(axis='y', style='sci', scilimits=(0,0))
|
877
|
+
|
878
|
+
ax[0].grid(which='both')
|
879
|
+
ax[0].set_xticks(main_x)
|
880
|
+
ax[0].set_xticklabels([])
|
881
|
+
|
882
|
+
secax:Axes = ax[0].secondary_xaxis('top')
|
883
|
+
secax.set_xlabel(_('Real date\n[Y-M-D H:M:S]'), fontsize=8)
|
884
|
+
secax.set_xticks(main_x)
|
885
|
+
secax.set_xticklabels([datetime.strftime(i, '%Y-%m-%d %H:%M') for i in second_x], fontsize=8)
|
886
|
+
secax.tick_params(axis='x', rotation=30)
|
887
|
+
|
888
|
+
ax[1].plot(main_x, self.active_res2d.all_dt, 'o-')
|
889
|
+
ax[1].set_ylabel(_('$\Delta t$ [s]'), fontsize=8)
|
890
|
+
ax[1].grid(which='both')
|
891
|
+
ax[1].set_xticks(main_x)
|
892
|
+
ax[1].set_xticklabels([])
|
893
|
+
ax[1].ticklabel_format(axis='y', style='sci', scilimits=(0,0))
|
894
|
+
|
895
|
+
ctime = self.active_res2d.all_clock_time
|
896
|
+
ax[2].plot(main_x, self.active_res2d.all_clock_time, 'o-')
|
897
|
+
ax[2].set_ylabel(_('Clock time [s]'), fontsize=8)
|
898
|
+
ax[2].grid(which='both')
|
899
|
+
ax[2].set_xticks([])
|
900
|
+
ax[2].set_xticks(main_x)
|
901
|
+
ax[2].set_xticklabels([])
|
902
|
+
ax[2].ticklabel_format(axis='y', style='sci', scilimits=(0,0))
|
903
|
+
|
904
|
+
# Fit a line on the (main_x - clock time) plot
|
905
|
+
# This will give a mean acceleration factor
|
906
|
+
# The inverse of the slope of the line is the accelaration factor
|
907
|
+
# The line is y = slope * x + intercept
|
908
|
+
from scipy.stats import linregress
|
909
|
+
slope, intercept, r_value, p_value, std_err = linregress(main_x, ctime)
|
910
|
+
|
911
|
+
# Plot the info on the ax[2]
|
912
|
+
msg = _('Acceleration factor:')
|
913
|
+
ax[2].text(0.5, 0.5, f'{msg} {1/slope:.2f}', transform=ax[2].transAxes, fontsize=12, verticalalignment='top')
|
914
|
+
|
915
|
+
ax[3].plot(main_x, self.active_res2d.all_wet_meshes, 'o-', color='blue')
|
916
|
+
ax[3].plot(main_x, self.active_res2d.all_mostly_dry_mesh, 'o-', color='green')
|
917
|
+
ax[3].set_ylabel(_('Wet and Mostly dry\nmeshes [N]'), fontsize=8)
|
918
|
+
ax[3].grid(which='both')
|
919
|
+
ax[3].set_xticks(main_x)
|
920
|
+
ax[3].set_xlabel([])
|
921
|
+
ax[3].ticklabel_format(axis='y', style='sci', scilimits=(0,0))
|
922
|
+
|
923
|
+
ax[4].plot(main_x, [i/j*100 if j>0 else 0 for i, j in zip(self.active_res2d.all_mostly_dry_mesh, self.active_res2d.all_wet_meshes)], 'o-', color='red')
|
924
|
+
ax[4].set_ylabel(_('Wet/Mostly dry\nmeshes [%]'), fontsize=8)
|
925
|
+
ax[4].grid(which='both')
|
926
|
+
ax[4].set_xticks(main_x)
|
927
|
+
ax[4].set_xlabel(_('Simulated time [s]'), fontsize=8)
|
928
|
+
ax[4].ticklabel_format(axis='y', style='sci', scilimits=(0,0))
|
929
|
+
|
930
|
+
fig.suptitle('Simulation {}'.format(self.active_res2d.idx), fontsize=10)
|
931
|
+
|
932
|
+
fig.tight_layout()
|
933
|
+
fig.show()
|
934
|
+
|
935
|
+
def OnInterval(self, event):
|
936
|
+
""" Change the interval """
|
937
|
+
|
938
|
+
try:
|
939
|
+
interv = float(self._interval.GetValue())
|
940
|
+
if interv <= 0:
|
941
|
+
interv = 1.
|
942
|
+
self._interval.SetValue('1')
|
943
|
+
except:
|
944
|
+
interv = 1
|
945
|
+
self._interval.SetValue('1')
|
946
|
+
|
947
|
+
def _find_next(self, idx:int):
|
948
|
+
""" Find the next step based on the mode and interval """
|
949
|
+
|
950
|
+
mode = int(self._mode.GetSelection())
|
951
|
+
|
952
|
+
if mode == 0:
|
953
|
+
# By time [s]
|
954
|
+
next_time = self._all_times_steps[0][idx] + float(self._interval.GetValue())
|
955
|
+
diff = [abs(next_time - i) for i in self._all_times_steps[0][idx:]]
|
956
|
+
next_idx = diff.index(min(diff)) + idx
|
957
|
+
|
958
|
+
return next_idx
|
959
|
+
|
960
|
+
elif mode == 1:
|
961
|
+
# By time [hour]
|
962
|
+
next_time = self._all_times_steps[0][idx] + float(self._interval.GetValue())*3600
|
963
|
+
diff = [abs(next_time - i) for i in self._all_times_steps[0][idx:]]
|
964
|
+
next_idx = diff.index(min(diff)) + idx
|
965
|
+
|
966
|
+
return next_idx
|
967
|
+
|
968
|
+
elif mode == 2:
|
969
|
+
# By index
|
970
|
+
next_idx = min(idx + int(self._interval.GetValue()), len(self._all_times_steps[0])-1)
|
971
|
+
|
972
|
+
return next_idx
|
973
|
+
|
974
|
+
elif mode == 3:
|
975
|
+
# By time step
|
976
|
+
next_idx = self._all_times_steps[1].index(self._all_times_steps[1][idx] + int(self._interval.GetValue()))
|
977
|
+
diff = [abs(next_idx - i) for i in self._all_times_steps[1][idx:]]
|
978
|
+
next_idx = diff.index(min(diff)) + idx
|
979
|
+
|
980
|
+
return next_idx
|
981
|
+
|
982
|
+
def _find_prev(self, idx:int):
|
983
|
+
""" Find the previous step based on the mode and interval """
|
984
|
+
|
985
|
+
mode = int(self._mode.GetSelection())
|
986
|
+
|
987
|
+
if mode == 0:
|
988
|
+
# By time [s]
|
989
|
+
prev_time = self._all_times_steps[0][idx] - float(self._interval.GetValue())
|
990
|
+
diff = [abs(prev_time - i) for i in self._all_times_steps[0][:i]]
|
991
|
+
prev_idx = diff.index(min(diff))
|
992
|
+
|
993
|
+
return prev_idx
|
994
|
+
|
995
|
+
elif mode == 1:
|
996
|
+
# By time [hour]
|
997
|
+
prev_time = self._all_times_steps[0][idx] - float(self._interval.GetValue())*3600
|
998
|
+
diff = [abs(prev_time - i) for i in self._all_times_steps[0][:i]]
|
999
|
+
prev_idx = diff.index(min(diff))
|
1000
|
+
|
1001
|
+
return prev_idx
|
1002
|
+
|
1003
|
+
elif mode == 2:
|
1004
|
+
# By index
|
1005
|
+
prev_idx = max(idx - int(self._interval.GetValue()), 0)
|
1006
|
+
|
1007
|
+
return prev_idx
|
1008
|
+
|
1009
|
+
elif mode == 3:
|
1010
|
+
# By time step
|
1011
|
+
prev_idx = self._all_times_steps[1].index(self._all_times_steps[1][idx] - int(self._interval.GetValue()))
|
1012
|
+
diff = [abs(prev_idx - i) for i in self._all_times_steps[1][:i]]
|
1013
|
+
prev_idx = diff.index(min(diff))
|
1014
|
+
|
1015
|
+
return prev_idx
|
1016
|
+
|
1017
|
+
def OnNext(self, event):
|
1018
|
+
""" Go to the next step """
|
1019
|
+
|
1020
|
+
selected_step = self._slider_steps.GetValue()-1
|
1021
|
+
next_idx = self._find_next(selected_step)
|
1022
|
+
|
1023
|
+
if next_idx != selected_step:
|
1024
|
+
self._set_all(next_idx)
|
1025
|
+
self.Refresh(next_idx)
|
1026
|
+
|
1027
|
+
def OnPrev(self, event):
|
1028
|
+
""" Go to the previous step """
|
1029
|
+
|
1030
|
+
selected_step = self._slider_steps.GetValue()-1
|
1031
|
+
prev_idx = self._find_prev(selected_step)
|
1032
|
+
|
1033
|
+
if prev_idx != selected_step:
|
1034
|
+
self._set_all(prev_idx)
|
1035
|
+
self.Refresh(prev_idx)
|
1036
|
+
|
1037
|
+
def OnTextTime(self, event):
|
1038
|
+
try:
|
1039
|
+
self._starting_date = datetime.strptime(self._texttime.GetValue(), '%Y-%m-%d %H:%M:%S')
|
1040
|
+
self._step_time.Set(['{:.3f} - {}'.format(i, datetime.strftime(self._starting_date + timedelta(seconds=i), '%Y-%m-%d %H:%M:%S')) for i in self._all_times_steps[0]])
|
1041
|
+
except:
|
1042
|
+
logging.info('Error while parsing the date')
|
1043
|
+
pass
|
1044
|
+
|
1045
|
+
def OnClose(self, event):
|
1046
|
+
""" Close the simulation explorer """
|
1047
|
+
|
1048
|
+
self.mapviewer._pop_sim_explorer(self.active_res2d)
|
1049
|
+
self.Destroy()
|
1050
|
+
|
1051
|
+
def OnUpdate(self, event):
|
1052
|
+
self._update()
|
1053
|
+
|
1054
|
+
def OnApply(self, event):
|
1055
|
+
selected_step = self._slider_steps.GetValue()-1
|
1056
|
+
|
1057
|
+
self._cmd_apply.SetBackgroundColour(wx.Colour(255, 0, 0)) # Set button color to red
|
1058
|
+
self._cmd_apply.Refresh() # Refresh the button to apply the color change
|
1059
|
+
|
1060
|
+
self.Refresh(selected_step)
|
1061
|
+
|
1062
|
+
self._cmd_apply.SetBackgroundColour(wx.NullColour) # Reset button color to default
|
1063
|
+
self._cmd_apply.Refresh() # Refresh the button to apply the color change
|
1064
|
+
|
1065
|
+
def _set_all(self, idx:int):
|
1066
|
+
self._slider_steps.SetValue(idx+1)
|
1067
|
+
self._step_idx.SetSelection(idx)
|
1068
|
+
self._step_time.SetSelection(idx)
|
1069
|
+
self._step_num.SetSelection(idx)
|
1070
|
+
|
1071
|
+
def Refresh(self, idx:int):
|
1072
|
+
self.active_res2d.read_oneresult(idx)
|
1073
|
+
self.active_res2d.set_currentview()
|
1074
|
+
self.mapviewer.Refresh()
|
1075
|
+
|
1076
|
+
def OnSliderSteps(self, event):
|
1077
|
+
selected_step = self._slider_steps.GetValue()
|
1078
|
+
self._set_all(selected_step-1)
|
1079
|
+
|
1080
|
+
def OnSelectCurTime(self, event):
|
1081
|
+
selected_time = self._step_num.GetSelection()
|
1082
|
+
self._set_all(selected_time)
|
1083
|
+
|
1084
|
+
def OnSelectNumStep(self, event):
|
1085
|
+
selected_step = self._step_time.GetSelection()
|
1086
|
+
self._set_all(selected_step)
|
1087
|
+
|
1088
|
+
def OnSelectIdxStep(self, event):
|
1089
|
+
selected_step = self._step_idx.GetSelection()
|
1090
|
+
self._set_all(selected_step)
|
1091
|
+
|
1092
|
+
def _update(self):
|
1093
|
+
nb = self.active_res2d.get_nbresults()
|
1094
|
+
self._all_times_steps = self.active_res2d.get_times_steps()
|
1095
|
+
|
1096
|
+
self._slider_steps.SetMax(nb)
|
1097
|
+
self._step_idx.Set([str(i) for i in range(1,nb+1)])
|
1098
|
+
self._step_time.Set(['{:.3f} - {}'.format(i, datetime.strftime(self._starting_date + timedelta(seconds=i), '%Y-%m-%d %H:%M:%S')) for i in self._all_times_steps[0]])
|
1099
|
+
self._step_num.Set([str(i) for i in self._all_times_steps[1]])
|
1100
|
+
|
734
1101
|
class WolfMapViewer(wx.Frame):
|
735
1102
|
"""
|
736
1103
|
Fenêtre de visualisation de données WOLF grâce aux WxWidgets
|
@@ -751,6 +1118,7 @@ class WolfMapViewer(wx.Frame):
|
|
751
1118
|
mytiles: list[Tiles]
|
752
1119
|
mypartsystems: list[Particle_system]
|
753
1120
|
myviewers3d:list[Wolf_Viewer3D]
|
1121
|
+
sim_explorers: dict[Wolfresults_2D:Sim_Explorer]
|
754
1122
|
|
755
1123
|
canvas: GLCanvas # canvas OpenGL
|
756
1124
|
context: GLContext # context OpenGL
|
@@ -1217,6 +1585,14 @@ class WolfMapViewer(wx.Frame):
|
|
1217
1585
|
# # print(msg)
|
1218
1586
|
# return 0
|
1219
1587
|
|
1588
|
+
@property
|
1589
|
+
def viewer_name(self):
|
1590
|
+
return self.GetTitle()
|
1591
|
+
|
1592
|
+
@viewer_name.setter
|
1593
|
+
def viewer_name(self, value):
|
1594
|
+
self.SetTitle(value)
|
1595
|
+
|
1220
1596
|
@property
|
1221
1597
|
def wxlogging(self):
|
1222
1598
|
return self._wxlogging
|
@@ -1442,6 +1818,10 @@ class WolfMapViewer(wx.Frame):
|
|
1442
1818
|
if self.menuwolf2d is None:
|
1443
1819
|
self.menuwolf2d = wx.Menu()
|
1444
1820
|
|
1821
|
+
self.menu2d_explore_results = self.menuwolf2d.Append(wx.ID_ANY, _("Explore time/index results"), _("Open a dialog to explore time/index results"))
|
1822
|
+
|
1823
|
+
self.menuwolf2d.AppendSeparator()
|
1824
|
+
|
1445
1825
|
self.menu2d_curentview = self.menuwolf2d.Append(wx.ID_ANY, _("Change current view"), _("Current view"))
|
1446
1826
|
self.menu2d_lastres = self.menuwolf2d.Append(wx.ID_ANY, _("Read last result"), _("Current view"))
|
1447
1827
|
self.menu2d_epsilon = self.menuwolf2d.Append(wx.ID_ANY, _("Set epsilon water depth"), _("Set the epsilon used in the mask"))
|
@@ -1454,11 +1834,11 @@ class WolfMapViewer(wx.Frame):
|
|
1454
1834
|
self.menuwolf2d.AppendSeparator()
|
1455
1835
|
|
1456
1836
|
self.menu2d_dangermap = self.menuwolf2d.Append(wx.ID_ANY, _("Danger map"), _("Compute the danger map"))
|
1457
|
-
self.menu2d_dangermaph = self.menuwolf2d.Append(wx.ID_ANY, _("Danger map - only h"), _("Compute the danger map"))
|
1837
|
+
self.menu2d_dangermaph = self.menuwolf2d.Append(wx.ID_ANY, _("Danger map - only h"), _("Compute the danger map - only waterdepth"))
|
1458
1838
|
|
1459
1839
|
self.menuwolf2d.AppendSeparator()
|
1460
1840
|
|
1461
|
-
self.menu2d_export_as = self.menuwolf2d.Append(wx.ID_ANY, _("Export results as..."), _("Export results as Geotif or
|
1841
|
+
self.menu2d_export_as = self.menuwolf2d.Append(wx.ID_ANY, _("Export results as..."), _("Export results as Geotif, Shapefile or Numpy arrays"))
|
1462
1842
|
|
1463
1843
|
self.menuwolf2d.AppendSeparator()
|
1464
1844
|
# Possible cache entries will be added after this separator
|
@@ -1651,6 +2031,41 @@ class WolfMapViewer(wx.Frame):
|
|
1651
2031
|
|
1652
2032
|
self.active_array.reset_plot()
|
1653
2033
|
|
2034
|
+
def _add_sim_explorer(self, which:Wolfresults_2D):
|
2035
|
+
""" Add a step chooser """
|
2036
|
+
|
2037
|
+
if which in self.sim_explorers:
|
2038
|
+
logging.warning(_('Step chooser already exists for this result'))
|
2039
|
+
self.sim_explorers[which].Show()
|
2040
|
+
self.sim_explorers[which].Raise()
|
2041
|
+
self.sim_explorers[which].SetFocus()
|
2042
|
+
self.sim_explorers[which].Center()
|
2043
|
+
return
|
2044
|
+
|
2045
|
+
self.sim_explorers[which] = Sim_Explorer(self, which.idx, self, which)
|
2046
|
+
self.sim_explorers[which]._set_all(which.current_result)
|
2047
|
+
|
2048
|
+
def _pop_sim_explorer(self, which:Wolfresults_2D):
|
2049
|
+
""" Pop a step chooser """
|
2050
|
+
|
2051
|
+
if which in self.sim_explorers:
|
2052
|
+
self.sim_explorers.pop(which)
|
2053
|
+
logging.debug(_('Pop step chooser for result {}'.format(which.idx)))
|
2054
|
+
else:
|
2055
|
+
logging.warning(_('No step chooser for this result'))
|
2056
|
+
|
2057
|
+
def _update_sim_explorer(self, which:Wolfresults_2D = None):
|
2058
|
+
|
2059
|
+
if which is None:
|
2060
|
+
if self.active_res2d is None:
|
2061
|
+
logging.warning(_('No active 2D result -- Please activate a 2D result first'))
|
2062
|
+
return
|
2063
|
+
|
2064
|
+
which = self.active_res2d
|
2065
|
+
|
2066
|
+
if which in self.sim_explorers:
|
2067
|
+
self.sim_explorers[which]._set_all(which.current_result)
|
2068
|
+
|
1654
2069
|
def Onmenuwolf2d(self, event: wx.MenuEvent):
|
1655
2070
|
|
1656
2071
|
id = event.GetId()
|
@@ -1670,6 +2085,13 @@ class WolfMapViewer(wx.Frame):
|
|
1670
2085
|
|
1671
2086
|
self.export_results_as()
|
1672
2087
|
|
2088
|
+
elif itemlabel == _("Explore time/index results"):
|
2089
|
+
if self.active_res2d is None:
|
2090
|
+
logging.warning(_('No active 2D result ! -- Please activate a 2D result first'))
|
2091
|
+
return
|
2092
|
+
|
2093
|
+
self._add_sim_explorer(self.active_res2d)
|
2094
|
+
|
1673
2095
|
elif itemlabel == _("Change current view"):
|
1674
2096
|
|
1675
2097
|
# Change view for results
|
@@ -2450,6 +2872,16 @@ class WolfMapViewer(wx.Frame):
|
|
2450
2872
|
else:
|
2451
2873
|
return config[ConfigurationKeys.TICKS_SIZE]
|
2452
2874
|
|
2875
|
+
@property
|
2876
|
+
def assembly_mode(self) -> str:
|
2877
|
+
""" Return the assembly mode from configs """
|
2878
|
+
|
2879
|
+
config = self.get_configuration()
|
2880
|
+
if config is None:
|
2881
|
+
return 'square'
|
2882
|
+
else:
|
2883
|
+
return config[ConfigurationKeys.ASSEMBLY_IMAGES]
|
2884
|
+
|
2453
2885
|
@property
|
2454
2886
|
def ticks_bounds(self) -> bool:
|
2455
2887
|
""" Return the ticks bounds from configs """
|
@@ -3041,7 +3473,12 @@ class WolfMapViewer(wx.Frame):
|
|
3041
3473
|
|
3042
3474
|
return myimage
|
3043
3475
|
|
3044
|
-
def save_canvasogl(self,
|
3476
|
+
def save_canvasogl(self,
|
3477
|
+
fn:str='',
|
3478
|
+
mpl:bool=True,
|
3479
|
+
ds:float=0.,
|
3480
|
+
dpi:int= 300,
|
3481
|
+
add_title:bool = False):
|
3045
3482
|
"""
|
3046
3483
|
Sauvegarde de la fenêtre d'affichage dans un fichier
|
3047
3484
|
|
@@ -3151,6 +3588,8 @@ class WolfMapViewer(wx.Frame):
|
|
3151
3588
|
|
3152
3589
|
# self.Paint()
|
3153
3590
|
|
3591
|
+
if add_title:
|
3592
|
+
ax.set_title(self.viewer_name)
|
3154
3593
|
fig.set_size_inches(12, 10)
|
3155
3594
|
fig.tight_layout()
|
3156
3595
|
|
@@ -3253,23 +3692,37 @@ class WolfMapViewer(wx.Frame):
|
|
3253
3692
|
self.mywmsfore = []
|
3254
3693
|
self.myres2D = []
|
3255
3694
|
self.myviewers3d = []
|
3695
|
+
self.sim_explorers = {}
|
3256
3696
|
|
3257
3697
|
# liste des éléments modifiable dans l'arbre
|
3258
3698
|
self.all_lists = [self.myarrays, self.myvectors, self.myclouds, self.mytri, self.myothers, self.myviews, self.myres2D, self.mytiles, self.mypartsystems, self.myviewers3d]
|
3259
3699
|
|
3700
|
+
self.menu_options = wx.Menu()
|
3701
|
+
self._change_title = self.menu_options.Append(wx.ID_ANY, _('Change title'), _('Change title of the window'))
|
3702
|
+
self.Bind(wx.EVT_MENU, self.OnChangeTitle, self._change_title)
|
3703
|
+
|
3260
3704
|
if self.get_configuration() is not None:
|
3261
3705
|
# see PyGui.py if necessary
|
3262
3706
|
|
3263
|
-
self.menu_options = wx.Menu()
|
3264
3707
|
self.menubar.Append(self.menu_options, _('Options'))
|
3265
3708
|
self.option_global = self.menu_options.Append(wx.ID_ANY,_("Global"),_("Modify global options"))
|
3266
3709
|
self.Bind(wx.EVT_MENU, self.GlobalOptionsDialog, self.option_global)
|
3267
3710
|
|
3268
|
-
|
3269
|
-
|
3711
|
+
self.menu_1to9 =self.menu_options.Append(wx.ID_ANY, _('Colors for selections 1->9'), _('Selections'))
|
3712
|
+
self.Bind(wx.EVT_MENU, self.colors1to9.change_colors, self.menu_1to9)
|
3270
3713
|
|
3271
3714
|
self.Show(True)
|
3272
3715
|
|
3716
|
+
def OnChangeTitle(self, e):
|
3717
|
+
"""
|
3718
|
+
Change the title of the window
|
3719
|
+
"""
|
3720
|
+
|
3721
|
+
dlg = wx.TextEntryDialog(None, _('Enter the new title'), _('Change title'), self.GetTitle())
|
3722
|
+
if dlg.ShowModal() == wx.ID_OK:
|
3723
|
+
self.SetTitle(dlg.GetValue())
|
3724
|
+
dlg.Destroy()
|
3725
|
+
|
3273
3726
|
def OnSize(self, e):
|
3274
3727
|
"""
|
3275
3728
|
Redimensionnement de la fenêtre
|
@@ -4645,6 +5098,8 @@ class WolfMapViewer(wx.Frame):
|
|
4645
5098
|
else:
|
4646
5099
|
return
|
4647
5100
|
|
5101
|
+
logging.info(_('This could take some time for large area...\n Take a coffee and relax!'))
|
5102
|
+
|
4648
5103
|
bounds = array.get_bounds()
|
4649
5104
|
|
4650
5105
|
# align bounds on chunk_size
|
@@ -4738,7 +5193,7 @@ class WolfMapViewer(wx.Frame):
|
|
4738
5193
|
array.reset_plot()
|
4739
5194
|
self.Paint()
|
4740
5195
|
|
4741
|
-
logging.info(_('Filling done'))
|
5196
|
+
logging.info(_('Filling done !'))
|
4742
5197
|
|
4743
5198
|
def count_active_array_from_laz(self, array:WolfArray = None, used_codes:list = [], chunk_size:float = 500.):
|
4744
5199
|
""" Fill active array with laz data
|
@@ -5005,6 +5460,7 @@ class WolfMapViewer(wx.Frame):
|
|
5005
5460
|
|
5006
5461
|
curmodel.read_oneresult()
|
5007
5462
|
curmodel.set_currentview()
|
5463
|
+
self._update_sim_explorer(curmodel)
|
5008
5464
|
|
5009
5465
|
self.Refresh()
|
5010
5466
|
self.currently_readresults = False
|
@@ -5023,6 +5479,8 @@ class WolfMapViewer(wx.Frame):
|
|
5023
5479
|
|
5024
5480
|
curmodel.read_oneresult(which)
|
5025
5481
|
curmodel.set_currentview()
|
5482
|
+
self._update_sim_explorer(curmodel)
|
5483
|
+
|
5026
5484
|
|
5027
5485
|
self.Refresh()
|
5028
5486
|
self.currently_readresults = False
|
@@ -5041,6 +5499,7 @@ class WolfMapViewer(wx.Frame):
|
|
5041
5499
|
|
5042
5500
|
curmodel.read_previous()
|
5043
5501
|
curmodel.set_currentview()
|
5502
|
+
self._update_sim_explorer(curmodel)
|
5044
5503
|
|
5045
5504
|
self.Refresh()
|
5046
5505
|
self.currently_readresults = False
|
@@ -5082,6 +5541,8 @@ class WolfMapViewer(wx.Frame):
|
|
5082
5541
|
|
5083
5542
|
curmodel.read_next()
|
5084
5543
|
curmodel.set_currentview()
|
5544
|
+
self._update_sim_explorer(curmodel)
|
5545
|
+
|
5085
5546
|
|
5086
5547
|
self.Refresh()
|
5087
5548
|
self.currently_readresults = False
|
@@ -5364,6 +5825,8 @@ class WolfMapViewer(wx.Frame):
|
|
5364
5825
|
linkedarrays = self.get_linked_arrays()
|
5365
5826
|
|
5366
5827
|
with wx.MultiChoiceDialog(None, _('Choose the arrays to plot'), _('Arrays'), [curarray for curarray in list(linkedarrays.keys())]) as dlg:
|
5828
|
+
dlg.SetSelections(range(len(linkedarrays)))
|
5829
|
+
|
5367
5830
|
if dlg.ShowModal() == wx.ID_CANCEL:
|
5368
5831
|
dlg.Destroy()
|
5369
5832
|
return
|
@@ -6094,9 +6557,9 @@ class WolfMapViewer(wx.Frame):
|
|
6094
6557
|
autoscale = False
|
6095
6558
|
|
6096
6559
|
fn, ds = self.save_canvasogl(mpl=True)
|
6097
|
-
all_images = self.save_linked_canvas(fn[:-4], mpl= True, ds= ds)
|
6098
6560
|
|
6099
|
-
self.
|
6561
|
+
all_images = self.save_linked_canvas(fn[:-4], mpl= True, ds= ds, add_title= True)
|
6562
|
+
self.assembly_images(all_images, mode= self.assembly_mode)
|
6100
6563
|
|
6101
6564
|
elif itemlabel == _('Copy image...'):
|
6102
6565
|
autoscale = False
|
@@ -6405,31 +6868,40 @@ class WolfMapViewer(wx.Frame):
|
|
6405
6868
|
|
6406
6869
|
logging.info(_('Filtering done !'))
|
6407
6870
|
|
6408
|
-
def export_results_as(self, which:Literal['geotiff','shape'] = None, multiband:bool = None):
|
6871
|
+
def export_results_as(self, which:Literal['geotiff','shape','numpy'] = None, multiband:bool = None):
|
6409
6872
|
"""
|
6410
|
-
Export des résultats WOLF2D vers
|
6411
|
-
|
6873
|
+
Export des résultats WOLF2D vers différents formats.
|
6874
|
+
Au moins un résultat doit être chargé pour pouvoir être exporté.
|
6412
6875
|
"""
|
6413
6876
|
|
6414
6877
|
dlg = wx.DirDialog(self,_('Choose output directory'), style = wx.DD_DIR_MUST_EXIST)
|
6415
6878
|
ret=dlg.ShowModal()
|
6416
6879
|
|
6417
6880
|
if ret == wx.ID_CANCEL:
|
6881
|
+
logging.warning(_('Abort!'))
|
6418
6882
|
dlg.Destroy()
|
6419
6883
|
return
|
6420
6884
|
|
6421
6885
|
outdir = dlg.GetPath()
|
6422
6886
|
dlg.Destroy()
|
6423
6887
|
|
6424
|
-
if which not in ['geotiff','shape']:
|
6425
|
-
dlg = wx.SingleChoiceDialog(self,_('Choose output format'), _('Format'), ['Geotiff','Shape file'])
|
6426
|
-
dlg.ShowModal()
|
6888
|
+
if which not in ['geotiff','shape','numpy']:
|
6889
|
+
dlg = wx.SingleChoiceDialog(self,_('Choose output format'), _('Format'), ['Geotiff','Shape file','Numpy array'])
|
6890
|
+
ret = dlg.ShowModal()
|
6891
|
+
|
6892
|
+
if ret == wx.ID_CANCEL:
|
6893
|
+
logging.warning(_('Abort!'))
|
6894
|
+
dlg.Destroy()
|
6895
|
+
return
|
6896
|
+
|
6427
6897
|
sel = dlg.GetSelection()
|
6428
6898
|
|
6429
6899
|
if sel == 0:
|
6430
6900
|
which = 'geotiff'
|
6431
|
-
|
6901
|
+
elif sel == 1:
|
6432
6902
|
which = 'shape'
|
6903
|
+
else:
|
6904
|
+
which = 'numpy'
|
6433
6905
|
|
6434
6906
|
dlg.Destroy()
|
6435
6907
|
|
@@ -6452,7 +6924,12 @@ class WolfMapViewer(wx.Frame):
|
|
6452
6924
|
|
6453
6925
|
dlg = wx.MultiChoiceDialog(self,_('Choose results to export'), _('Results'), choices=loaded_res)
|
6454
6926
|
dlg.SetSelections([idx for idx, res in enumerate(loaded_res) if self.get_obj_from_id(res, drawtype=draw_type.RES2D).plotted])
|
6455
|
-
dlg.ShowModal()
|
6927
|
+
ret = dlg.ShowModal()
|
6928
|
+
if ret == wx.ID_CANCEL:
|
6929
|
+
logging.warning(_('Abort!'))
|
6930
|
+
dlg.Destroy()
|
6931
|
+
return
|
6932
|
+
|
6456
6933
|
sel = dlg.GetSelections() # Get a list if integers
|
6457
6934
|
sel_res = [self.get_obj_from_id(loaded_res[cursel], drawtype=draw_type.RES2D) for cursel in sel] # convert to list of objects
|
6458
6935
|
|
@@ -6478,7 +6955,13 @@ class WolfMapViewer(wx.Frame):
|
|
6478
6955
|
|
6479
6956
|
dlg = wx.MultiChoiceDialog(self,_('Choose fields to export'), _('Fields'), choices= [str(field[0]) for field in fields])
|
6480
6957
|
dlg.SetSelections([idx for idx, field in enumerate(fields) if field[1]])
|
6481
|
-
dlg.ShowModal()
|
6958
|
+
ret = dlg.ShowModal()
|
6959
|
+
|
6960
|
+
if ret == wx.ID_CANCEL:
|
6961
|
+
logging.warning(_('Abort!'))
|
6962
|
+
dlg.Destroy()
|
6963
|
+
return
|
6964
|
+
|
6482
6965
|
sel_fields = dlg.GetSelections() # Get a list if integers
|
6483
6966
|
dlg.Destroy()
|
6484
6967
|
|
@@ -6666,13 +7149,20 @@ class WolfMapViewer(wx.Frame):
|
|
6666
7149
|
|
6667
7150
|
return linkedarrays
|
6668
7151
|
|
6669
|
-
def save_linked_canvas(self, fn, mpl=True, ds=0
|
6670
|
-
""" Save canvas of all linked viewers
|
7152
|
+
def save_linked_canvas(self, fn:str, mpl:bool= True, ds:float= 0., add_title:bool= True) -> tuple[(str, float), str]:
|
7153
|
+
""" Save canvas of all linked viewers
|
7154
|
+
|
7155
|
+
:param fn: filename without extension -- '.png' will be added
|
7156
|
+
:param mpl: save as matplotlib image
|
7157
|
+
:param ds: Ticks size for matplotlib image
|
7158
|
+
:return: list of tuple ((filename, ds), viewer_name)
|
7159
|
+
"""
|
6671
7160
|
|
7161
|
+
fn = str(fn)
|
6672
7162
|
ret = []
|
6673
7163
|
if self.linked:
|
6674
7164
|
for idx, curel in enumerate(self.linkedList):
|
6675
|
-
ret.append(curel.save_canvasogl(fn + '_' + str(idx) + '.png', mpl, ds))
|
7165
|
+
ret.append((curel.save_canvasogl(fn + '_' + str(idx) + '.png', mpl, ds, add_title= add_title), self.viewer_name))
|
6676
7166
|
|
6677
7167
|
return ret
|
6678
7168
|
|
@@ -6680,50 +7170,55 @@ class WolfMapViewer(wx.Frame):
|
|
6680
7170
|
""" Assembly images
|
6681
7171
|
|
6682
7172
|
Every image has the same size (width, height)
|
7173
|
+
|
7174
|
+
:param all_images: list of tuple (filename, viewer_name)
|
7175
|
+
:param mode: 'horizontal', 'vertical', 'square'
|
6683
7176
|
"""
|
6684
7177
|
|
7178
|
+
assert mode in ['horizontal', 'vertical', 'square', 0, 1, 2], 'Mode not recognized'
|
7179
|
+
|
6685
7180
|
from PIL import Image
|
6686
7181
|
|
6687
|
-
images = [Image.open(fn) for fn, ds in all_images]
|
7182
|
+
images = [Image.open(fn) for (fn, ds), viewername in all_images]
|
6688
7183
|
|
6689
7184
|
widths, heights = zip(*(i.size for i in images))
|
6690
7185
|
|
6691
|
-
if mode == 'horizontal':
|
7186
|
+
if mode == 'horizontal' or mode==0:
|
6692
7187
|
|
6693
7188
|
total_width = sum(widths)
|
6694
7189
|
max_height = max(heights)
|
6695
7190
|
|
6696
|
-
new_im = Image.new('RGB', (total_width, max_height))
|
7191
|
+
new_im = Image.new('RGB', (total_width, max_height), color=(255,255,255))
|
6697
7192
|
|
6698
7193
|
x_offset = 0
|
6699
7194
|
for im in images:
|
6700
7195
|
new_im.paste(im, (x_offset,0))
|
6701
7196
|
x_offset += im.size[0]
|
6702
7197
|
|
6703
|
-
new_im.save(all_images[0][0][:-4] + '_assembly.png')
|
7198
|
+
new_im.save(all_images[0][0][0][:-4] + '_assembly.png')
|
6704
7199
|
|
6705
|
-
elif mode == 'vertical':
|
7200
|
+
elif mode == 'vertical' or mode==1:
|
6706
7201
|
|
6707
7202
|
total_height = sum(heights)
|
6708
7203
|
max_width = max(widths)
|
6709
7204
|
|
6710
|
-
new_im = Image.new('RGB', (max_width, total_height))
|
7205
|
+
new_im = Image.new('RGB', (max_width, total_height), color=(255,255,255))
|
6711
7206
|
|
6712
7207
|
y_offset = 0
|
6713
7208
|
for im in images:
|
6714
7209
|
new_im.paste(im, (0, y_offset))
|
6715
7210
|
y_offset += im.size[1]
|
6716
7211
|
|
6717
|
-
new_im.save(all_images[0][0][:-4] + '_assembly.png')
|
7212
|
+
new_im.save(all_images[0][0][0][:-4] + '_assembly.png')
|
6718
7213
|
|
6719
|
-
elif mode == 'square':
|
7214
|
+
elif mode == 'square' or mode==2:
|
6720
7215
|
|
6721
7216
|
max_width = max(widths)
|
6722
7217
|
max_height = max(heights)
|
6723
7218
|
|
6724
7219
|
nb_hor = int(np.ceil(np.sqrt(len(images))))
|
6725
7220
|
|
6726
|
-
new_im = Image.new('RGB', (max_width*nb_hor, max_height*nb_hor))
|
7221
|
+
new_im = Image.new('RGB', (max_width*nb_hor, max_height*nb_hor), color=(255,255,255))
|
6727
7222
|
|
6728
7223
|
x_offset = 0
|
6729
7224
|
y_offset = 0
|
@@ -6734,7 +7229,9 @@ class WolfMapViewer(wx.Frame):
|
|
6734
7229
|
y_offset += im.size[1]
|
6735
7230
|
x_offset = 0
|
6736
7231
|
|
6737
|
-
new_im.save(all_images[0][0][:-4] + '_assembly.png')
|
7232
|
+
new_im.save(all_images[0][0][0][:-4] + '_assembly.png')
|
7233
|
+
|
7234
|
+
return new_im
|
6738
7235
|
|
6739
7236
|
def thread_update_blender(self):
|
6740
7237
|
print("Update blender")
|
@@ -9380,7 +9877,7 @@ class WolfMapViewer(wx.Frame):
|
|
9380
9877
|
# \n \
|
9381
9878
|
# CTRL+Q : Quit application\n \
|
9382
9879
|
# CTRL+U : Import GLTF/GLB\n \
|
9383
|
-
# CTRL+C : Set copy source
|
9880
|
+
# CTRL+C : Set copy source\n \
|
9384
9881
|
# CTRL+V : Paste selected values\n \
|
9385
9882
|
# CTRL+ALT+V ou ALTGr+V : Paste/Recopy selection\n \
|
9386
9883
|
# CTRL+L : chargement d'une matrice sur base du nom de fichier de la tile\n \
|
@@ -9416,7 +9913,8 @@ class WolfMapViewer(wx.Frame):
|
|
9416
9913
|
'F7': _('Drawing : refresh'),
|
9417
9914
|
'Arrows': _('Drawing : lateral movements'),
|
9418
9915
|
'c or C': _('Drawing : copy canvas to Clipboard wo axes'),
|
9419
|
-
'
|
9916
|
+
'ALT+C': _('Drawing : copy canvas to Clipboard as Matplotlib image'),
|
9917
|
+
'ALT+SHIFT+C': _('Drawing : copy canvas to Clipboard as Matplotlib image with axes - linked arrays'),
|
9420
9918
|
|
9421
9919
|
'CTRL+o': _('Results : increase transparency of the current result'),
|
9422
9920
|
'CTRL+O': _('Results : decrease transparency of the current result'),
|
@@ -9542,7 +10040,25 @@ class WolfMapViewer(wx.Frame):
|
|
9542
10040
|
logging.debug(_('Alt is down'))
|
9543
10041
|
|
9544
10042
|
if ctrldown or altdown:
|
9545
|
-
if key ==
|
10043
|
+
if key == 60 and shiftdown: #'>'
|
10044
|
+
if self.active_array is not None:
|
10045
|
+
if self.active_array.SelectionData is not None:
|
10046
|
+
self.active_array.SelectionData.dilate_contour_selection(1)
|
10047
|
+
self.active_array.reset_plot()
|
10048
|
+
elif key == 60 and not shiftdown: #'<'
|
10049
|
+
if self.active_array is not None:
|
10050
|
+
if self.active_array.SelectionData is not None:
|
10051
|
+
self.active_array.SelectionData.erode_contour_selection()
|
10052
|
+
self.active_array.reset_plot()
|
10053
|
+
|
10054
|
+
elif key == wx.WXK_F2 and ctrldown and altdown and shiftdown:
|
10055
|
+
|
10056
|
+
if self.active_res2d is None:
|
10057
|
+
logging.info(_('Please activate a simulation before search a specific result'))
|
10058
|
+
|
10059
|
+
self._add_sim_explorer(self.active_res2d)
|
10060
|
+
|
10061
|
+
elif key == wx.WXK_F2 and not shiftdown:
|
9546
10062
|
|
9547
10063
|
if self.active_res2d is not None:
|
9548
10064
|
nb = self.active_res2d.get_nbresults()
|
@@ -9556,20 +10072,11 @@ class WolfMapViewer(wx.Frame):
|
|
9556
10072
|
self.active_res2d.set_currentview()
|
9557
10073
|
self.Refresh()
|
9558
10074
|
|
10075
|
+
self._update_sim_explorer()
|
10076
|
+
|
9559
10077
|
else:
|
9560
10078
|
logging.info(_('Please activate a simulation before search a specific result'))
|
9561
10079
|
|
9562
|
-
elif key == 60 and shiftdown: #'>'
|
9563
|
-
if self.active_array is not None:
|
9564
|
-
if self.active_array.SelectionData is not None:
|
9565
|
-
self.active_array.SelectionData.dilate_contour_selection(1)
|
9566
|
-
self.active_array.reset_plot()
|
9567
|
-
elif key == 60 and not shiftdown: #'<'
|
9568
|
-
if self.active_array is not None:
|
9569
|
-
if self.active_array.SelectionData is not None:
|
9570
|
-
self.active_array.SelectionData.erode_contour_selection()
|
9571
|
-
self.active_array.reset_plot()
|
9572
|
-
|
9573
10080
|
elif key == wx.WXK_F2 and shiftdown:
|
9574
10081
|
|
9575
10082
|
if self.active_res2d is not None:
|
@@ -9595,6 +10102,8 @@ class WolfMapViewer(wx.Frame):
|
|
9595
10102
|
self.active_res2d.set_currentview()
|
9596
10103
|
self.Refresh()
|
9597
10104
|
|
10105
|
+
self._update_sim_explorer()
|
10106
|
+
|
9598
10107
|
else:
|
9599
10108
|
logging.info(_('Please activate a simulation before searching a specific result'))
|
9600
10109
|
|
@@ -9612,6 +10121,7 @@ class WolfMapViewer(wx.Frame):
|
|
9612
10121
|
self.active_particle_system.current_step = nb-1
|
9613
10122
|
self.Refresh()
|
9614
10123
|
self._update_mytooltip()
|
10124
|
+
self._update_sim_explorer()
|
9615
10125
|
|
9616
10126
|
else:
|
9617
10127
|
logging.info(_('Please activate a particle system before searching a specific result'))
|
@@ -9639,6 +10149,7 @@ class WolfMapViewer(wx.Frame):
|
|
9639
10149
|
self.active_particle_system.current_step = choices.index(keyvalue)
|
9640
10150
|
self.Refresh()
|
9641
10151
|
self._update_mytooltip()
|
10152
|
+
self._update_sim_explorer()
|
9642
10153
|
|
9643
10154
|
else:
|
9644
10155
|
logging.info(_('Please activate a simulation before search a specific result'))
|
@@ -9707,11 +10218,45 @@ class WolfMapViewer(wx.Frame):
|
|
9707
10218
|
elif key == wx.WXK_DOWN:
|
9708
10219
|
self.downobj()
|
9709
10220
|
|
9710
|
-
elif key == ord('C') and altdown and not ctrldown:
|
10221
|
+
elif key == ord('C') and altdown and not ctrldown and not shiftdown:
|
9711
10222
|
# ALT+C
|
9712
10223
|
#Copie du canvas dans le clipboard pour transfert vers autre application
|
9713
10224
|
self.copy_canvasogl()
|
9714
10225
|
|
10226
|
+
elif key == ord('C') and altdown and not ctrldown and shiftdown:
|
10227
|
+
# ALT+SHIFT+C
|
10228
|
+
# Copie du canvas dans le clipboard pour transfert vers autre application
|
10229
|
+
# Copie des canvas liés
|
10230
|
+
|
10231
|
+
from tempfile import TemporaryDirectory
|
10232
|
+
|
10233
|
+
logging.info(_('Creating images'))
|
10234
|
+
|
10235
|
+
with TemporaryDirectory() as tmpdirname:
|
10236
|
+
all_images = self.save_linked_canvas(Path(tmpdirname) / 'fig', mpl= True, ds= self.ticks_size, add_title= True)
|
10237
|
+
im_assembly = self.assembly_images(all_images, mode= self.assembly_mode)
|
10238
|
+
|
10239
|
+
logging.info(_('Creating images - done'))
|
10240
|
+
|
10241
|
+
# Copy image to clipboard
|
10242
|
+
if im_assembly is not None:
|
10243
|
+
if wx.TheClipboard.Open():
|
10244
|
+
|
10245
|
+
#création d'un objet bitmap wx
|
10246
|
+
wxbitmap = wx.Bitmap().FromBuffer(im_assembly.width, im_assembly.height, im_assembly.tobytes())
|
10247
|
+
|
10248
|
+
# objet wx exportable via le clipboard
|
10249
|
+
dataobj = wx.BitmapDataObject()
|
10250
|
+
dataobj.SetBitmap(wxbitmap)
|
10251
|
+
|
10252
|
+
wx.TheClipboard.SetData(dataobj)
|
10253
|
+
wx.TheClipboard.Close()
|
10254
|
+
logging.info(_('Image copied to clipboard'))
|
10255
|
+
else:
|
10256
|
+
logging.error(_('Cannot open the clipboard'))
|
10257
|
+
else:
|
10258
|
+
logging.error(_('No image to copy to clipboard'))
|
10259
|
+
|
9715
10260
|
elif key == ord('C') and ctrldown and not altdown:
|
9716
10261
|
# CTRL+C
|
9717
10262
|
if self.active_array is None:
|
@@ -9975,7 +10520,13 @@ class WolfMapViewer(wx.Frame):
|
|
9975
10520
|
self.active_array.myops.select_node_by_node()
|
9976
10521
|
|
9977
10522
|
if self.active_res2d is not None:
|
9978
|
-
self.
|
10523
|
+
if self.active_array is not None:
|
10524
|
+
msg = wx.MessageDialog(None, _('Do you want to select the nodes of the active result ?'), _('Select nodes'), wx.YES_NO | wx.ICON_QUESTION)
|
10525
|
+
ret = msg.ShowModal()
|
10526
|
+
if ret == wx.ID_YES:
|
10527
|
+
self.active_res2d.properties.select_node_by_node()
|
10528
|
+
else:
|
10529
|
+
self.active_res2d.properties.select_node_by_node()
|
9979
10530
|
|
9980
10531
|
if self.active_array is None and self.active_res2d is None:
|
9981
10532
|
logging.warning(_('No active array or result 2D to select node by node !'))
|