From 4aec48b4f68ba3a9e8f2226846232253ba07be37 Mon Sep 17 00:00:00 2001 From: Sylvain Tricot Date: Tue, 22 Oct 2024 12:39:54 +0200 Subject: [PATCH] Provide a "nogui" target in the installation. It is possible to install msspec without gui, which reduces a lot the number of dependencies. It is still possible to export the results as *.png or to view the cluster with the ase gui. --- Makefile | 5 + src/msspec/iodata.py | 808 ++++++++++++++++++++++--------------------- src/options.mk | 2 +- 3 files changed, 418 insertions(+), 397 deletions(-) diff --git a/Makefile b/Makefile index d0dfe5f..65ceda1 100644 --- a/Makefile +++ b/Makefile @@ -37,6 +37,11 @@ light: VENV_PATH = ./_venv light: venv @$(INSIDE_VENV) pip install src/ +nogui: VENV_PATH = ./_venv +nogui: venv + @$(INSIDE_VENV) pip install --no-cache-dir --upgrade -r src/pip.freeze + @$(INSIDE_VENV) pip install -e src/ + @+$(INSIDE_VENV) $(MAKE) -C src pybinding _attrdict: # Check if virtualenv python version > 3.3.0 diff --git a/src/msspec/iodata.py b/src/msspec/iodata.py index 27369d9..c60ccc3 100644 --- a/src/msspec/iodata.py +++ b/src/msspec/iodata.py @@ -17,7 +17,7 @@ # along with this msspec. If not, see . # # Source file : src/msspec/iodata.py -# Last modified: Mon, 11 Mar 2024 09:51:47 +0100 +# Last modified: Tue, 22 Oct 2024 12:39:54 +0200 # Committed by : Sylvain Tricot @@ -79,19 +79,26 @@ import ase.io from ase.io.extxyz import read_xyz, write_xyz import h5py import numpy as np -import wx.grid from lxml import etree -from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas #from matplotlib.backends.backend_wxagg import FigureCanvasWx as FigureCanvas from matplotlib.backends.backend_agg import FigureCanvasAgg -from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg +#from matplotlib.backends.backend_cairo import FigureCanvasCairo as FigureCanvasAgg from matplotlib.figure import Figure from terminaltables import AsciiTable import msspec -from msspec.msspecgui.msspec.gui.clusterviewer import ClusterViewer from msspec.misc import LOGGER +try: + import wx.grid + from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas + from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg + from msspec.msspecgui.msspec.gui.clusterviewer import ClusterViewer + has_gui = True +except ImportError: + LOGGER.warning('No modules for GUI') + has_gui = False + def cols2matrix(x, y, z, nx=88*1+1, ny=360*1+1): # mix the values of existing theta and new theta and return the @@ -796,11 +803,17 @@ class Data(object): """Pops up a grphical window to show all the defined views of the Data object. """ - app = wx.App(False) - app.SetAppName('MsSpec Data Viewer') - frame = _DataWindow(self) - frame.Show(True) - app.MainLoop() + if has_gui: + app = wx.App(False) + app.SetAppName('MsSpec Data Viewer') + frame = _DataWindow(self) + frame.Show(True) + app.MainLoop() + else: + print('**** INFORMATION ****') + print('You can not use the Data.view() method since ther is no') + print('graphical user interface available in this version of MsSpec.') + print("Install WxPython if you need it or use Data.export(...) method instead.") class _DataSetView(object): @@ -895,7 +908,8 @@ class _DataSetView(object): axes.set_yticks(R_ticks) axes.set_yticklabels(theta_ticks) - figure.colorbar(im) + cbar = figure.colorbar(im) + #im.set_clim(0, 0.0275) elif proj == 'polar': values[0] = np.radians(values[0]) @@ -918,6 +932,7 @@ class _DataSetView(object): axes.set_ylabel(opts['ylabel']) axes.set_xlim(*opts['xlim']) axes.set_ylim(*opts['ylim']) + #axes.set_axis_off() #axes.set_pickradius(5) if label: axes.legend() @@ -1008,425 +1023,426 @@ class _DataSetView(object): s += '\tconditions : %s\n' % str(self._selection_conditions) return s -class _GridWindow(wx.Frame): - def __init__(self, dset, parent=None): - title = 'Data: ' + dset.title - wx.Frame.__init__(self, parent, title=title, size=(640, 480)) - self.create_grid(dset) +if has_gui: + class _GridWindow(wx.Frame): + def __init__(self, dset, parent=None): + title = 'Data: ' + dset.title + wx.Frame.__init__(self, parent, title=title, size=(640, 480)) + self.create_grid(dset) - def create_grid(self, dset): - grid = wx.grid.Grid(self, -1) - grid.CreateGrid(len(dset), len(dset.columns())) - for ic, c in enumerate(dset.columns()): - grid.SetColLabelValue(ic, c) - for iv, v in enumerate(dset[c]): - grid.SetCellValue(iv, ic, str(v)) + def create_grid(self, dset): + grid = wx.grid.Grid(self, -1) + grid.CreateGrid(len(dset), len(dset.columns())) + for ic, c in enumerate(dset.columns()): + grid.SetColLabelValue(ic, c) + for iv, v in enumerate(dset[c]): + grid.SetCellValue(iv, ic, str(v)) -class _ParametersWindow(wx.Frame): - def __init__(self, dset, parent=None): - title = 'Parameters: ' + dset.title - wx.Frame.__init__(self, parent, title=title, size=(400, 480)) - self.create_tree(dset) + class _ParametersWindow(wx.Frame): + def __init__(self, dset, parent=None): + title = 'Parameters: ' + dset.title + wx.Frame.__init__(self, parent, title=title, size=(400, 480)) + self.create_tree(dset) - def create_tree(self, dset): - datatree = {} - for p in dset.parameters(): - is_hidden = p.get('hidden', "False") - if is_hidden == "True": - continue - group = datatree.get(p['group'], []) - #strval = str(p['value'] * p['unit'] if p['unit'] else p['value']) - #group.append("{:s} = {:s}".format(p['name'], strval)) - group.append("{} = {} {}".format(p['name'], p['value'], p['unit'])) - datatree[p['group']] = group + def create_tree(self, dset): + datatree = {} + for p in dset.parameters(): + is_hidden = p.get('hidden', "False") + if is_hidden == "True": + continue + group = datatree.get(p['group'], []) + #strval = str(p['value'] * p['unit'] if p['unit'] else p['value']) + #group.append("{:s} = {:s}".format(p['name'], strval)) + group.append("{} = {} {}".format(p['name'], p['value'], p['unit'])) + datatree[p['group']] = group - tree = wx.TreeCtrl(self, -1) - root = tree.AddRoot('Parameters') + tree = wx.TreeCtrl(self, -1) + root = tree.AddRoot('Parameters') - for key in list(datatree.keys()): - item0 = tree.AppendItem(root, key) - for item in datatree[key]: - tree.AppendItem(item0, item) - tree.ExpandAll() - tree.SelectItem(root) + for key in list(datatree.keys()): + item0 = tree.AppendItem(root, key) + for item in datatree[key]: + tree.AppendItem(item0, item) + tree.ExpandAll() + tree.SelectItem(root) -class _DataWindow(wx.Frame): - def __init__(self, data): - assert isinstance(data, (Data, DataSet)) + class _DataWindow(wx.Frame): + def __init__(self, data): + assert isinstance(data, (Data, DataSet)) - if isinstance(data, DataSet): - dset = data - data = Data() - data.first = dset - self.data = data - self._filename = None - self._current_dset = None + if isinstance(data, DataSet): + dset = data + data = Data() + data.first = dset + self.data = data + self._filename = None + self._current_dset = None - wx.Frame.__init__(self, None, title="", size=(640, 480)) + wx.Frame.__init__(self, None, title="", size=(640, 480)) - self.Bind(wx.EVT_CLOSE, self.on_close) + self.Bind(wx.EVT_CLOSE, self.on_close) - # Populate the menu bar - self.create_menu() + # Populate the menu bar + self.create_menu() - # Create the status bar - statusbar = wx.StatusBar(self, -1) - statusbar.SetFieldsCount(3) - statusbar.SetStatusWidths([-2, -1, -1]) - self.SetStatusBar(statusbar) + # Create the status bar + statusbar = wx.StatusBar(self, -1) + statusbar.SetFieldsCount(3) + statusbar.SetStatusWidths([-2, -1, -1]) + self.SetStatusBar(statusbar) - # Add the notebook to hold all graphs - self.notebooks = {} - sizer = wx.BoxSizer(wx.VERTICAL) - #sizer.Add(self.notebook) - self.SetSizer(sizer) + # Add the notebook to hold all graphs + self.notebooks = {} + sizer = wx.BoxSizer(wx.VERTICAL) + #sizer.Add(self.notebook) + self.SetSizer(sizer) - self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.on_page_changed) + self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.on_page_changed) - self.create_notebooks() - - self.update_title() - - def create_notebooks(self): - for key in list(self.notebooks.keys()): - nb = self.notebooks.pop(key) - nb.Destroy() - - for dset in self.data: - nb = wx.Notebook(self, -1) - self.notebooks[dset.title] = nb - #self.GetSizer().Add(nb, 1, wx.ALL|wx.EXPAND) - self.GetSizer().Add(nb, proportion=1, flag=wx.ALL|wx.EXPAND) - for view in dset.views(): - self.create_page(nb, view) - - self.create_menu() - - self.show_dataset(self.data[0].title) - - - def create_menu(self): - menubar = wx.MenuBar() - menu1 = wx.Menu() - menu1.Append(110, "Open\tCtrl+O") - menu1.Append(120, "Save\tCtrl+S") - menu1.Append(130, "Save as...") - menu1.Append(140, "Export\tCtrl+E") - menu1.AppendSeparator() - menu1.Append(199, "Close\tCtrl+Q") - - menu2 = wx.Menu() - for i, dset in enumerate(self.data): - menu_id = 201 + i - menu2.AppendRadioItem(menu_id, dset.title) - self.Bind(wx.EVT_MENU, self.on_menu_dataset, id=menu_id) - - self.Bind(wx.EVT_MENU, self.on_open, id=110) - self.Bind(wx.EVT_MENU, self.on_save, id=120) - self.Bind(wx.EVT_MENU, self.on_saveas, id=130) - self.Bind(wx.EVT_MENU, self.on_export, id=140) - self.Bind(wx.EVT_MENU, self.on_close, id=199) - - - menu3 = wx.Menu() - menu3.Append(301, "Data") - menu3.Append(302, "Cluster") - menu3.Append(303, "Parameters") - - self.Bind(wx.EVT_MENU, self.on_viewdata, id=301) - self.Bind(wx.EVT_MENU, self.on_viewcluster, id=302) - self.Bind(wx.EVT_MENU, self.on_viewparameters, id=303) - - menubar.Append(menu1, "&File") - menubar.Append(menu2, "&Datasets") - menubar.Append(menu3, "&View") - self.SetMenuBar(menubar) - - def on_open(self, event): - if self.data.is_dirty(): - mbx = wx.MessageDialog(self, ('Displayed data is unsaved. Do ' - 'you wish to save before opening' - 'another file ?'), - 'Warning: Unsaved data', - wx.YES_NO | wx.ICON_WARNING) - if mbx.ShowModal() == wx.ID_YES: - self.on_saveas(wx.Event()) - mbx.Destroy() - - wildcard = "HDF5 files (*.hdf5)|*.hdf5" - dlg = wx.FileDialog( - self, message="Open a file...", defaultDir=os.getcwd(), - defaultFile="", wildcard=wildcard, style=wx.FD_OPEN - ) - - if dlg.ShowModal() == wx.ID_OK: - path = dlg.GetPath() - self._filename = path - self.data = Data.load(path) self.create_notebooks() - dlg.Destroy() - self.update_title() - def on_save(self, event): - if self._filename: + self.update_title() + + def create_notebooks(self): + for key in list(self.notebooks.keys()): + nb = self.notebooks.pop(key) + nb.Destroy() + + for dset in self.data: + nb = wx.Notebook(self, -1) + self.notebooks[dset.title] = nb + #self.GetSizer().Add(nb, 1, wx.ALL|wx.EXPAND) + self.GetSizer().Add(nb, proportion=1, flag=wx.ALL|wx.EXPAND) + for view in dset.views(): + self.create_page(nb, view) + + self.create_menu() + + self.show_dataset(self.data[0].title) + + + def create_menu(self): + menubar = wx.MenuBar() + menu1 = wx.Menu() + menu1.Append(110, "Open\tCtrl+O") + menu1.Append(120, "Save\tCtrl+S") + menu1.Append(130, "Save as...") + menu1.Append(140, "Export\tCtrl+E") + menu1.AppendSeparator() + menu1.Append(199, "Close\tCtrl+Q") + + menu2 = wx.Menu() + for i, dset in enumerate(self.data): + menu_id = 201 + i + menu2.AppendRadioItem(menu_id, dset.title) + self.Bind(wx.EVT_MENU, self.on_menu_dataset, id=menu_id) + + self.Bind(wx.EVT_MENU, self.on_open, id=110) + self.Bind(wx.EVT_MENU, self.on_save, id=120) + self.Bind(wx.EVT_MENU, self.on_saveas, id=130) + self.Bind(wx.EVT_MENU, self.on_export, id=140) + self.Bind(wx.EVT_MENU, self.on_close, id=199) + + + menu3 = wx.Menu() + menu3.Append(301, "Data") + menu3.Append(302, "Cluster") + menu3.Append(303, "Parameters") + + self.Bind(wx.EVT_MENU, self.on_viewdata, id=301) + self.Bind(wx.EVT_MENU, self.on_viewcluster, id=302) + self.Bind(wx.EVT_MENU, self.on_viewparameters, id=303) + + menubar.Append(menu1, "&File") + menubar.Append(menu2, "&Datasets") + menubar.Append(menu3, "&View") + self.SetMenuBar(menubar) + + def on_open(self, event): if self.data.is_dirty(): - self.data.save(self._filename) - else: - self.on_saveas(event) - - def on_saveas(self, event): - overwrite = True - wildcard = "HDF5 files (*.hdf5)|*.hdf5|All files (*.*)|*.*" - dlg = wx.FileDialog( - self, message="Save file as ...", defaultDir=os.getcwd(), - defaultFile='{}.hdf5'.format(self.data.title.replace(' ','_')), - wildcard=wildcard, style=wx.FD_SAVE) - dlg.SetFilterIndex(0) - - if dlg.ShowModal() == wx.ID_OK: - path = dlg.GetPath() - if os.path.exists(path): - mbx = wx.MessageDialog(self, ('This file already exists. ' - 'Do you wish to overwrite it ?'), - 'Warning: File exists', - wx.YES_NO | wx.ICON_WARNING) - if mbx.ShowModal() == wx.ID_NO: - overwrite = False + mbx = wx.MessageDialog(self, ('Displayed data is unsaved. Do ' + 'you wish to save before opening' + 'another file ?'), + 'Warning: Unsaved data', + wx.YES_NO | wx.ICON_WARNING) + if mbx.ShowModal() == wx.ID_YES: + self.on_saveas(wx.Event()) mbx.Destroy() - if overwrite: - self.data.save(path) + + wildcard = "HDF5 files (*.hdf5)|*.hdf5" + dlg = wx.FileDialog( + self, message="Open a file...", defaultDir=os.getcwd(), + defaultFile="", wildcard=wildcard, style=wx.FD_OPEN + ) + + if dlg.ShowModal() == wx.ID_OK: + path = dlg.GetPath() self._filename = path - dlg.Destroy() - self.update_title() + self.data = Data.load(path) + self.create_notebooks() + dlg.Destroy() + self.update_title() - def on_export(self, event): - overwrite = True - dlg = wx.DirDialog( - self, message="Export data...", defaultPath=os.getcwd(), - style=wx.DD_DEFAULT_STYLE) - - if dlg.ShowModal() == wx.ID_OK: - path = dlg.GetPath() - if os.listdir(path): - mbx = wx.MessageDialog(self, - ('This folder is not empty. ' - 'Exporting tour data here may ' - 'overwrite its content. Do you wish ' - 'to continue ?'), - 'Warning: Folder is not empty', - wx.YES_NO | wx.ICON_WARNING) - if mbx.ShowModal() == wx.ID_NO: - overwrite = False - mbx.Destroy() - self.data.export(path, overwrite) - dlg.Destroy() - - def on_viewdata(self, event): - dset = self.data[self._current_dset] - frame = _GridWindow(dset, parent=self) - frame.Show() - - def on_viewcluster(self, event): - win = wx.Frame(None, size=wx.Size(480, 340)) - cluster_viewer = ClusterViewer(win, size=wx.Size(480, 340)) - - dset = self.data[self._current_dset] - #s = StringIO() - #s.write(dset.get_parameter(group='Cluster', name='cluster')['value']) - #_s = dset.get_parameter(group='Cluster', name='cluster')['value'] - #print(_s) - # rewind to the begining of the string - #s.seek(0) - #atoms = ase.io.read(s, format='xyz') - atoms = dset.get_cluster() - cluster_viewer.set_atoms(atoms, rescale=True, center=True) - cluster_viewer.rotate_atoms(0., 180.) - cluster_viewer.rotate_atoms(-45., -45.) - #cluster_viewer.show_emitter(True) - win.Show() - - def on_viewparameters(self, event): - dset = self.data[self._current_dset] - frame = _ParametersWindow(dset, parent=self) - frame.Show() - - def on_close(self, event): - if self.data.is_dirty(): - mbx = wx.MessageDialog(self, ('Displayed data is unsaved. Do you ' - 'really want to quit ?'), - 'Warning: Unsaved data', - wx.YES_NO | wx.ICON_WARNING) - if mbx.ShowModal() == wx.ID_NO: - mbx.Destroy() - return - self.Destroy() - - - def on_menu_dataset(self, event): - menu_id = event.GetId() - dset_name = self.GetMenuBar().FindItemById(menu_id).GetItemLabelText() - self.show_dataset(dset_name) - - - def show_dataset(self, name): - for nb in list(self.notebooks.values()): - nb.Hide() - self.notebooks[name].Show() - self.Layout() - self.update_statusbar() - self._current_dset = name - - def create_page(self, nb, view): - # Get the matplotlib figure - figure = view.get_figure() - - # Create a panel - p = wx.Panel(nb, -1) - - # Create a matplotlib canvas for the figure - canvas = FigureCanvas(p, -1, figure) - sizer = wx.BoxSizer(wx.VERTICAL) - - toolbar = NavigationToolbar2WxAgg(canvas) - toolbar.Realize() - - #sizer.Add(toolbar, 0, wx.ALL|wx.EXPAND) - sizer.Add(toolbar, proportion=0, flag=wx.ALL|wx.EXPAND) - toolbar.update() - - #sizer.Add(canvas, 5, wx.ALL|wx.EXPAND) - sizer.Add(canvas, proportion=1, flag=wx.ALL|wx.EXPAND) - - p.SetSizer(sizer) - p.Fit() - p.Show() - - # MPL events - figure.canvas.mpl_connect('motion_notify_event', self.on_mpl_motion) - figure.canvas.mpl_connect('pick_event', self.on_mpl_pick) - - nb.AddPage(p, view.title) - canvas.draw() - - - def OLDcreate_page(self, nb, view): - opts = view._plotopts - p = wx.Panel(nb, -1) - - figure = Figure() - - axes = None - proj = opts['projection'] - scale = opts['scale'] - if proj == 'rectilinear': - axes = figure.add_subplot(111, projection='rectilinear') - elif proj in ('polar', 'ortho', 'stereo'): - axes = figure.add_subplot(111, projection='polar') - - canvas = FigureCanvas(p, -1, figure) - sizer = wx.BoxSizer(wx.VERTICAL) - - toolbar = NavigationToolbar2WxAgg(canvas) - toolbar.Realize() - - sizer.Add(toolbar, 0, wx.ALL|wx.EXPAND) - toolbar.update() - - sizer.Add(canvas, 5, wx.ALL|wx.EXPAND) - - p.SetSizer(sizer) - p.Fit() - p.Show() - - - for values, label in zip(view.get_data(), opts['legend']): - # if we have only one column to plot, select a bar graph - if np.shape(values)[0] == 1: - xvalues = list(range(len(values[0]))) - axes.bar(xvalues, values[0], label=label, - picker=5) - axes.set_xticks(xvalues) + def on_save(self, event): + if self._filename: + if self.data.is_dirty(): + self.data.save(self._filename) else: - if proj in ('ortho', 'stereo'): - theta, phi, Xsec = cols2matrix(*values) - theta_ticks = np.arange(0, 91, 15) - if proj == 'ortho': - R = np.sin(np.radians(theta)) - R_ticks = np.sin(np.radians(theta_ticks)) - elif proj == 'stereo': - R = 2 * np.tan(np.radians(theta/2.)) - R_ticks = 2 * np.tan(np.radians(theta_ticks/2.)) - #R = np.tan(np.radians(theta/2.)) - X, Y = np.meshgrid(np.radians(phi), R) - im = axes.pcolormesh(X, Y, Xsec) - axes.set_yticks(R_ticks) - axes.set_yticklabels(theta_ticks) + self.on_saveas(event) - figure.colorbar(im) + def on_saveas(self, event): + overwrite = True + wildcard = "HDF5 files (*.hdf5)|*.hdf5|All files (*.*)|*.*" + dlg = wx.FileDialog( + self, message="Save file as ...", defaultDir=os.getcwd(), + defaultFile='{}.hdf5'.format(self.data.title.replace(' ','_')), + wildcard=wildcard, style=wx.FD_SAVE) + dlg.SetFilterIndex(0) - elif proj == 'polar': - values[0] = np.radians(values[0]) - axes.plot(*values, label=label, picker=5, - marker=opts['marker']) + if dlg.ShowModal() == wx.ID_OK: + path = dlg.GetPath() + if os.path.exists(path): + mbx = wx.MessageDialog(self, ('This file already exists. ' + 'Do you wish to overwrite it ?'), + 'Warning: File exists', + wx.YES_NO | wx.ICON_WARNING) + if mbx.ShowModal() == wx.ID_NO: + overwrite = False + mbx.Destroy() + if overwrite: + self.data.save(path) + self._filename = path + dlg.Destroy() + self.update_title() + + def on_export(self, event): + overwrite = True + dlg = wx.DirDialog( + self, message="Export data...", defaultPath=os.getcwd(), + style=wx.DD_DEFAULT_STYLE) + + if dlg.ShowModal() == wx.ID_OK: + path = dlg.GetPath() + if os.listdir(path): + mbx = wx.MessageDialog(self, + ('This folder is not empty. ' + 'Exporting tour data here may ' + 'overwrite its content. Do you wish ' + 'to continue ?'), + 'Warning: Folder is not empty', + wx.YES_NO | wx.ICON_WARNING) + if mbx.ShowModal() == wx.ID_NO: + overwrite = False + mbx.Destroy() + self.data.export(path, overwrite) + dlg.Destroy() + + def on_viewdata(self, event): + dset = self.data[self._current_dset] + frame = _GridWindow(dset, parent=self) + frame.Show() + + def on_viewcluster(self, event): + win = wx.Frame(None, size=wx.Size(480, 340)) + cluster_viewer = ClusterViewer(win, size=wx.Size(480, 340)) + + dset = self.data[self._current_dset] + #s = StringIO() + #s.write(dset.get_parameter(group='Cluster', name='cluster')['value']) + #_s = dset.get_parameter(group='Cluster', name='cluster')['value'] + #print(_s) + # rewind to the begining of the string + #s.seek(0) + #atoms = ase.io.read(s, format='xyz') + atoms = dset.get_cluster() + cluster_viewer.set_atoms(atoms, rescale=True, center=True) + cluster_viewer.rotate_atoms(0., 180.) + cluster_viewer.rotate_atoms(-45., -45.) + #cluster_viewer.show_emitter(True) + win.Show() + + def on_viewparameters(self, event): + dset = self.data[self._current_dset] + frame = _ParametersWindow(dset, parent=self) + frame.Show() + + def on_close(self, event): + if self.data.is_dirty(): + mbx = wx.MessageDialog(self, ('Displayed data is unsaved. Do you ' + 'really want to quit ?'), + 'Warning: Unsaved data', + wx.YES_NO | wx.ICON_WARNING) + if mbx.ShowModal() == wx.ID_NO: + mbx.Destroy() + return + self.Destroy() + + + def on_menu_dataset(self, event): + menu_id = event.GetId() + dset_name = self.GetMenuBar().FindItemById(menu_id).GetItemLabelText() + self.show_dataset(dset_name) + + + def show_dataset(self, name): + for nb in list(self.notebooks.values()): + nb.Hide() + self.notebooks[name].Show() + self.Layout() + self.update_statusbar() + self._current_dset = name + + def create_page(self, nb, view): + # Get the matplotlib figure + figure = view.get_figure() + + # Create a panel + p = wx.Panel(nb, -1) + + # Create a matplotlib canvas for the figure + canvas = FigureCanvas(p, -1, figure) + sizer = wx.BoxSizer(wx.VERTICAL) + + toolbar = NavigationToolbar2WxAgg(canvas) + toolbar.Realize() + + #sizer.Add(toolbar, 0, wx.ALL|wx.EXPAND) + sizer.Add(toolbar, proportion=0, flag=wx.ALL|wx.EXPAND) + toolbar.update() + + #sizer.Add(canvas, 5, wx.ALL|wx.EXPAND) + sizer.Add(canvas, proportion=1, flag=wx.ALL|wx.EXPAND) + + p.SetSizer(sizer) + p.Fit() + p.Show() + + # MPL events + figure.canvas.mpl_connect('motion_notify_event', self.on_mpl_motion) + figure.canvas.mpl_connect('pick_event', self.on_mpl_pick) + + nb.AddPage(p, view.title) + canvas.draw() + + + def OLDcreate_page(self, nb, view): + opts = view._plotopts + p = wx.Panel(nb, -1) + + figure = Figure() + + axes = None + proj = opts['projection'] + scale = opts['scale'] + if proj == 'rectilinear': + axes = figure.add_subplot(111, projection='rectilinear') + elif proj in ('polar', 'ortho', 'stereo'): + axes = figure.add_subplot(111, projection='polar') + + canvas = FigureCanvas(p, -1, figure) + sizer = wx.BoxSizer(wx.VERTICAL) + + toolbar = NavigationToolbar2WxAgg(canvas) + toolbar.Realize() + + sizer.Add(toolbar, 0, wx.ALL|wx.EXPAND) + toolbar.update() + + sizer.Add(canvas, 5, wx.ALL|wx.EXPAND) + + p.SetSizer(sizer) + p.Fit() + p.Show() + + + for values, label in zip(view.get_data(), opts['legend']): + # if we have only one column to plot, select a bar graph + if np.shape(values)[0] == 1: + xvalues = list(range(len(values[0]))) + axes.bar(xvalues, values[0], label=label, + picker=5) + axes.set_xticks(xvalues) else: - if scale == 'semilogx': - pltcmd = axes.semilogx - elif scale == 'semilogy': - pltcmd = axes.semilogy - elif scale == 'log': - pltcmd = axes.loglog + if proj in ('ortho', 'stereo'): + theta, phi, Xsec = cols2matrix(*values) + theta_ticks = np.arange(0, 91, 15) + if proj == 'ortho': + R = np.sin(np.radians(theta)) + R_ticks = np.sin(np.radians(theta_ticks)) + elif proj == 'stereo': + R = 2 * np.tan(np.radians(theta/2.)) + R_ticks = 2 * np.tan(np.radians(theta_ticks/2.)) + #R = np.tan(np.radians(theta/2.)) + X, Y = np.meshgrid(np.radians(phi), R) + im = axes.pcolormesh(X, Y, Xsec) + axes.set_yticks(R_ticks) + axes.set_yticklabels(theta_ticks) + + figure.colorbar(im) + + elif proj == 'polar': + values[0] = np.radians(values[0]) + axes.plot(*values, label=label, picker=5, + marker=opts['marker']) else: - pltcmd = axes.plot - pltcmd(*values, label=label, picker=5, - marker=opts['marker']) - axes.grid(opts['grid']) - axes.set_title(opts['title']) - axes.set_xlabel(opts['xlabel']) - axes.set_ylabel(opts['ylabel']) - axes.set_xlim(*opts['xlim']) - axes.set_ylim(*opts['ylim']) - if label: - axes.legend() - axes.autoscale(enable=opts['autoscale']) + if scale == 'semilogx': + pltcmd = axes.semilogx + elif scale == 'semilogy': + pltcmd = axes.semilogy + elif scale == 'log': + pltcmd = axes.loglog + else: + pltcmd = axes.plot + pltcmd(*values, label=label, picker=5, + marker=opts['marker']) + axes.grid(opts['grid']) + axes.set_title(opts['title']) + axes.set_xlabel(opts['xlabel']) + axes.set_ylabel(opts['ylabel']) + axes.set_xlim(*opts['xlim']) + axes.set_ylim(*opts['ylim']) + if label: + axes.legend() + axes.autoscale(enable=opts['autoscale']) - # MPL events - figure.canvas.mpl_connect('motion_notify_event', self.on_mpl_motion) - figure.canvas.mpl_connect('pick_event', self.on_mpl_pick) + # MPL events + figure.canvas.mpl_connect('motion_notify_event', self.on_mpl_motion) + figure.canvas.mpl_connect('pick_event', self.on_mpl_pick) - nb.AddPage(p, view.title) + nb.AddPage(p, view.title) - def update_statusbar(self): - sb = self.GetStatusBar() - menu_id = self.GetMenuBar().FindMenu('Datasets') - menu = self.GetMenuBar().GetMenu(menu_id) - for item in menu.GetMenuItems(): - if item.IsChecked(): - sb.SetStatusText("%s" % item.GetItemLabelText(), 1) - break + def update_statusbar(self): + sb = self.GetStatusBar() + menu_id = self.GetMenuBar().FindMenu('Datasets') + menu = self.GetMenuBar().GetMenu(menu_id) + for item in menu.GetMenuItems(): + if item.IsChecked(): + sb.SetStatusText("%s" % item.GetItemLabelText(), 1) + break - def update_title(self): - title = "MsSpec Data Viewer" - if self.data.title: - title += ": " + self.data.title - if self._filename: - title += " [" + os.path.basename(self._filename) + "]" - self.SetTitle(title) + def update_title(self): + title = "MsSpec Data Viewer" + if self.data.title: + title += ": " + self.data.title + if self._filename: + title += " [" + os.path.basename(self._filename) + "]" + self.SetTitle(title) - def on_mpl_motion(self, event): - sb = self.GetStatusBar() - try: - txt = "[{:.3f}, {:.3f}]".format(event.xdata, event.ydata) - sb.SetStatusText(txt, 2) - except Exception: - pass + def on_mpl_motion(self, event): + sb = self.GetStatusBar() + try: + txt = "[{:.3f}, {:.3f}]".format(event.xdata, event.ydata) + sb.SetStatusText(txt, 2) + except Exception: + pass - def on_mpl_pick(self, event): - print(event.artist) + def on_mpl_pick(self, event): + print(event.artist) - def on_page_changed(self, event): - self.update_statusbar() + def on_page_changed(self, event): + self.update_statusbar() diff --git a/src/options.mk b/src/options.mk index 5e08919..6c30220 100644 --- a/src/options.mk +++ b/src/options.mk @@ -3,7 +3,7 @@ PYMAJ = 3 PYMIN = 5 FC = gfortran -F2PY = f2py3 --f77exec=$(FC) --f90exec=$(FC) +F2PY = f2py --f77exec=$(FC) --f90exec=$(FC) NO_VENV = 0 DEBUG = 0