-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #191 from ebranlard/dev
Version 0.5 - Merging dev to main
- Loading branch information
Showing
58 changed files
with
4,648 additions
and
1,880 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
openpyxl | ||
numpy | ||
pandas | ||
xarray | ||
pyarrow # for parquet files | ||
matplotlib | ||
chardet | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
""" | ||
TODO come up with some decent sepcs. Potentially use pandas or xarray | ||
""" | ||
import numpy as np | ||
|
||
def extract2Dfields(fo, force=False, **kwargs): | ||
if not hasattr(fo, 'fields2D_tmp') or force: | ||
fo.fields2D_tmp = None | ||
#print('[INFO] Attempting to extract 2D field for file {}'.format(fo.filename)) | ||
if not hasattr(fo, 'to2DFields'): | ||
print('[WARN] type {} does not have a `to2DFields` method'.format(type(fo))) | ||
return None | ||
try: | ||
fields = fo.to2DFields(**kwargs) | ||
except: | ||
print('[FAIL] Attempting to extract 2D field for file {}'.format(fo.filename)) | ||
return None | ||
if fields is None: | ||
print('[WARN] type {} has a `to2DFields` method but returned None'.format(type(fo))) | ||
return None | ||
# Convert to pydatview datatype for 2d fields | ||
fo.fields2D_tmp = Fields2D(fields) | ||
fo.fields2D_tmp.keys() | ||
print('[ OK ] 2D field computed successfully') | ||
else: | ||
print('[INFO] 2D field already computed for file {}'.format(fo.filename)) | ||
if not isinstance(fo.fields2D_tmp, Fields2D): | ||
raise Exception('ImplementationError') | ||
|
||
return fo.fields2D_tmp | ||
|
||
|
||
class Fields2D(): | ||
""" | ||
Fields2D is a list of xarray, readonly | ||
""" | ||
def __init__(self, ds=None): | ||
if ds is None: | ||
ds = [] | ||
self.ds = ds | ||
self._keys = None | ||
|
||
def __repr__(self): | ||
s='<{} object>:\n'.format(type(self).__name__) | ||
s+='|Main attributes:\n' | ||
s+='| - ds: {}\n'.format(self.ds) | ||
s+='| - _keys: {}\n'.format(self._keys) | ||
return s | ||
|
||
def keys(self): | ||
if self._keys is not None: | ||
return self._keys | ||
keys =[] | ||
variables = self.ds.variables | ||
# Filter variables based on dimensions (r, t) | ||
dims = np.unique(np.array([self.ds[var].dims for var in variables], dtype=object)) | ||
dims2d = [d for d in dims if len(d)==2] | ||
for D in dims2d: | ||
for var in variables: | ||
if self.ds[var].dims==(D[0],D[1]): | ||
keys.append(var) | ||
self._keys = keys | ||
return keys | ||
|
||
def loc(self, svar): | ||
try: | ||
i1, i2 = self.ds[svar].dims | ||
except: | ||
raise IndexError('Variable {} not found in field'.format(svar)) | ||
sx = i1 | ||
sy = i2 | ||
if 'unit' in self.ds[i1].attrs.keys(): | ||
sx += ' ['+ self.ds[i1].attrs['unit'] + ']' | ||
if 'unit' in self.ds[i2].attrs.keys(): | ||
sy += ' ['+ self.ds[i2].attrs['unit'] + ']' | ||
fieldname = svar | ||
if 'unit' in self.ds[svar].attrs.keys(): | ||
fieldname += ' ['+ self.ds[svar].attrs['unit'] + ']' | ||
return {'M': self.ds[svar].values, 'x':self.ds[i1].values, 'y':self.ds[i2].values, 'sx':sx, 'sy':sy, 'fieldname':fieldname} | ||
|
||
def iloc(self, i): | ||
var = self._keys[i] | ||
return self.loc(var) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
""" | ||
""" | ||
import wx | ||
from pydatview.GUIPlotPanel import PlotPanel | ||
from pydatview.GUIInfoPanel import InfoPanel | ||
from pydatview.GUISelectionPanel import SelectionPanel, SEL_MODES_ID | ||
# from pydatview.GUISelectionPanel import SelectionPanel,SEL_MODES,SEL_MODES_ID | ||
# from pydatview.GUISelectionPanel import ColumnPopup,TablePopup | ||
# from pydatview.GUIPipelinePanel import PipelinePanel | ||
# from pydatview.GUIToolBox import GetKeyString, TBAddTool | ||
# from pydatview.Tables import TableList, Table | ||
|
||
|
||
SIDE_COL = [160,160,300,420,530] | ||
SIDE_COL_LARGE = [200,200,360,480,600] | ||
BOT_PANL =85 | ||
|
||
class Fields1DPanel(wx.SplitterWindow): # TODO Panel | ||
|
||
def __init__(self, parent, mainframe): | ||
# Superclass constructor | ||
super(Fields1DPanel, self).__init__(parent) | ||
# Data | ||
self.parent = parent | ||
self.mainframe = mainframe | ||
|
||
self.vSplitter = self # Backward compatibility | ||
|
||
# --- Create a selPanel, plotPanel and infoPanel | ||
mode = SEL_MODES_ID[mainframe.comboMode.GetSelection()] | ||
self.selPanel = SelectionPanel(self.vSplitter, mainframe.tabList, mode=mode, mainframe=mainframe) | ||
self.tSplitter = wx.SplitterWindow(self.vSplitter) | ||
#self.tSplitter.SetMinimumPaneSize(20) | ||
self.infoPanel = InfoPanel(self.tSplitter, data=mainframe.data['infoPanel']) | ||
self.plotPanel = PlotPanel(self.tSplitter, self.selPanel, infoPanel=self.infoPanel, pipeLike=mainframe.pipePanel, data=mainframe.data['plotPanel']) | ||
self.livePlotFreezeUnfreeze() # Dont enable panels if livePlot is not allowed | ||
self.tSplitter.SetSashGravity(0.9) | ||
self.tSplitter.SplitHorizontally(self.plotPanel, self.infoPanel) | ||
self.tSplitter.SetMinimumPaneSize(BOT_PANL) | ||
self.tSplitter.SetSashGravity(1) | ||
self.tSplitter.SetSashPosition(400) | ||
|
||
self.vSplitter.SplitVertically(self.selPanel, self.tSplitter) | ||
self.vSplitter.SetMinimumPaneSize(SIDE_COL[0]) | ||
self.tSplitter.SetSashPosition(SIDE_COL[0]) | ||
|
||
|
||
# --- Bind | ||
# The selPanel does the binding, but the callback is stored here because it involves plotPanel... TODO, rethink it | ||
#self.selPanel.bindColSelectionChange(self.onColSelectionChangeCallBack) | ||
self.selPanel.setTabSelectionChangeCallback(mainframe.onTabSelectionChangeTrigger) | ||
self.selPanel.setRedrawCallback(mainframe.redrawCallback) | ||
self.selPanel.setUpdateLayoutCallback(mainframe.mainFrameUpdateLayout) | ||
self.plotPanel.setAddTablesCallback(mainframe.load_dfs) | ||
|
||
self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, mainframe.onSashChangeMain, self.vSplitter) | ||
|
||
# --- Mainframe backward compatibility | ||
mainframe.selPanel = self.selPanel | ||
mainframe.plotPanel = self.plotPanel | ||
mainframe.infoPanel = self.infoPanel | ||
|
||
|
||
def updateSashLayout(self, event=None): | ||
# try: | ||
nWind = self.selPanel.splitter.nWindows | ||
if self.Size[0]<=800: | ||
sash=SIDE_COL[nWind] | ||
else: | ||
sash=SIDE_COL_LARGE[nWind] | ||
self.resizeSideColumn(sash) | ||
# except: | ||
# print('[Fail] An error occured in mainFrameUpdateLayout') | ||
|
||
|
||
# --- Side column | ||
def resizeSideColumn(self,width): | ||
# To force the replot we do an epic unsplit/split... | ||
#self.vSplitter.Unsplit() | ||
#self.vSplitter.SplitVertically(self.selPanel, self.tSplitter) | ||
self.vSplitter.SetMinimumPaneSize(width) | ||
self.vSplitter.SetSashPosition(width) | ||
#self.selPanel.splitter.setEquiSash() | ||
|
||
def livePlotFreezeUnfreeze(self): | ||
pass | ||
#if self.cbLivePlot.IsChecked(): | ||
# if hasattr(self,'plotPanel'): | ||
# #print('[INFO] Enabling live plot') | ||
# #self.plotPanel.Enable(True) | ||
# self.infoPanel.Enable(True) | ||
#else: | ||
# if hasattr(self,'plotPanel'): | ||
# #print('[INFO] Disabling live plot') | ||
# #self.plotPanel.Enable(False) | ||
# self.infoPanel.Enable(False) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
""" | ||
""" | ||
import os | ||
import numpy as np | ||
import wx | ||
from wx.lib.splitter import MultiSplitterWindow | ||
# Local | ||
from pydatview.common import ellude_common | ||
from pydatview.common import CHAR | ||
from pydatview.GUICommon import getMonoFont | ||
from pydatview.Fields2D import extract2Dfields | ||
from pydatview.GUIPlot2DPanel import Plot2DPanel | ||
|
||
# --------------------------------------------------------------------------------} | ||
# --- Fields 2D Panel | ||
# --------------------------------------------------------------------------------{ | ||
class Fields2DPanel(wx.Panel): | ||
def __init__(self, parent, mainframe): | ||
wx.Panel.__init__(self, parent) | ||
# Data | ||
self.parent = parent | ||
self.mainframe = mainframe | ||
self.fileobjects = None | ||
|
||
multi_split = MultiSplitterWindow(self) | ||
self.filesPanel = wx.Panel(multi_split) | ||
self.fieldsPanel = wx.Panel(multi_split) | ||
self.canvasPanel = Plot2DPanel(multi_split) | ||
|
||
# GUI | ||
self.btExtractFields = wx.Button(self.filesPanel, label=CHAR['compute']+' '+"Extract 2D fields for all", style=wx.BU_EXACTFIT) | ||
self.textArgs = wx.TextCtrl(self.filesPanel, wx.ID_ANY, '', style = wx.TE_PROCESS_ENTER) | ||
self.lbFiles = wx.ListBox(self.filesPanel, style=wx.LB_EXTENDED) | ||
self.lbFields = wx.ListBox(self.fieldsPanel, style=wx.LB_EXTENDED) | ||
self.textArgs.SetValue('DeltaAzi=10') # TODO | ||
self.lbFiles.SetFont(getMonoFont(self)) | ||
self.lbFields.SetFont(getMonoFont(self)) | ||
self.textArgs.SetFont(getMonoFont(self)) | ||
|
||
# Layout | ||
sizer_files = wx.BoxSizer(wx.VERTICAL) | ||
sizer_files.Add(self.textArgs, 0, wx.EXPAND | wx.ALL, 1) | ||
sizer_files.Add(self.btExtractFields, 0, wx.EXPAND | wx.ALL, 1) | ||
sizer_files.Add(self.lbFiles, 1, wx.EXPAND | wx.ALL, 1) | ||
self.filesPanel.SetSizer(sizer_files) | ||
|
||
sizer_fields = wx.BoxSizer(wx.VERTICAL) | ||
sizer_fields.Add(self.lbFields, 1, wx.EXPAND | wx.ALL, 1) | ||
self.fieldsPanel.SetSizer(sizer_fields) | ||
|
||
multi_split.AppendWindow(self.filesPanel, 200) | ||
multi_split.AppendWindow(self.fieldsPanel, 200) | ||
multi_split.AppendWindow(self.canvasPanel) | ||
|
||
sizer = wx.BoxSizer(wx.VERTICAL) | ||
sizer.Add(multi_split, 1, wx.EXPAND) | ||
self.SetSizer(sizer) | ||
|
||
# Bind | ||
self.lbFiles.Bind(wx.EVT_LISTBOX, self.on_file_selected) | ||
self.lbFields.Bind(wx.EVT_LISTBOX, self.on_2d_field_selected) | ||
self.btExtractFields.Bind(wx.EVT_BUTTON, self.onExtract) | ||
#self.textArgs.Bind(wx.EVT_TEXT_ENTER, self.onParamChangeEnter) | ||
|
||
def cleanGUI(self, event=None): | ||
self.deselect() | ||
self.lbFiles.Clear() | ||
self.lbFields.Clear() | ||
self.canvasPanel.clean_plot() | ||
|
||
def deselect(self, event=None): | ||
[self.lbFiles.Deselect(i) for i in self.lbFiles.GetSelections()] | ||
[self.lbFields.Deselect(i) for i in self.lbFields.GetSelections()] | ||
|
||
def updateFiles(self, filenames, fileobjects): | ||
self.fileobjects=fileobjects | ||
filenames = [os.path.abspath(f).replace('/','|').replace('\\','|') for f in filenames] | ||
filenames = ellude_common(filenames) | ||
self.lbFiles.Set(filenames) | ||
#self.lbFiles.SetSelection(0) | ||
#self.on_file_selected() | ||
|
||
def getArgs(self): | ||
args = self.textArgs.GetValue().split(',') | ||
kwargs={} | ||
for arg in args: | ||
k, v = arg.split('=') | ||
kwargs[k.strip()] = v.strip() | ||
return kwargs | ||
|
||
def onExtract(self, event=None): | ||
self.deselect() | ||
kwargs = self.getArgs() | ||
for fo in self.fileobjects: | ||
extract2Dfields(fo, force=True, **kwargs) | ||
|
||
def on_file_selected(self, event=None): | ||
self.canvasPanel.clean_plot() | ||
|
||
ISelF = self.lbFiles.GetSelections() | ||
kwargs = self.getArgs() | ||
# --- Compute 2d field if not done yet | ||
for iself in ISelF: | ||
file_object = self.fileobjects[iself] | ||
if not hasattr(file_object, 'fields2D_tmp'): | ||
# Computing fields here if not already done for this file | ||
fields = extract2Dfields(file_object, **kwargs) | ||
else: | ||
fields = file_object.fields2D_tmp | ||
|
||
iself = ISelF[0] | ||
fieldListByFile=[] | ||
for iself in ISelF: | ||
fields = file_object.fields2D_tmp | ||
if fields is not None: | ||
fieldListByFile.append(fields.keys()) | ||
else: | ||
print('[WARN] No 2D fields for this file') | ||
|
||
# --- Get common columns | ||
if len(fieldListByFile)>0: | ||
commonCols = fieldListByFile[0] | ||
for i in np.arange(1,len(fieldListByFile)): | ||
commonCols = list( set(commonCols) & set( fieldListByFile[i])) | ||
# Respect order of first | ||
commonCols = [c for c in fieldListByFile[0] if c in commonCols] | ||
#commonCols.sort() | ||
self.lbFields.Set(commonCols) | ||
|
||
# Trigger, we select the first field... | ||
if len(commonCols)>0: | ||
self.lbFields.SetSelection(0) | ||
self.on_2d_field_selected() | ||
else: | ||
print('[WARN] No 2D fields') | ||
|
||
|
||
def on_2d_field_selected(self, event=None): | ||
ISelF = self.lbFiles.GetSelections() | ||
self.canvasPanel.fields=[] | ||
for iself in ISelF : | ||
file_object = self.fileobjects[iself] | ||
ISelC = self.lbFields.GetSelections() | ||
for iselc in ISelC: | ||
sfield = self.lbFields.GetString(iselc) | ||
# Field is a dictionary with keys: M, x, y, sx, sy, fieldname | ||
field = file_object.fields2D_tmp.loc(sfield) | ||
self.canvasPanel.add_field(**field) | ||
self.canvasPanel.update_plot() | ||
|
||
|
||
|
||
|
Oops, something went wrong.