Skip to content

Commit 6a21beb

Browse files
committed
GUI: introducing tabs for file explorer and 2d field (#19 #62)
1 parent 7899245 commit 6a21beb

File tree

6 files changed

+305
-102
lines changed

6 files changed

+305
-102
lines changed

pydatview/GUIFields1D.py

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
"""
2+
"""
3+
import wx
4+
from pydatview.GUIPlotPanel import PlotPanel
5+
from pydatview.GUIInfoPanel import InfoPanel
6+
from pydatview.GUISelectionPanel import SelectionPanel, SEL_MODES_ID
7+
# from pydatview.GUISelectionPanel import SelectionPanel,SEL_MODES,SEL_MODES_ID
8+
# from pydatview.GUISelectionPanel import ColumnPopup,TablePopup
9+
# from pydatview.GUIPipelinePanel import PipelinePanel
10+
# from pydatview.GUIToolBox import GetKeyString, TBAddTool
11+
# from pydatview.Tables import TableList, Table
12+
13+
14+
SIDE_COL = [160,160,300,420,530]
15+
SIDE_COL_LARGE = [200,200,360,480,600]
16+
BOT_PANL =85
17+
18+
class Fields1DPanel(wx.SplitterWindow): # TODO Panel
19+
20+
def __init__(self, parent, mainframe):
21+
# Superclass constructor
22+
super(Fields1DPanel, self).__init__(parent)
23+
# Data
24+
self.parent = parent
25+
self.mainframe = mainframe
26+
27+
self.vSplitter = self # Backward compatibility
28+
29+
# --- Create a selPanel, plotPanel and infoPanel
30+
mode = SEL_MODES_ID[mainframe.comboMode.GetSelection()]
31+
self.selPanel = SelectionPanel(self.vSplitter, mainframe.tabList, mode=mode, mainframe=mainframe)
32+
self.tSplitter = wx.SplitterWindow(self.vSplitter)
33+
#self.tSplitter.SetMinimumPaneSize(20)
34+
self.infoPanel = InfoPanel(self.tSplitter, data=mainframe.data['infoPanel'])
35+
self.plotPanel = PlotPanel(self.tSplitter, self.selPanel, infoPanel=self.infoPanel, pipeLike=mainframe.pipePanel, data=mainframe.data['plotPanel'])
36+
self.livePlotFreezeUnfreeze() # Dont enable panels if livePlot is not allowed
37+
self.tSplitter.SetSashGravity(0.9)
38+
self.tSplitter.SplitHorizontally(self.plotPanel, self.infoPanel)
39+
self.tSplitter.SetMinimumPaneSize(BOT_PANL)
40+
self.tSplitter.SetSashGravity(1)
41+
self.tSplitter.SetSashPosition(400)
42+
43+
self.vSplitter.SplitVertically(self.selPanel, self.tSplitter)
44+
self.vSplitter.SetMinimumPaneSize(SIDE_COL[0])
45+
self.tSplitter.SetSashPosition(SIDE_COL[0])
46+
47+
48+
# --- Bind
49+
# The selPanel does the binding, but the callback is stored here because it involves plotPanel... TODO, rethink it
50+
#self.selPanel.bindColSelectionChange(self.onColSelectionChangeCallBack)
51+
self.selPanel.setTabSelectionChangeCallback(mainframe.onTabSelectionChangeTrigger)
52+
self.selPanel.setRedrawCallback(mainframe.redrawCallback)
53+
self.selPanel.setUpdateLayoutCallback(mainframe.mainFrameUpdateLayout)
54+
self.plotPanel.setAddTablesCallback(mainframe.load_dfs)
55+
56+
self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, mainframe.onSashChangeMain, self.vSplitter)
57+
58+
# --- Mainframe backward compatibility
59+
mainframe.selPanel = self.selPanel
60+
mainframe.plotPanel = self.plotPanel
61+
mainframe.infoPanel = self.infoPanel
62+
63+
64+
def updateSashLayout(self, event=None):
65+
# try:
66+
nWind = self.selPanel.splitter.nWindows
67+
if self.Size[0]<=800:
68+
sash=SIDE_COL[nWind]
69+
else:
70+
sash=SIDE_COL_LARGE[nWind]
71+
self.resizeSideColumn(sash)
72+
# except:
73+
# print('[Fail] An error occured in mainFrameUpdateLayout')
74+
75+
76+
# --- Side column
77+
def resizeSideColumn(self,width):
78+
# To force the replot we do an epic unsplit/split...
79+
#self.vSplitter.Unsplit()
80+
#self.vSplitter.SplitVertically(self.selPanel, self.tSplitter)
81+
self.vSplitter.SetMinimumPaneSize(width)
82+
self.vSplitter.SetSashPosition(width)
83+
#self.selPanel.splitter.setEquiSash()
84+
85+
def livePlotFreezeUnfreeze(self):
86+
pass
87+
#if self.cbLivePlot.IsChecked():
88+
# if hasattr(self,'plotPanel'):
89+
# #print('[INFO] Enabling live plot')
90+
# #self.plotPanel.Enable(True)
91+
# self.infoPanel.Enable(True)
92+
#else:
93+
# if hasattr(self,'plotPanel'):
94+
# #print('[INFO] Disabling live plot')
95+
# #self.plotPanel.Enable(False)
96+
# self.infoPanel.Enable(False)
97+

