Commit 976dedb9 authored by eric pellegrini's avatar eric pellegrini

The userdefinition viewer, the registry viewer and the periodictable

viewer are no longer plugins.
Improved significantly the ergonomy of the periodictable viewer
The user can now performs several atom selection and transmutation.
Improved the atom list widget
Fixed several bugs
Added new icons
parent a8429c86
......@@ -36,7 +36,7 @@ import operator
import numpy
from MDANSE.Framework.UserDefinitionsStore import UD_STORE
from MDANSE.Framework.Configurators.IConfigurator import IConfigurator, ConfiguratorError
from MDANSE.Framework.Configurators.IConfigurator import IConfigurator
from MDANSE.Framework.AtomSelectionParser import AtomSelectionParser
# The granularities at which the selection will be performed
......@@ -76,20 +76,26 @@ class AtomSelectionConfigurator(IConfigurator):
trajConfig = configuration[self._dependencies['trajectory']]
if value is None:
value = 'all'
elif not isinstance(value,basestring):
raise ConfiguratorError("invalid type for atom selection. Must be a string", self)
value = ['all']
if isinstance(value,basestring):
value = [value]
self["value"] = value
if UD_STORE.has_definition(trajConfig["basename"],"atom_selection",value):
ud = UD_STORE.get_definition(trajConfig["basename"],"atom_selection",value)
self.update(ud)
else:
parser = AtomSelectionParser(trajConfig["instance"].universe)
self["indexes"] = parser.parse(value)
self["expression"] = value
self["indexes"] = []
for v in value:
if UD_STORE.has_definition(trajConfig["basename"],"atom_selection",v):
ud = UD_STORE.get_definition(trajConfig["basename"],"atom_selection",v)
self["indexes"].append(ud["indexes"])
else:
parser = AtomSelectionParser(trajConfig["instance"].universe)
self["indexes"].append(parser.parse(v))
self["indexes"].sort()
self["n_selected_atoms"] = len(self["indexes"])
atoms = sorted(trajConfig["universe"].atomList(), key = operator.attrgetter('index'))
selectedAtoms = [atoms[idx] for idx in self["indexes"]]
......
......@@ -84,25 +84,19 @@ class AtomTransmutationConfigurator(IConfigurator):
trajConfig = configuration[self._dependencies['trajectory']]
parser = AtomSelectionParser(trajConfig["instance"].universe)
# If the input value is a dictionary, it must have a selection string as key and the element
# to be transmutated to as value
if isinstance(value,dict):
for expression,element in value.items():
indexes = parser.parse(element,expression)
self.transmutate(configuration, indexes, element)
# Otherwise, it must be a string that will be found as a user-definition keys
elif isinstance(value,basestring):
if UD_STORE.has_definition(trajConfig["basename"],"atom_transmutation",value):
ud = UD_STORE.get_definition(trajConfig["basename"],"atom_transmutation",value)
self.transmutate(configuration, ud["indexes"], ud["element"])
for expression,element in value:
# Otherwise, it must be a string that will be found as a user-definition keys
if not isinstance(expression,basestring):
raise ConfiguratorError("Wrong format for atom transmutation configurator.",self)
if UD_STORE.has_definition(trajConfig["basename"],"atom_transmutation",expression):
ud = UD_STORE.get_definition(trajConfig["basename"],"atom_selection",expression)
self.transmutate(configuration, ud["indexes"], element)
else:
raise ConfiguratorError("wrong parameters type: must be either a dictionary whose keys are an atom selection string and values are the target element \
or a list of string that match an user definition",self)
else:
raise ConfiguratorError("wrong parameters type: must be either a dictionary whose keys are an atom selection string and values are the target element \
or a list of string that match an user definition",self)
indexes = parser.parse(expression)
self.transmutate(configuration, indexes, element)
def transmutate(self, configuration, selection, element):
'''
......
This diff is collapsed.
#MDANSE : Molecular Dynamics Analysis for Neutron Scattering Experiments
#------------------------------------------------------------------------------------------
#Copyright (C)
#2015- Eric C. Pellegrini Institut Laue-Langevin
#BP 156
#6, rue Jules Horowitz
#38042 Grenoble Cedex 9
#France
#pellegrini[at]ill.fr
#goret[at]ill.fr
#aoun[at]ill.fr
#
#This library is free software; you can redistribute it and/or
#modify it under the terms of the GNU Lesser General Public
#License as published by the Free Software Foundation; either
#version 2.1 of the License, or (at your option) any later version.
#
#This library is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
#Lesser General Public License for more details.
#
#You should have received a copy of the GNU Lesser General Public
#License along with this library; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
'''
Created on Mar 30, 2015
:author: Eric C. Pellegrini
'''
from MDANSE.Framework.Plugins.AtomSelectionPlugin import AtomSelectionPlugin
class AtomTransmutationPlugin(AtomSelectionPlugin):
type = 'atom_transmutation'
label = "Atom transmutation"
ancestor = ["molecular_viewer"]
udType = "atom_selection"
\ No newline at end of file
This diff is collapsed.
......@@ -132,15 +132,22 @@ class IPlugin(wx.Panel):
def currentWindow(self):
return self._currentWindow
def close(self):
pass
def on_close_pane(self, event):
d = wx.MessageDialog(None, 'Closing this plugin will also close all the other ones you plugged in in so far. Do you really want to close ?', 'Question', wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION)
if d.ShowModal() == wx.ID_NO:
return
window = event.GetPane().window
# Call the 'close' method the plugin to be closed
window.close()
self._mgr.DetachPane(window)
window.Destroy()
self._mgr.Update()
......
......@@ -164,7 +164,7 @@ class JobFrame(wx.Frame):
def __init__(self, parent, jobType, datakey=None):
wx.Frame.__init__(self, parent, wx.ID_ANY, size = (800,400), style=wx.DEFAULT_DIALOG_STYLE|wx.MINIMIZE_BOX|wx.MAXIMIZE_BOX|wx.RESIZE_BORDER)
wx.Frame.__init__(self, parent, wx.ID_ANY, size = (800,800), style=wx.DEFAULT_DIALOG_STYLE|wx.MINIMIZE_BOX|wx.MAXIMIZE_BOX|wx.RESIZE_BORDER)
self._jobType = jobType
......@@ -196,6 +196,6 @@ if __name__ == "__main__":
filename = os.path.join(os.path.dirname(PLATFORM.package_directory()),'Data','Trajectories','MMTK','protein_in_periodic_universe.nc')
app = wx.App(False)
f = JobFrame(None,'dl_poly')
f = JobFrame(None,'ac',filename)
f.Show()
app.MainLoop()
\ No newline at end of file
......@@ -166,9 +166,7 @@ class MolecularViewerPanel(ComponentPlugin):
ComponentPlugin.__init__(self, parent, *args, **kwargs)
self.enable_picking(True)
pub.subscribe(self.msg_set_selection, 'msg_set_selection')
def build_panel(self):
self._iren = MyRenderWindowInteractor(self, wx.ID_ANY, size=self.GetSize())
......@@ -200,6 +198,7 @@ class MolecularViewerPanel(ComponentPlugin):
self._iren.Bind(wx.EVT_CONTEXT_MENU, self.on_show_popup_menu)
pub.subscribe(self.msg_set_selection, 'msg_set_selection')
pub.subscribe(self.msg_switch_viewers_state, "msg_switch_viewers_state")
pub.subscribe(self.msg_clear_selection,'msg_clear_selection')
......
#MDANSE : Molecular Dynamics Analysis for Neutron Scattering Experiments
#------------------------------------------------------------------------------------------
#Copyright (C)
#2015- Eric C. Pellegrini Institut Laue-Langevin
#BP 156
#6, rue Jules Horowitz
#38042 Grenoble Cedex 9
#France
#pellegrini[at]ill.fr
#goret[at]ill.fr
#aoun[at]ill.fr
#
#This library is free software; you can redistribute it and/or
#modify it under the terms of the GNU Lesser General Public
#License as published by the Free Software Foundation; either
#version 2.1 of the License, or (at your option) any later version.
#
#This library is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
#Lesser General Public License for more details.
#
#You should have received a copy of the GNU Lesser General Public
#License along with this library; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
'''
Created on Jul 2, 2015
:author: Eric C. Pellegrini
'''
import operator
import os
import wx
import wx.aui as wxaui
import wx.grid as wxgrid
from MDANSE import LOGGER
from MDANSE.Framework.Widgets.UserDefinitionWidget import UserDefinitionsPlugin
class PartialChargesPlugin(UserDefinitionsPlugin):
type = 'partial_charges'
label = "Partial charges"
ancestor = ["molecular_viewer"]
def __init__(self, parent, *args, **kwargs):
self._parent = parent
self._selectedAtoms = []
UserDefinitionsPlugin.__init__(self, parent)
def build_panel(self):
self._mainPanel = wx.Panel(self,wx.ID_ANY)
sizer = wx.BoxSizer(wx.VERTICAL)
self._grid = wxgrid.Grid(self._mainPanel)
sizer.Add(self._grid, 1, wx.ALL|wx.EXPAND, 5)
self._mainPanel.SetSizer(sizer)
self._mgr.AddPane(self._mainPanel, wxaui.AuiPaneInfo().DestroyOnClose().Center().Dock().CaptionVisible(False).CloseButton(False).BestSize(self.GetSize()))
self._mgr.Update()
def plug(self):
self.parent.mgr.GetPane(self).Float().Dockable(False).CloseButton(True).BestSize((600,600))
self.parent.mgr.Update()
self.set_trajectory(self.dataproxy.data)
def set_trajectory(self,trajectory):
self._trajectory = trajectory
self._target = os.path.basename(self._trajectory.filename)
self._grid.CreateGrid(self._trajectory.universe.numberOfAtoms(),3)
self._grid.SetRowLabelSize(1)
self._grid.SetColFormatNumber(0)
self._grid.SetColFormatNumber(1)
self._grid.SetColFormatNumber(2)
roAttr = wxgrid.GridCellAttr()
roAttr.SetReadOnly(True)
roAttr.SetBackgroundColour(wx.Colour(220,220,220))
self._grid.SetColAttr(0,roAttr)
self._grid.SetColAttr(1,roAttr)
floatAttr = wxgrid.GridCellAttr()
floatAttr.SetRenderer(wxgrid.GridCellFloatRenderer())
floatAttr.SetEditor(wxgrid.GridCellFloatEditor())
self._grid.SetColAttr(2,floatAttr)
self._grid.SetColLabelValue(0,'index')
self._grid.SetColLabelValue(1,'name')
self._grid.SetColLabelValue(2,'charge')
atoms = sorted(self._trajectory.universe.atomList(), key=operator.attrgetter('index'))
for idx, at in enumerate(atoms):
self._grid.SetCellValue(idx,0,str(idx))
self._grid.SetCellValue(idx,1,at.name)
def validate(self):
charges = {}
for i in range(self._trajectory.universe.numberOfAtoms()):
val = self._grid.GetCellValue(i,2)
if val:
charges[i] = float(val)
if not charges:
LOGGER("No partial charges defined.", "error", ["dialog"])
return None
return {'charges' : charges}
\ No newline at end of file
This diff is collapsed.
......@@ -32,56 +32,64 @@ Created on Mar 30, 2015
import wx
from MDANSE import ELEMENTS, LOGGER
from MDANSE import ELEMENTS
from MDANSE.Framework.Widgets.UserDefinitionWidget import UserDefinitionWidget
from MDANSE.Framework.Widgets.AtomSelectionWidget import AtomSelectionPlugin
from MDANSE.Framework.UserDefinitionsStore import UD_STORE
from MDANSE.Framework.Widgets.AtomSelectionWidget import AtomSelectionWidget
from MDANSE.GUI.Icons import ICONS
class AtomTransmutationPlugin(AtomSelectionPlugin):
type = 'atom_transmutation'
label = "Atom transmutation"
ancestor = ["molecular_viewer"]
def build_dialog(self):
AtomSelectionPlugin.build_dialog(self)
self._elements = wx.ComboBox(self._mainPanel, wx.ID_ANY, value="Transmutate to", choices=ELEMENTS.elements)
self._selectionExpressionSizer.Add(self._elements, pos=(0,3), flag=wx.EXPAND|wx.ALIGN_CENTER_VERTICAL)
self._mainPanel.Layout()
def validate(self):
if not self._selection:
LOGGER("The current selection is empty", "error", ["dialog"])
return None
element = self._elements.GetStringSelection()
if not element:
LOGGER("No target element selected to be transmutated to", "error", ["dialog"])
return None
ud = {}
ud['element'] = element
ud['indexes'] = self._selection
return ud
class AtomTransmutationWidget(UserDefinitionWidget):
class AtomTransmutationWidget(AtomSelectionWidget):
type = "atom_transmutation"
udType = "atom_selection"
def get_widget_value(self):
def on_add_definition(self,event):
panel = wx.Panel(self._widgetPanel,wx.ID_ANY)
sizer = wx.BoxSizer(wx.HORIZONTAL)
availableUDs = wx.Choice(panel, wx.ID_ANY,style=wx.CB_SORT)
uds = UD_STORE.filter(self._basename, "atom_selection")
availableUDs.SetItems(uds)
view = wx.Button(panel, wx.ID_ANY, label="View selected definition")
elements = wx.ComboBox(panel, wx.ID_ANY, value="Transmutate to", choices=ELEMENTS.elements)
remove = wx.BitmapButton(panel, wx.ID_ANY, ICONS["minus",16,16])
sizer.Add(availableUDs, 1, wx.ALL|wx.EXPAND, 5)
sizer.Add(view, 0, wx.ALL|wx.EXPAND, 5)
sizer.Add(elements, 0, wx.ALL|wx.EXPAND, 5)
sizer.Add(remove, 0, wx.ALL|wx.EXPAND, 5)
panel.SetSizer(sizer)
ud = self._availableUDs.GetStringSelection()
self._sizer.Add(panel,1,wx.ALL|wx.EXPAND,5)
if not ud:
self._widgetPanel.GrandParent.Layout()
self.Bind(wx.EVT_BUTTON, self.on_view_definition, view)
self.Bind(wx.EVT_BUTTON, self.on_remove_definition, remove)
def get_widget_value(self):
sizerItemList = list(self._sizer.GetChildren())
del sizerItemList[0]
uds = []
for sizerItem in self._sizer.GetChildren():
panel = sizerItem.GetWindow()
children = panel.GetChildren()
udName = children[0]
element = children[1]
oldSelection = udName.GetStringSelection()
udName.SetItems(uds)
udName.SetStringSelection(oldSelection)
uds.append([udName,element.GetStringSelection])
if not uds:
return None
else:
return str(ud)
\ No newline at end of file
return uds
\ No newline at end of file
This diff is collapsed.
......@@ -30,103 +30,11 @@ Created on Jul 2, 2015
:author: Eric C. Pellegrini
'''
import operator
import os
import wx
import wx.aui as wxaui
import wx.grid as wxgrid
from MDANSE import LOGGER
from MDANSE.Framework.Widgets.UserDefinitionWidget import UserDefinitionsPlugin, UserDefinitionsDialog, UserDefinitionWidget
class PartialChargesPlugin(UserDefinitionsPlugin):
type = 'partial_charges'
label = "Partial charges"
ancestor = ["molecular_viewer"]
def __init__(self, parent, *args, **kwargs):
self._parent = parent
self._selectedAtoms = []
UserDefinitionsPlugin.__init__(self, parent)
def build_panel(self):
self._mainPanel = wx.Panel(self,wx.ID_ANY)
sizer = wx.BoxSizer(wx.VERTICAL)
self._grid = wxgrid.Grid(self._mainPanel)
sizer.Add(self._grid, 1, wx.ALL|wx.EXPAND, 5)
self._mainPanel.SetSizer(sizer)
self._mgr.AddPane(self._mainPanel, wxaui.AuiPaneInfo().DestroyOnClose().Center().Dock().CaptionVisible(False).CloseButton(False).BestSize(self.GetSize()))
self._mgr.Update()
def plug(self):
self.parent.mgr.GetPane(self).Float().Dockable(False).CloseButton(True).BestSize((600,600))
self.parent.mgr.Update()
self.set_trajectory(self.dataproxy.data)
def set_trajectory(self,trajectory):
self._trajectory = trajectory
self._target = os.path.basename(self._trajectory.filename)
self._grid.CreateGrid(self._trajectory.universe.numberOfAtoms(),3)
self._grid.SetRowLabelSize(1)
self._grid.SetColFormatNumber(0)
self._grid.SetColFormatNumber(1)
self._grid.SetColFormatNumber(2)
roAttr = wxgrid.GridCellAttr()
roAttr.SetReadOnly(True)
roAttr.SetBackgroundColour(wx.Colour(220,220,220))
self._grid.SetColAttr(0,roAttr)
self._grid.SetColAttr(1,roAttr)
floatAttr = wxgrid.GridCellAttr()
floatAttr.SetRenderer(wxgrid.GridCellFloatRenderer())
floatAttr.SetEditor(wxgrid.GridCellFloatEditor())
self._grid.SetColAttr(2,floatAttr)
self._grid.SetColLabelValue(0,'index')
self._grid.SetColLabelValue(1,'name')
self._grid.SetColLabelValue(2,'charge')
atoms = sorted(self._trajectory.universe.atomList(), key=operator.attrgetter('index'))
for idx, at in enumerate(atoms):
self._grid.SetCellValue(idx,0,str(idx))
self._grid.SetCellValue(idx,1,at.name)
def validate(self):
charges = {}
for i in range(self._trajectory.universe.numberOfAtoms()):
val = self._grid.GetCellValue(i,2)
if val:
charges[i] = float(val)
if not charges:
LOGGER("No partial charges defined.", "error", ["dialog"])
return None
return {'charges' : charges}
from MDANSE.Framework.Widgets.UserDefinitionWidget import UserDefinitionsDialog, UserDefinitionWidget
class PartialChargesWidget(UserDefinitionWidget):
......
This diff is collapsed.
......@@ -43,6 +43,37 @@ from MDANSE.Framework.UserDefinitionsStore import UD_STORE
from MDANSE.Framework.Widgets.IWidget import IWidget
from MDANSE.GUI import DATA_CONTROLLER
class UserDefinitionsDialog(wx.Dialog):
def __init__(self,parent,trajectory,udType,*args,**kwargs):
wx.Dialog.__init__(self, parent, style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.MINIMIZE_BOX|wx.MAXIMIZE_BOX)
self._mgr = wxaui.AuiManager(self)
self.datakey = trajectory.filename
self._plugin = REGISTRY['plugin'][udType](self,*args,**kwargs)
self.SetTitle(self._plugin.label)
self._plugin.set_trajectory(trajectory)
pub.sendMessage("msg_set_data", plugin=self._plugin)
self.Bind(wx.EVT_CLOSE, self.on_quit)
def on_quit(self, event):
d = wx.MessageDialog(None,'Do you really want to quit ?','Question',wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION)
if d.ShowModal() == wx.ID_YES:
self.Destroy()
@property
def plugin(self):
return self._plugin
class UserDefinitionWidget(IWidget):
__metaclass__ = abc.ABCMeta
......@@ -62,27 +93,28 @@ class UserDefinitionWidget(IWidget):
pub.subscribe(self.msg_set_ud, "msg_set_ud")
self.Bind(wx.EVT_BUTTON, self.on_view_user_definition, viewUD)
self.Bind(wx.EVT_BUTTON, self.on_new_user_definition, newUD)
self.Bind(wx.EVT_BUTTON, self.on_view_definition, viewUD)
self.Bind(wx.EVT_BUTTON, self.on_new_definition, newUD)
return sizer
def on_view_user_definition(self,event):
def on_view_definition(self,event):
ud = self._availableUDs.GetStringSelection()
viewUD = event.GetEventObject()
ud = viewUD.Parent.GetChildren()[0].GetStringSelection()
if not ud:
LOGGER("Please select a user definition","error",["dialog"])
return
from MDANSE.Framework.Plugins.UserDefinitionViewerPlugin import UserDefinitionViewerFrame
from MDANSE.GUI.UserDefinitionViewer import UserDefinitionViewer
f = UserDefinitionViewerFrame(self,ud=[self._basename,self.type,ud])
f = UserDefinitionViewer(self,ud=[self._basename,self.type,ud])
f.Show()
def on_new_user_definition(self,event):
def on_new_definition(self,event):
dlg = UserDefinitionsDialog(self,self._trajectory,self.type)
dlg = UserDefinitionsDialog(None,self._trajectory,self.type)
dlg.ShowModal()
......@@ -99,10 +131,6 @@ class UserDefinitionWidget(IWidget):
self._basename = os.path.basename(self._filename)
self.msg_set_ud()
uds = UD_STORE.filter(self._basename, self.type)
self._availableUDs.SetItems(uds)
def msg_set_ud(self):
......@@ -110,37 +138,6 @@ class UserDefinitionWidget(IWidget):
self._availableUDs.SetItems(uds)
class UserDefinitionsDialog(wx.Dialog):
def __init__(self,parent,trajectory,udType,*args,**kwargs):
wx.Dialog.__init__(self, parent)
self._mgr = wxaui.AuiManager(self)
self.datakey = trajectory.filename
self._plugin = REGISTRY['plugin'][udType](self,*args,**kwargs)
self.SetTitle(self._plugin.label)
self._plugin.set_trajectory(trajectory)
pub.sendMessage("msg_set_data", plugin=self._plugin)
self.Bind(wx.EVT_CLOSE, self.on_quit)
def on_quit(self, event):
d = wx.MessageDialog(None,'Do you really want to quit ?','Question',wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION)
if d.ShowModal() == wx.ID_YES:
self.Destroy()
@property
def plugin(self):
return self._plugin
class UserDefinitionsPlugin(ComponentPlugin):
category = ('User definition',)
......@@ -180,10 +177,12 @@ class UserDefinitionsPlugin(ComponentPlugin):
value = self.validate()
if value is None:
return
return