pydatview/GUIFields2D.py

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
"""
2+
"""
3+
import os
4+
import numpy as np
5+
import wx
6+
from wx.lib.splitter import MultiSplitterWindow
7+
import matplotlib.pyplot as plt
8+
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
9+
# Local
10+
from pydatview.common import ellude_common
11+
12+
class Fields2DPanel(wx.Panel):
13+
def __init__(self, parent, mainframe):
14+
wx.Panel.__init__(self, parent)
15+
# Data
16+
self.parent = parent
17+
self.mainframe = mainframe
18+
self.fileobjects = None
19+
20+
multi_split = MultiSplitterWindow(self)
21+
self.files_panel = wx.Panel(multi_split)
22+
self.fields_panel = wx.Panel(multi_split)
23+
self.canvas_panel = wx.Panel(multi_split)
24+
25+
self.lbFiles = wx.ListBox(self.files_panel, style=wx.LB_SINGLE)
26+
self.lbFiles.Bind(wx.EVT_LISTBOX, self.on_file_selected)
27+
28+
sizer_files = wx.BoxSizer(wx.VERTICAL)
29+
sizer_files.Add(self.lbFiles, 1, wx.EXPAND | wx.ALL, 5)
30+
self.files_panel.SetSizer(sizer_files)
31+
32+
self.lbFields = wx.ListBox(self.fields_panel, style=wx.LB_SINGLE)
33+
self.lbFields.Bind(wx.EVT_LISTBOX, self.on_2d_field_selected)
34+
35+
sizer_fields = wx.BoxSizer(wx.VERTICAL)
36+
sizer_fields.Add(self.lbFields, 1, wx.EXPAND | wx.ALL, 5)
37+
self.fields_panel.SetSizer(sizer_fields)
38+
39+
self.canvas = FigureCanvas(self.canvas_panel, -1, plt.figure())
40+
sizer_canvas = wx.BoxSizer(wx.HORIZONTAL)
41+
sizer_canvas.Add(self.canvas, 1, wx.EXPAND | wx.ALL, 5)
42+
self.canvas_panel.SetSizer(sizer_canvas)
43+
44+
multi_split.AppendWindow(self.files_panel, 200)
45+
multi_split.AppendWindow(self.fields_panel, 200)
46+
multi_split.AppendWindow(self.canvas_panel)
47+
48+
sizer = wx.BoxSizer(wx.VERTICAL)
49+
sizer.Add(multi_split, 1, wx.EXPAND)
50+
self.SetSizer(sizer)
51+
52+
def updateFiles(self, filenames, fileobjects):
53+
self.fileobjects=fileobjects
54+
filenames = [os.path.abspath(f).replace('/','|').replace('\\','|') for f in filenames]
55+
filenames = ellude_common(filenames)
56+
self.lbFiles.Set(filenames)
57+
58+
59+
def on_file_selected(self, event):
60+
selected_file = self.lbFiles.GetStringSelection()
61+
# Assume get_2d_fields_list() is a function that returns a list of 2D fields in the file
62+
fields_list = get_2d_fields_list(selected_file)
63+
self.lbFields.Set(fields_list)
64+
65+
def on_2d_field_selected(self, event):
66+
selected_field = self.lbFields.GetStringSelection()
67+
plot_selected_2d_field(selected_field)
68+
69+
70+
def generate_random_2d_field(shape=(30, 40)):
71+
return np.random.rand(*shape)
72+
73+
def get_2d_fields_list(file_path):
74+
# In this example, return a list of 2D fields and add "field_random"
75+
return ["field1", "field2", "field_random"]
76+
77+
def get_2d_field_data(field_name):
78+
# Placeholder for getting the data for the selected 2D field
79+
# You might want to implement this based on your actual data source
80+
pass
81+
82+
def plot_selected_2d_field(field_name):
83+
if field_name == "field_random":
84+
field_data = generate_random_2d_field()
85+
else:
86+
# Assume get_2d_field_data() is a function that returns the data for the selected 2D field
87+
field_data = get_2d_field_data(field_name)
88+
89+
# Clear previous plot
90+
plt.clf()
91+
92+
# Plot the 2D field on the canvas using contourf
93+
plt.contourf(field_data)
94+
plt.title(f"2D Field: {field_name}")
95+
96+
# Update the canvas
97+
plt.draw()

pydatview/GUIFileInfo.py

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"""
2+
3+
"""
4+
import os
5+
import wx
6+
from wx.lib.splitter import MultiSplitterWindow
7+
# Local
8+
import pydatview.io as weio # File Formats and File Readers
9+
from pydatview.common import ellude_common
10+
11+
class FileInfoPanel(wx.Panel):
12+
13+
def __init__(self, parent, mainframe, filelist=None):
14+
wx.Panel.__init__(self, parent)
15+
# Data
16+
self.parent = parent
17+
self.mainframe = mainframe
18+
self.fileobjects = None
19+
# GUI
20+
multi_split = MultiSplitterWindow(self)
21+
self.list_panel = wx.Panel(multi_split)
22+
self.text_panel = wx.Panel(multi_split)
23+
24+
self.lbFiles = wx.ListBox(self.list_panel, style=wx.LB_SINGLE)
25+
self.lbFiles.Bind(wx.EVT_LISTBOX, self.on_file_selected)
26+
27+
sizer_list = wx.BoxSizer(wx.VERTICAL)
28+
sizer_list.Add(self.lbFiles, 1, wx.EXPAND | wx.ALL, 5)
29+
self.list_panel.SetSizer(sizer_list)
30+
31+
self.tb = wx.TextCtrl(self.text_panel, style=wx.TE_MULTILINE | wx.TE_READONLY)
32+
sizer_text = wx.BoxSizer(wx.HORIZONTAL)
33+
sizer_text.Add(self.tb, 1, wx.EXPAND | wx.ALL, 5)
34+
self.text_panel.SetSizer(sizer_text)
35+
36+
multi_split.AppendWindow(self.list_panel, 200)
37+
multi_split.AppendWindow(self.text_panel)
38+
39+
sizer = wx.BoxSizer(wx.VERTICAL)
40+
sizer.Add(multi_split, 1, wx.EXPAND)
41+
self.SetSizer(sizer)
42+
43+
def updateFiles(self, filenames, fileobjects):
44+
self.fileobjects = fileobjects
45+
filenames = [os.path.abspath(f).replace('/','|').replace('\\','|') for f in filenames]
46+
filenames = ellude_common(filenames)
47+
self.lbFiles.Set(filenames)
48+
49+
def on_file_selected(self, event):
50+
isel = self.lbFiles.GetSelection()
51+
content = self.fileobjects[isel].__repr__()
52+
self.tb.SetValue(content)

pydatview/Tables.py

+18-3
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,11 @@ def _load_file_tabs(self, filename, fileformat=None, bReload=False):
167167
pass
168168
elif not isinstance(dfs,dict):
169169
if len(dfs)>0:
170-
tabs=[Table(data=dfs, filename=filename, fileformat=fileformat, dayfirst=self.options['dayfirst'])]
170+
tabs=[Table(data=dfs, filename=filename, fileformat=fileformat, dayfirst=self.options['dayfirst'], fileobject=F)]
171171
else:
172172
for k in list(dfs.keys()):
173173
if len(dfs[k])>0:
174-
tabs.append(Table(data=dfs[k], name=str(k), filename=filename, fileformat=fileformat, dayfirst=self.options['dayfirst']))
174+
tabs.append(Table(data=dfs[k], name=str(k), filename=filename, fileformat=fileformat, dayfirst=self.options['dayfirst'], fileobject=F))
175175
if len(tabs)<=0:
176176
warn='Warn: No dataframe found in file: '+filename+'\n'
177177
return tabs, warn
@@ -349,6 +349,20 @@ def tabNames(self):
349349
def filenames(self):
350350
return [t.filename for t in self._tabs]
351351

352+
@property
353+
def fileobjects(self):
354+
return [t.fileobject for t in self._tabs]
355+
356+
@property
357+
def unique_fileobjects(self):
358+
unique_list = []
359+
for x in self.fileobjects:
360+
if x not in unique_list and x is not None:
361+
unique_list.append(x)
362+
return unique_list
363+
364+
365+
352366
@property
353367
def fileformats(self):
354368
return [t.fileformat for t in self._tabs]
@@ -517,9 +531,10 @@ class Table(object):
517531
# active_name :
518532
# raw_name :
519533
# filename :
520-
def __init__(self, data=None, name='', filename='', fileformat=None, dayfirst=False):
534+
def __init__(self, data=None, name='', filename='', fileformat=None, dayfirst=False, fileobject=None):
521535
# Default init
522536
self.maskString=''
537+
self.fileobject = fileobject
523538
self.mask=None
524539
self.columns_pre_transpose = None
525540

pydatview/common.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def find_leftstop(s):
7373
return s[:len(s)-i]
7474
return s
7575

76-
def ellude_common(strings,minLength=2):
76+
def ellude_common(strings, minLength=2, sep='|'):
7777
"""
7878
ellude the common parts of two strings
7979
@@ -87,7 +87,7 @@ def ellude_common(strings,minLength=2):
8787
if len(S)==0:
8888
pass
8989
elif len(S)==1:
90-
ns=S[0].rfind('|')+1
90+
ns=S[0].rfind(sep)+1
9191
ne=0;
9292
else:
9393
ss = common_start(S)

0 commit comments

Comments
 (0)