diff --git a/MDANSE/Src/MDANSE/Chemistry/H5ChemicalEntity.py b/MDANSE/Src/MDANSE/Chemistry/H5ChemicalEntity.py deleted file mode 100644 index aa5ad9af97..0000000000 --- a/MDANSE/Src/MDANSE/Chemistry/H5ChemicalEntity.py +++ /dev/null @@ -1,239 +0,0 @@ -import abc - -from MDANSE.Chemistry.ChemicalEntity import ( - Atom, - AtomCluster, - Molecule, - Nucleotide, - NucleotideChain, - PeptideChain, - Protein, - Residue, -) - - -class _H5ChemicalEntity(metaclass=abc.ABCMeta): - def __init__(self, h5_file, h5_contents): - self._h5_file = h5_file - - self._h5_contents = h5_contents - - @abc.abstractmethod - def build(self): - pass - - -class H5Atom(_H5ChemicalEntity): - def __init__(self, h5_file, h5_contents, symbol, name, ghost): - super(H5Atom, self).__init__(h5_file, h5_contents) - - self._symbol = symbol - - self._name = name - - self._ghost = ghost - - def build(self): - a = Atom(symbol=self._symbol, name=self._name, ghost=self._ghost) - return a - - -class H5AtomCluster(_H5ChemicalEntity): - def __init__(self, h5_file, h5_contents, atom_indexes, name): - super(H5AtomCluster, self).__init__(h5_file, h5_contents) - - self._atom_indexes = atom_indexes - - self._name = name - - def build(self): - atoms = [] - for atom_index in self._atom_indexes: - h5_atom_instance = eval( - self._h5_contents["atoms"][atom_index], - globals(), - {"self": self, "h5_contents": self._h5_contents}, - ) - atoms.append(h5_atom_instance.build()) - - ac = AtomCluster(self._name, atoms) - - return ac - - -class H5Molecule(_H5ChemicalEntity): - def __init__(self, h5_file, h5_contents, atom_indexes, code, name): - super(H5Molecule, self).__init__(h5_file, h5_contents) - - self._atom_indexes = atom_indexes - - self._code = code - - self._name = name - - def build(self): - mol = Molecule(self._code, self._name) - - atoms = [] - for atom_index in self._atom_indexes: - h5_atom_instance = eval( - self._h5_contents["atoms"][atom_index], - globals(), - {"self": self, "h5_contents": self._h5_contents}, - ) - atom = h5_atom_instance.build() - atom.parent = mol - atoms.append(atom) - - atom_names = [at.name for at in atoms] - mol.reorder_atoms(atom_names) - - for i, at in enumerate(mol.atom_list): - at.ghost = atoms[i].ghost - - return mol - - -class H5Residue(_H5ChemicalEntity): - def __init__(self, h5_file, h5_contents, atom_indexes, code, name, variant): - super(H5Residue, self).__init__(h5_file, h5_contents) - - self._atom_indexes = atom_indexes - - self._code = code - - self._name = name - - self._variant = variant - - def build(self): - res = Residue(self._code, self._name, self._variant) - - atoms = [] - for atom_index in self._atom_indexes: - h5_atom_instance = eval( - self._h5_contents["atoms"][atom_index], - globals(), - {"self": self, "h5_contents": self._h5_contents}, - ) - atom = h5_atom_instance.build() - atom.parent = res - atoms.append(atom) - - atoms = [at.name for at in atoms] - res.set_atoms(atoms) - - return res - - -class H5Nucleotide(_H5ChemicalEntity): - def __init__(self, h5_file, h5_contents, atom_indexes, code, name, variant): - super(H5Nucleotide, self).__init__(h5_file, h5_contents) - - self._atom_indexes = atom_indexes - - self._code = code - - self._name = name - - self._variant = variant - - def build(self): - nucl = Nucleotide(self._code, self._name, self._variant) - - atoms = [] - for atom_index in self._atom_indexes: - h5_atom_instance = eval( - self._h5_contents["atoms"][atom_index], - globals(), - {"self": self, "h5_contents": self._h5_contents}, - ) - atom = h5_atom_instance.build() - atom.parent = nucl - atoms.append(atom) - - atoms = [at.name for at in atoms] - nucl.set_atoms(atoms) - - return nucl - - -class H5PeptideChain(_H5ChemicalEntity): - def __init__(self, h5_file, h5_contents, name, res_indexes): - super(H5PeptideChain, self).__init__(h5_file, h5_contents) - - self._name = name - - self._res_indexes = res_indexes - - def build(self): - pc = PeptideChain(self._name) - - residues = [] - for res_index in self._res_indexes: - h5_residue_instance = eval( - self._h5_contents["residues"][res_index], - globals(), - {"self": self, "h5_contents": self._h5_contents}, - ) - res = h5_residue_instance.build() - res.parent = pc - residues.append(res) - - pc.set_residues(residues) - - return pc - - -class H5NucleotideChain(_H5ChemicalEntity): - def __init__(self, h5_file, h5_contents, name, nucl_indexes): - super(H5NucleotideChain, self).__init__(h5_file, h5_contents) - - self._name = name - - self._nucl_indexes = nucl_indexes - - def build(self): - nc = NucleotideChain(self._name) - - nucleotides = [] - for nucl_index in self._nucl_indexes: - h5_nucleotide_instance = eval( - self._h5_contents["nucleotides"][nucl_index], - globals(), - {"self": self, "h5_contents": self._h5_contents}, - ) - nucl = h5_nucleotide_instance.build() - nucl.parent = nc - nucleotides.append(nucl) - - nc.set_nucleotides(nucleotides) - - return nc - - -class H5Protein(_H5ChemicalEntity): - def __init__(self, h5_file, h5_contents, name, peptide_chain_indexes): - super(H5Protein, self).__init__(h5_file, h5_contents) - - self._name = name - - self._peptide_chain_indexes = peptide_chain_indexes - - def build(self): - p = Protein(self._name) - - peptide_chains = [] - for pc_index in self._peptide_chain_indexes: - h5_peptide_chain_instance = eval( - self._h5_contents["peptide_chains"][pc_index], - globals(), - {"self": self, "h5_contents": self._h5_contents}, - ) - pc = h5_peptide_chain_instance.build() - pc.parent = p - peptide_chains.append(pc) - - p.set_peptide_chains(peptide_chains) - - return p diff --git a/MDANSE/Src/MDANSE/Core/Decorators.py b/MDANSE/Src/MDANSE/Core/Decorators.py deleted file mode 100644 index 645cd23b37..0000000000 --- a/MDANSE/Src/MDANSE/Core/Decorators.py +++ /dev/null @@ -1,9 +0,0 @@ -import abc -import sys - - -def compatibleabstractproperty(func): - if sys.version_info > (3, 3): - return property(abc.abstractmethod(func)) - else: - return abc.abstractproperty(func) diff --git a/MDANSE/Src/MDANSE/Externals/__init__.py b/MDANSE/Src/MDANSE/Externals/__init__.py deleted file mode 100644 index d00465fca3..0000000000 --- a/MDANSE/Src/MDANSE/Externals/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/Externals/__init__.py -# @brief Implements module/class/test __init__ -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** diff --git a/MDANSE/Src/MDANSE/Externals/svgfig/__init__.py b/MDANSE/Src/MDANSE/Externals/svgfig/__init__.py deleted file mode 100644 index 64590f302c..0000000000 --- a/MDANSE/Src/MDANSE/Externals/svgfig/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/Externals/svgfig/__init__.py -# @brief Implements module/class/test __init__ -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** diff --git a/MDANSE/Src/MDANSE/Externals/svgfig/svgfig.py b/MDANSE/Src/MDANSE/Externals/svgfig/svgfig.py deleted file mode 100644 index ce143c679e..0000000000 --- a/MDANSE/Src/MDANSE/Externals/svgfig/svgfig.py +++ /dev/null @@ -1,4676 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/Externals/svgfig/svgfig.py -# @brief Implements module/class/test svgfig -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -# svgfig.py copyright (C) 2008 Jim Pivarski -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -# -# Full licence is in the file COPYING and at http://www.gnu.org/copyleft/gpl.html - -import re, codecs, os, platform, copy, itertools, math, cmath, random, sys, copy - -_epsilon = 1e-5 - - -if re.search("windows", platform.system(), re.I): - try: - import winreg - - _default_directory = winreg.QueryValueEx( - winreg.OpenKey( - winreg.HKEY_CURRENT_USER, - r"Software\Microsoft\Windows\Current Version\Explorer\Shell Folders", - ), - "Desktop", - )[0] - # tmpdir = _winreg.QueryValueEx(_winreg.OpenKey(_winreg.HKEY_CURRENT_USER, "Environment"), "TEMP")[0] - # if tmpdir[0:13] != "%USERPROFILE%": - # tmpdir = os.path.expanduser("~") + tmpdir[13:] - except: - _default_directory = os.path.expanduser("~") + os.sep + "Desktop" - -_default_fileName = "tmp.svg" - -_hacks = {} -_hacks["inkscape-text-vertical-shift"] = False - - -def rgb(r, g, b, maximum=1.0): - """Create an SVG color string "#xxyyzz" from r, g, and b. - - r,g,b = 0 is black and r,g,b = maximum is white. - """ - return "#%02x%02x%02x" % ( - max(0, min(r * 255.0 / maximum, 255)), - max(0, min(g * 255.0 / maximum, 255)), - max(0, min(b * 255.0 / maximum, 255)), - ) - - -def attr_preprocess(attr): - for name in list(attr.keys()): - name_colon = re.sub("__", ":", name) - if name_colon != name: - attr[name_colon] = attr[name] - del attr[name] - name = name_colon - - name_dash = re.sub("_", "-", name) - if name_dash != name: - attr[name_dash] = attr[name] - del attr[name] - name = name_dash - - return attr - - -class SVG: - """A tree representation of an SVG image or image fragment. - - SVG(t, sub, sub, sub..., attribute=value) - - t required SVG type name - sub optional list nested SVG elements or text/Unicode - attribute=value pairs optional keywords SVG attributes - - In attribute names, "__" becomes ":" and "_" becomes "-". - - SVG in XML - - - - - - - SVG in Python - - >>> svg = SVG("g", SVG("rect", x=1, y=1, width=2, height=2), \ - ... SVG("rect", x=3, y=3, width=2, height=2), \ - ... id="mygroup", fill="blue") - - Sub-elements and attributes may be accessed through tree-indexing: - - >>> svg = SVG("text", SVG("tspan", "hello there"), stroke="none", fill="black") - >>> svg[0] - - >>> svg[0, 0] - 'hello there' - >>> svg["fill"] - 'black' - - Iteration is depth-first: - - >>> svg = SVG("g", SVG("g", SVG("line", x1=0, y1=0, x2=1, y2=1)), \ - ... SVG("text", SVG("tspan", "hello again"))) - ... - >>> for ti, s in svg: - ... print ti, repr(s) - ... - (0,) - (0, 0) - (0, 0, 'x2') 1 - (0, 0, 'y1') 0 - (0, 0, 'x1') 0 - (0, 0, 'y2') 1 - (1,) - (1, 0) - (1, 0, 0) 'hello again' - - Use "print" to navigate: - - >>> print svg - None - [0] - [0, 0] - [1] - [1, 0] - """ - - def __init__(self, *t_sub, **attr): - if len(t_sub) == 0: - raise TypeError("SVG element must have a t (SVG type)") - - # first argument is t (SVG type) - self.t = t_sub[0] - # the rest are sub-elements - self.sub = list(t_sub[1:]) - - # keyword arguments are attributes - # need to preprocess to handle differences between SVG and Python syntax - self.attr = attr_preprocess(attr) - - def __getitem__(self, ti): - """Index is a list that descends tree, returning a sub-element if - it ends with a number and an attribute if it ends with a string.""" - obj = self - if isinstance(ti, (list, tuple)): - for i in ti[:-1]: - obj = obj[i] - ti = ti[-1] - - if isinstance(ti, (int, slice)): - return obj.sub[ti] - else: - return obj.attr[ti] - - def __setitem__(self, ti, value): - """Index is a list that descends tree, returning a sub-element if - it ends with a number and an attribute if it ends with a string.""" - obj = self - if isinstance(ti, (list, tuple)): - for i in ti[:-1]: - obj = obj[i] - ti = ti[-1] - - if isinstance(ti, (int, slice)): - obj.sub[ti] = value - else: - obj.attr[ti] = value - - def __delitem__(self, ti): - """Index is a list that descends tree, returning a sub-element if - it ends with a number and an attribute if it ends with a string.""" - obj = self - if isinstance(ti, (list, tuple)): - for i in ti[:-1]: - obj = obj[i] - ti = ti[-1] - - if isinstance(ti, (int, slice)): - del obj.sub[ti] - else: - del obj.attr[ti] - - def __contains__(self, value): - """x in svg == True iff x is an attribute in svg.""" - return value in self.attr - - def __eq__(self, other): - """x == y iff x represents the same SVG as y.""" - if id(self) == id(other): - return True - return ( - isinstance(other, SVG) - and self.t == other.t - and self.sub == other.sub - and self.attr == other.attr - ) - - def __ne__(self, other): - """x != y iff x does not represent the same SVG as y.""" - return not (self == other) - - def append(self, x): - """Appends x to the list of sub-elements (drawn last, overlaps - other primatives).""" - self.sub.append(x) - - def prepend(self, x): - """Prepends x to the list of sub-elements (drawn first may be - overlapped by other primatives).""" - self.sub[0:0] = [x] - - def extend(self, x): - """Extends list of sub-elements by a list x.""" - self.sub.extend(x) - - def clone(self, shallow=False): - """Deep copy of SVG tree. Set shallow=True for a shallow copy.""" - if shallow: - return copy.copy(self) - else: - return copy.deepcopy(self) - - ### nested class - class SVGDepthIterator: - """Manages SVG iteration.""" - - def __init__(self, svg, ti, depth_limit): - self.svg = svg - self.ti = ti - self.shown = False - self.depth_limit = depth_limit - - def __iter__(self): - return self - - def __next__(self): - if not self.shown: - self.shown = True - if self.ti != (): - return self.ti, self.svg - - if not isinstance(self.svg, SVG): - raise StopIteration - if self.depth_limit != None and len(self.ti) >= self.depth_limit: - raise StopIteration - - if "iterators" not in self.__dict__: - self.iterators = [] - for i, s in enumerate(self.svg.sub): - self.iterators.append( - self.__class__(s, self.ti + (i,), self.depth_limit) - ) - for k, s in list(self.svg.attr.items()): - self.iterators.append( - self.__class__(s, self.ti + (k,), self.depth_limit) - ) - self.iterators = itertools.chain(*self.iterators) - - return next(self.iterators) - - ### end nested class - - def depth_first(self, depth_limit=None): - """Returns a depth-first generator over the SVG. If depth_limit - is a number, stop recursion at that depth.""" - return self.SVGDepthIterator(self, (), depth_limit) - - def breadth_first(self, depth_limit=None): - """Not implemented yet. Any ideas on how to do it? - - Returns a breadth-first generator over the SVG. If depth_limit - is a number, stop recursion at that depth.""" - raise NotImplementedError( - "Got an algorithm for breadth-first searching a tree without effectively copying the tree?" - ) - - def __iter__(self): - return self.depth_first() - - def items(self, sub=True, attr=True, text=True): - """Get a recursively-generated list of tree-index, sub-element/attribute pairs. - - If sub == False, do not show sub-elements. - If attr == False, do not show attributes. - If text == False, do not show text/Unicode sub-elements. - """ - output = [] - for ti, s in self: - show = False - if isinstance(ti[-1], int): - if isinstance(s, str): - show = text - else: - show = sub - else: - show = attr - - if show: - output.append((ti, s)) - return output - - def keys(self, sub=True, attr=True, text=True): - """Get a recursively-generated list of tree-indexes. - - If sub == False, do not show sub-elements. - If attr == False, do not show attributes. - If text == False, do not show text/Unicode sub-elements. - """ - return [ti for ti, s in self.items(sub, attr, text)] - - def values(self, sub=True, attr=True, text=True): - """Get a recursively-generated list of sub-elements and attributes. - - If sub == False, do not show sub-elements. - If attr == False, do not show attributes. - If text == False, do not show text/Unicode sub-elements. - """ - return [s for ti, s in self.items(sub, attr, text)] - - def __repr__(self): - return self.xml(depth_limit=0) - - def __str__(self): - """Print (actually, return a string of) the tree in a form useful for browsing.""" - return self.tree(sub=True, attr=False, text=False) - - def tree( - self, - depth_limit=None, - sub=True, - attr=True, - text=True, - tree_width=20, - obj_width=80, - ): - """Print (actually, return a string of) the tree in a form useful for browsing. - - If depth_limit == a number, stop recursion at that depth. - If sub == False, do not show sub-elements. - If attr == False, do not show attributes. - If text == False, do not show text/Unicode sub-elements. - tree_width is the number of characters reserved for printing tree indexes. - obj_width is the number of characters reserved for printing sub-elements/attributes. - """ - - output = [] - - line = "%s %s" % ( - ("%%-%ds" % tree_width) % repr(None), - ("%%-%ds" % obj_width) % (repr(self))[0:obj_width], - ) - output.append(line) - - for ti, s in self.depth_first(depth_limit): - show = False - if isinstance(ti[-1], int): - if isinstance(s, str): - show = text - else: - show = sub - else: - show = attr - - if show: - line = "%s %s" % ( - ("%%-%ds" % tree_width) % repr(list(ti)), - ("%%-%ds" % obj_width) % (" " * len(ti) + repr(s))[0:obj_width], - ) - output.append(line) - - return "\n".join(output) - - def xml(self, indent=" ", newl="\n", depth_limit=None, depth=0): - """Get an XML representation of the SVG. - - indent string used for indenting - newl string used for newlines - If depth_limit == a number, stop recursion at that depth. - depth starting depth (not useful for users) - - print svg.xml() - """ - - attrstr = [] - for n, v in list(self.attr.items()): - if isinstance(v, dict): - v = "; ".join(["%s:%s" % (ni, vi) for ni, vi in list(v.items())]) - elif isinstance(v, (list, tuple)): - v = ", ".join(v) - attrstr.append(" %s=%s" % (n, repr(v))) - attrstr = "".join(attrstr) - - if len(self.sub) == 0: - return "%s<%s%s />" % (indent * depth, self.t, attrstr) - - if depth_limit == None or depth_limit > depth: - substr = [] - for s in self.sub: - if isinstance(s, SVG): - substr.append(s.xml(indent, newl, depth_limit, depth + 1) + newl) - elif isinstance(s, str): - substr.append("%s%s%s" % (indent * (depth + 1), s, newl)) - else: - substr.append("%s%s%s" % (indent * (depth + 1), repr(s), newl)) - substr = "".join(substr) - - return "%s<%s%s>%s%s%s" % ( - indent * depth, - self.t, - attrstr, - newl, - substr, - indent * depth, - self.t, - ) - - else: - return "%s<%s (%d sub)%s />" % ( - indent * depth, - self.t, - len(self.sub), - attrstr, - ) - - def standalone_xml(self, indent=" ", newl="\n"): - """Get an XML representation of the SVG that can be saved/rendered. - - indent string used for indenting - newl string used for newlines - """ - - if self.t == "svg": - top = self - else: - top = canvas(self) - return """\ - - - -""" + ( - "".join(top.__standalone_xml(indent, newl)) - ) # end of return statement - - def __standalone_xml(self, indent, newl): - output = ["<%s" % self.t] - - for n, v in list(self.attr.items()): - if isinstance(v, dict): - v = "; ".join(["%s:%s" % (ni, vi) for ni, vi in list(v.items())]) - elif isinstance(v, (list, tuple)): - v = ", ".join(v) - output.append(' %s="%s"' % (n, v)) - - if len(self.sub) == 0: - output.append(" />%s%s" % (newl, newl)) - return output - - elif self.t == "text" or self.t == "tspan" or self.t == "style": - output.append(">") - - else: - output.append(">%s%s" % (newl, newl)) - - for s in self.sub: - if isinstance(s, SVG): - output.extend(s.__standalone_xml(indent, newl)) - else: - output.append(str(s)) - - if self.t == "tspan": - output.append("" % self.t) - else: - output.append("%s%s" % (self.t, newl, newl)) - - return output - - def interpret_fileName(self, fileName=None): - if fileName == None: - fileName = _default_fileName - if re.search("windows", platform.system(), re.I) and not os.path.isabs( - fileName - ): - fileName = _default_directory + os.sep + fileName - return fileName - - def save(self, fileName=None, encoding="utf-8", compresslevel=None): - """Save to a file for viewing. Note that svg.save() overwrites the file named _default_fileName. - - fileName default=None note that _default_fileName will be overwritten if - no fileName is specified. If the extension - is ".svgz" or ".gz", the output will be gzipped - encoding default="utf-8" file encoding (default is Unicode) - compresslevel default=None if a number, the output will be gzipped with that - compression level (1-9, 1 being fastest and 9 most - thorough) - """ - fileName = self.interpret_fileName(fileName) - - if ( - compresslevel != None - or re.search("\.svgz$", fileName, re.I) - or re.search("\.gz$", fileName, re.I) - ): - import gzip - - if compresslevel == None: - f = gzip.GzipFile(fileName, "w") - else: - f = gzip.GzipFile(fileName, "w", compresslevel) - - f = codecs.EncodedFile(f, "utf-8", encoding) - f.write(self.standalone_xml()) - f.close() - - else: - f = codecs.open(fileName, "w", encoding=encoding) - f.write(self.standalone_xml()) - f.close() - - def inkview(self, fileName=None, encoding="utf-8"): - """View in "inkview", assuming that program is available on your system. - - fileName default=None note that any file named _default_fileName will be - overwritten if no fileName is specified. If the extension - is ".svgz" or ".gz", the output will be gzipped - encoding default="utf-8" file encoding (default is Unicode) - """ - fileName = self.interpret_fileName(fileName) - self.save(fileName, encoding) - os.spawnvp(os.P_NOWAIT, "inkview", ("inkview", fileName)) - - def inkscape(self, fileName=None, encoding="utf-8"): - """View in "inkscape", assuming that program is available on your system. - - fileName default=None note that any file named _default_fileName will be - overwritten if no fileName is specified. If the extension - is ".svgz" or ".gz", the output will be gzipped - encoding default="utf-8" file encoding (default is Unicode) - """ - fileName = self.interpret_fileName(fileName) - self.save(fileName, encoding) - os.spawnvp(os.P_NOWAIT, "inkscape", ("inkscape", fileName)) - - def firefox(self, fileName=None, encoding="utf-8"): - """View in "firefox", assuming that program is available on your system. - - fileName default=None note that any file named _default_fileName will be - overwritten if no fileName is specified. If the extension - is ".svgz" or ".gz", the output will be gzipped - encoding default="utf-8" file encoding (default is Unicode) - """ - fileName = self.interpret_fileName(fileName) - self.save(fileName, encoding) - os.spawnvp(os.P_NOWAIT, "firefox", ("firefox", fileName)) - - -###################################################################### - -_canvas_defaults = { - "width": "400px", - "height": "400px", - "viewBox": "0 0 100 100", - "xmlns": "http://www.w3.org/2000/svg", - "xmlns:xlink": "http://www.w3.org/1999/xlink", - "version": "1.1", - "style": { - "stroke": "black", - "fill": "none", - "stroke-width": "0.5pt", - "stroke-linejoin": "round", - "text-anchor": "middle", - }, - "font-family": ["Helvetica", "Arial", "FreeSans", "Sans", "sans", "sans-serif"], -} - - -def canvas(*sub, **attr): - """Creates a top-level SVG object, allowing the user to control the - image size and aspect ratio. - - canvas(sub, sub, sub..., attribute=value) - - sub optional list nested SVG elements or text/Unicode - attribute=value pairs optional keywords SVG attributes - - Default attribute values: - - width "400px" - height "400px" - viewBox "0 0 100 100" - xmlns "http://www.w3.org/2000/svg" - xmlns:xlink "http://www.w3.org/1999/xlink" - version "1.1" - style "stroke:black; fill:none; stroke-width:0.5pt; stroke-linejoin:round; text-anchor:middle" - font-family "Helvetica,Arial,FreeSans?,Sans,sans,sans-serif" - """ - attributes = dict(_canvas_defaults) - attributes.update(attr) - - if sub == None or sub == (): - return SVG("svg", **attributes) - else: - return SVG("svg", *sub, **attributes) - - -def canvas_outline(*sub, **attr): - """Same as canvas(), but draws an outline around the drawable area, - so that you know how close your image is to the edges.""" - svg = canvas(*sub, **attr) - match = re.match( - "[, \t]*([0-9e.+\-]+)[, \t]+([0-9e.+\-]+)[, \t]+([0-9e.+\-]+)[, \t]+([0-9e.+\-]+)[, \t]*", - svg["viewBox"], - ) - if match == None: - raise ValueError("canvas viewBox is incorrectly formatted") - x, y, width, height = [float(x) for x in match.groups()] - svg.prepend( - SVG( - "rect", x=x, y=y, width=width, height=height, stroke="none", fill="cornsilk" - ) - ) - svg.append( - SVG("rect", x=x, y=y, width=width, height=height, stroke="black", fill="none") - ) - return svg - - -def template(fileName, svg, replaceme="REPLACEME"): - """Loads an SVG image from a file, replacing instances of - with a given svg object. - - fileName required name of the template SVG - svg required SVG object for replacement - replaceme default="REPLACEME" fake SVG element to be replaced by the given object - - >>> print load("template.svg") - None - >>> - >>> print template("template.svg", SVG("circle", cx=50, cy=50, r=30)) - None - """ - output = load(fileName) - for ti, s in output: - if isinstance(s, SVG) and s.t == replaceme: - output[ti] = svg - return output - - -###################################################################### - - -def load(fileName): - """Loads an SVG image from a file.""" - return load_stream(file(fileName)) - - -def load_stream(stream): - """Loads an SVG image from a stream (can be a string or a file object).""" - - from xml.sax import handler, make_parser - from xml.sax.handler import ( - feature_namespaces, - feature_external_ges, - feature_external_pes, - ) - - class ContentHandler(handler.ContentHandler): - def __init__(self): - self.stack = [] - self.output = None - self.all_whitespace = re.compile("^\s*$") - - def startElement(self, name, attr): - s = SVG(name) - s.attr = dict(list(attr.items())) - if len(self.stack) > 0: - last = self.stack[-1] - last.sub.append(s) - self.stack.append(s) - - def characters(self, ch): - if not isinstance(ch, str) or self.all_whitespace.match(ch) == None: - if len(self.stack) > 0: - last = self.stack[-1] - if len(last.sub) > 0 and isinstance(last.sub[-1], str): - last.sub[-1] = last.sub[-1] + "\n" + ch - else: - last.sub.append(ch) - - def endElement(self, name): - if len(self.stack) > 0: - last = self.stack[-1] - if ( - isinstance(last, SVG) - and last.t == "style" - and "type" in last.attr - and last.attr["type"] == "text/css" - and len(last.sub) == 1 - and isinstance(last.sub[0], str) - ): - last.sub[0] = "" - - self.output = self.stack.pop() - - ch = ContentHandler() - parser = make_parser() - parser.setContentHandler(ch) - parser.setFeature(feature_namespaces, 0) - parser.setFeature(feature_external_ges, 0) - parser.parse(stream) - return ch.output - - -###################################################################### - - -def totrans(expr, vars=("x", "y"), globals=None, locals=None): - """Converts to a coordinate transformation (a function that accepts - two arguments and returns two values). - - expr required a string expression or a function - of two real or one complex value - vars default=("x", "y") independent variable names; - a singleton ("z",) is interpreted - as complex - globals default=None dict of global variables - locals default=None dict of local variables - """ - - if callable(expr): - if expr.__code__.co_argcount == 2: - return expr - - elif expr.__code__.co_argcount == 1: - split = lambda z: (z.real, z.imag) - output = lambda x, y: split(expr(x + y * 1j)) - output.__name__ = expr.__name__ - return output - - else: - raise TypeError("must be a function of 2 or 1 variables") - - if len(vars) == 2: - g = math.__dict__ - if globals != None: - g.update(globals) - output = eval("lambda %s, %s: (%s)" % (vars[0], vars[1], expr), g, locals) - output.__name__ = "%s,%s -> %s" % (vars[0], vars[1], expr) - return output - - elif len(vars) == 1: - g = cmath.__dict__ - if globals != None: - g.update(globals) - output = eval("lambda %s: (%s)" % (vars[0], expr), g, locals) - split = lambda z: (z.real, z.imag) - output2 = lambda x, y: split(output(x + y * 1j)) - output2.__name__ = "%s -> %s" % (vars[0], expr) - return output2 - - else: - raise TypeError("vars must have 2 or 1 elements") - - -def window( - xmin, - xmax, - ymin, - ymax, - x=0, - y=0, - width=100, - height=100, - xlogbase=None, - ylogbase=None, - minusInfinity=-1000, - flipx=False, - flipy=True, -): - """Creates and returns a coordinate transformation (a function that - accepts two arguments and returns two values) that transforms from - (xmin, ymin), (xmax, ymax) - to - (x, y), (x + width, y + height). - - xlogbase, ylogbase default=None, None if a number, transform - logarithmically with given base - minusInfinity default=-1000 what to return if - log(0 or negative) is attempted - flipx default=False if true, reverse the direction of x - flipy default=True if true, reverse the direction of y - - (When composing windows, be sure to set flipy=False.) - """ - - if flipx: - ox1 = x + width - ox2 = x - else: - ox1 = x - ox2 = x + width - if flipy: - oy1 = y + height - oy2 = y - else: - oy1 = y - oy2 = y + height - ix1 = xmin - iy1 = ymin - ix2 = xmax - iy2 = ymax - - if xlogbase != None and (ix1 <= 0.0 or ix2 <= 0.0): - raise ValueError("x range incompatible with log scaling: (%g, %g)" % (ix1, ix2)) - - if ylogbase != None and (iy1 <= 0.0 or iy2 <= 0.0): - raise ValueError("y range incompatible with log scaling: (%g, %g)" % (iy1, iy2)) - - def maybelog(t, it1, it2, ot1, ot2, logbase): - if t <= 0.0: - return minusInfinity - else: - return ot1 + 1.0 * (math.log(t, logbase) - math.log(it1, logbase)) / ( - math.log(it2, logbase) - math.log(it1, logbase) - ) * (ot2 - ot1) - - xlogstr, ylogstr = "", "" - - if xlogbase == None: - xfunc = lambda x: ox1 + 1.0 * (x - ix1) / (ix2 - ix1) * (ox2 - ox1) - else: - xfunc = lambda x: maybelog(x, ix1, ix2, ox1, ox2, xlogbase) - xlogstr = " xlog=%g" % xlogbase - - if ylogbase == None: - yfunc = lambda y: oy1 + 1.0 * (y - iy1) / (iy2 - iy1) * (oy2 - oy1) - else: - yfunc = lambda y: maybelog(y, iy1, iy2, oy1, oy2, ylogbase) - ylogstr = " ylog=%g" % ylogbase - - output = lambda x, y: (xfunc(x), yfunc(y)) - - output.__name__ = "(%g, %g), (%g, %g) -> (%g, %g), (%g, %g)%s%s" % ( - ix1, - ix2, - iy1, - iy2, - ox1, - ox2, - oy1, - oy2, - xlogstr, - ylogstr, - ) - return output - - -def rotate(angle, cx=0, cy=0): - """Creates and returns a coordinate transformation which rotates - around (cx,cy) by "angle" degrees.""" - angle *= math.pi / 180.0 - return lambda x, y: ( - cx + math.cos(angle) * (x - cx) - math.sin(angle) * (y - cy), - cy + math.sin(angle) * (x - cx) + math.cos(angle) * (y - cy), - ) - - -class Fig: - """Stores graphics primitive objects and applies a single coordinate - transformation to them. To compose coordinate systems, nest Fig - objects. - - Fig(obj, obj, obj..., trans=function) - - obj optional list a list of drawing primatives - trans default=None a coordinate transformation function - - >>> fig = Fig(Line(0,0,1,1), Rect(0.2,0.2,0.8,0.8), trans="2*x, 2*y") - >>> print fig.SVG().xml() - - - - - >>> print Fig(fig, trans="x/2., y/2.").SVG().xml() - - - - - """ - - def __repr__(self): - if self.trans == None: - return "" % len(self.d) - elif isinstance(self.trans, str): - return " %s>" % (len(self.d), self.trans) - else: - return "" % (len(self.d), self.trans.__name__) - - def __init__(self, *d, **kwds): - self.d = list(d) - defaults = {"trans": None} - defaults.update(kwds) - kwds = defaults - - self.trans = kwds["trans"] - del kwds["trans"] - if len(kwds) != 0: - raise TypeError( - "Fig() got unexpected keyword arguments %s" % list(kwds.keys()) - ) - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object. - - Coordinate transformations in nested Figs will be composed. - """ - - if trans == None: - trans = self.trans - if isinstance(trans, str): - trans = totrans(trans) - - output = SVG("g") - for s in self.d: - if isinstance(s, SVG): - output.append(s) - - elif isinstance(s, Fig): - strans = s.trans - if isinstance(strans, str): - strans = totrans(strans) - - if trans == None: - subtrans = strans - elif strans == None: - subtrans = trans - else: - subtrans = lambda x, y: trans(*strans(x, y)) - - output.sub += s.SVG(subtrans).sub - - elif s == None: - pass - - else: - output.append(s.SVG(trans)) - - return output - - -class Plot: - """Acts like Fig, but draws a coordinate axis. You also need to supply plot ranges. - - Plot(xmin, xmax, ymin, ymax, obj, obj, obj..., keyword options...) - - xmin, xmax required minimum and maximum x values (in the objs' coordinates) - ymin, ymax required minimum and maximum y values (in the objs' coordinates) - obj optional list drawing primatives - keyword options keyword list options defined below - - The following are keyword options, with their default values: - - trans None transformation function - x, y 5, 5 upper-left corner of the Plot in SVG coordinates - width, height 90, 90 width and height of the Plot in SVG coordinates - flipx, flipy False, True flip the sign of the coordinate axis - minusInfinity -1000 if an axis is logarithmic and an object is plotted at 0 or - a negative value, -1000 will be used as a stand-in for NaN - atx, aty 0, 0 the place where the coordinate axes cross - xticks -10 request ticks according to the standard tick specification - (see help(Ticks)) - xminiticks True request miniticks according to the standard minitick - specification - xlabels True request tick labels according to the standard tick label - specification - xlogbase None if a number, the axis and transformation are logarithmic - with ticks at the given base (10 being the most common) - (same for y) - arrows None if a new identifier, create arrow markers and draw them - at the ends of the coordinate axes - text_attr {} a dictionary of attributes for label text - axis_attr {} a dictionary of attributes for the axis lines - """ - - def __repr__(self): - if self.trans == None: - return "" % len(self.d) - else: - return "" % (len(self.d), self.trans.__name__) - - def __init__(self, xmin, xmax, ymin, ymax, *d, **kwds): - self.xmin, self.xmax, self.ymin, self.ymax = xmin, xmax, ymin, ymax - self.d = list(d) - defaults = { - "trans": None, - "x": 5, - "y": 5, - "width": 90, - "height": 90, - "flipx": False, - "flipy": True, - "minusInfinity": -1000, - "atx": 0, - "xticks": -10, - "xminiticks": True, - "xlabels": True, - "xlogbase": None, - "aty": 0, - "yticks": -10, - "yminiticks": True, - "ylabels": True, - "ylogbase": None, - "arrows": None, - "text_attr": {}, - "axis_attr": {}, - } - defaults.update(kwds) - kwds = defaults - - self.trans = kwds["trans"] - del kwds["trans"] - self.x = kwds["x"] - del kwds["x"] - self.y = kwds["y"] - del kwds["y"] - self.width = kwds["width"] - del kwds["width"] - self.height = kwds["height"] - del kwds["height"] - self.flipx = kwds["flipx"] - del kwds["flipx"] - self.flipy = kwds["flipy"] - del kwds["flipy"] - self.minusInfinity = kwds["minusInfinity"] - del kwds["minusInfinity"] - self.atx = kwds["atx"] - del kwds["atx"] - self.xticks = kwds["xticks"] - del kwds["xticks"] - self.xminiticks = kwds["xminiticks"] - del kwds["xminiticks"] - self.xlabels = kwds["xlabels"] - del kwds["xlabels"] - self.xlogbase = kwds["xlogbase"] - del kwds["xlogbase"] - self.aty = kwds["aty"] - del kwds["aty"] - self.yticks = kwds["yticks"] - del kwds["yticks"] - self.yminiticks = kwds["yminiticks"] - del kwds["yminiticks"] - self.ylabels = kwds["ylabels"] - del kwds["ylabels"] - self.ylogbase = kwds["ylogbase"] - del kwds["ylogbase"] - self.arrows = kwds["arrows"] - del kwds["arrows"] - self.text_attr = kwds["text_attr"] - del kwds["text_attr"] - self.axis_attr = kwds["axis_attr"] - del kwds["axis_attr"] - if len(kwds) != 0: - raise TypeError( - "Plot() got unexpected keyword arguments %s" % list(kwds.keys()) - ) - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - if trans == None: - trans = self.trans - if isinstance(trans, str): - trans = totrans(trans) - - self.last_window = window( - self.xmin, - self.xmax, - self.ymin, - self.ymax, - x=self.x, - y=self.y, - width=self.width, - height=self.height, - xlogbase=self.xlogbase, - ylogbase=self.ylogbase, - minusInfinity=self.minusInfinity, - flipx=self.flipx, - flipy=self.flipy, - ) - - d = [ - Axes( - self.xmin, - self.xmax, - self.ymin, - self.ymax, - self.atx, - self.aty, - self.xticks, - self.xminiticks, - self.xlabels, - self.xlogbase, - self.yticks, - self.yminiticks, - self.ylabels, - self.ylogbase, - self.arrows, - self.text_attr, - **self.axis_attr, - ) - ] + self.d - - return Fig(Fig(*d, **{"trans": trans})).SVG(self.last_window) - - -class Frame: - text_defaults = {"stroke": "none", "fill": "black", "font-size": 5} - axis_defaults = {} - - tick_length = 1.5 - minitick_length = 0.75 - text_xaxis_offset = 1.0 - text_yaxis_offset = 2.0 - text_xtitle_offset = 6.0 - text_ytitle_offset = 12.0 - - def __repr__(self): - return "" % len(self.d) - - def __init__(self, xmin, xmax, ymin, ymax, *d, **kwds): - """Acts like Fig, but draws a coordinate frame around the data. You also need to supply plot ranges. - - Frame(xmin, xmax, ymin, ymax, obj, obj, obj..., keyword options...) - - xmin, xmax required minimum and maximum x values (in the objs' coordinates) - ymin, ymax required minimum and maximum y values (in the objs' coordinates) - obj optional list drawing primatives - keyword options keyword list options defined below - - The following are keyword options, with their default values: - - x, y 20, 5 upper-left corner of the Frame in SVG coordinates - width, height 75, 80 width and height of the Frame in SVG coordinates - flipx, flipy False, True flip the sign of the coordinate axis - minusInfinity -1000 if an axis is logarithmic and an object is plotted at 0 or - a negative value, -1000 will be used as a stand-in for NaN - xtitle None if a string, label the x axis - xticks -10 request ticks according to the standard tick specification - (see help(Ticks)) - xminiticks True request miniticks according to the standard minitick - specification - xlabels True request tick labels according to the standard tick label - specification - xlogbase None if a number, the axis and transformation are logarithmic - with ticks at the given base (10 being the most common) - (same for y) - text_attr {} a dictionary of attributes for label text - axis_attr {} a dictionary of attributes for the axis lines - """ - - self.xmin, self.xmax, self.ymin, self.ymax = xmin, xmax, ymin, ymax - self.d = list(d) - defaults = { - "x": 20, - "y": 5, - "width": 75, - "height": 80, - "flipx": False, - "flipy": True, - "minusInfinity": -1000, - "xtitle": None, - "xticks": -10, - "xminiticks": True, - "xlabels": True, - "x2labels": None, - "xlogbase": None, - "ytitle": None, - "yticks": -10, - "yminiticks": True, - "ylabels": True, - "y2labels": None, - "ylogbase": None, - "text_attr": {}, - "axis_attr": {}, - } - defaults.update(kwds) - kwds = defaults - - self.x = kwds["x"] - del kwds["x"] - self.y = kwds["y"] - del kwds["y"] - self.width = kwds["width"] - del kwds["width"] - self.height = kwds["height"] - del kwds["height"] - self.flipx = kwds["flipx"] - del kwds["flipx"] - self.flipy = kwds["flipy"] - del kwds["flipy"] - self.minusInfinity = kwds["minusInfinity"] - del kwds["minusInfinity"] - self.xtitle = kwds["xtitle"] - del kwds["xtitle"] - self.xticks = kwds["xticks"] - del kwds["xticks"] - self.xminiticks = kwds["xminiticks"] - del kwds["xminiticks"] - self.xlabels = kwds["xlabels"] - del kwds["xlabels"] - self.x2labels = kwds["x2labels"] - del kwds["x2labels"] - self.xlogbase = kwds["xlogbase"] - del kwds["xlogbase"] - self.ytitle = kwds["ytitle"] - del kwds["ytitle"] - self.yticks = kwds["yticks"] - del kwds["yticks"] - self.yminiticks = kwds["yminiticks"] - del kwds["yminiticks"] - self.ylabels = kwds["ylabels"] - del kwds["ylabels"] - self.y2labels = kwds["y2labels"] - del kwds["y2labels"] - self.ylogbase = kwds["ylogbase"] - del kwds["ylogbase"] - - self.text_attr = dict(self.text_defaults) - self.text_attr.update(kwds["text_attr"]) - del kwds["text_attr"] - - self.axis_attr = dict(self.axis_defaults) - self.axis_attr.update(kwds["axis_attr"]) - del kwds["axis_attr"] - - if len(kwds) != 0: - raise TypeError( - "Frame() got unexpected keyword arguments %s" % list(kwds.keys()) - ) - - def SVG(self): - """Apply the window transformation and return an SVG object.""" - - self.last_window = window( - self.xmin, - self.xmax, - self.ymin, - self.ymax, - x=self.x, - y=self.y, - width=self.width, - height=self.height, - xlogbase=self.xlogbase, - ylogbase=self.ylogbase, - minusInfinity=self.minusInfinity, - flipx=self.flipx, - flipy=self.flipy, - ) - - left = YAxis( - self.ymin, - self.ymax, - self.xmin, - self.yticks, - self.yminiticks, - self.ylabels, - self.ylogbase, - None, - None, - None, - self.text_attr, - **self.axis_attr, - ) - right = YAxis( - self.ymin, - self.ymax, - self.xmax, - self.yticks, - self.yminiticks, - self.y2labels, - self.ylogbase, - None, - None, - None, - self.text_attr, - **self.axis_attr, - ) - bottom = XAxis( - self.xmin, - self.xmax, - self.ymin, - self.xticks, - self.xminiticks, - self.xlabels, - self.xlogbase, - None, - None, - None, - self.text_attr, - **self.axis_attr, - ) - top = XAxis( - self.xmin, - self.xmax, - self.ymax, - self.xticks, - self.xminiticks, - self.x2labels, - self.xlogbase, - None, - None, - None, - self.text_attr, - **self.axis_attr, - ) - - left.tick_start = -self.tick_length - left.tick_end = 0 - left.minitick_start = -self.minitick_length - left.minitick_end = 0.0 - left.text_start = self.text_yaxis_offset - - right.tick_start = 0.0 - right.tick_end = self.tick_length - right.minitick_start = 0.0 - right.minitick_end = self.minitick_length - right.text_start = -self.text_yaxis_offset - right.text_attr["text-anchor"] = "start" - - bottom.tick_start = 0.0 - bottom.tick_end = self.tick_length - bottom.minitick_start = 0.0 - bottom.minitick_end = self.minitick_length - bottom.text_start = -self.text_xaxis_offset - - top.tick_start = -self.tick_length - top.tick_end = 0.0 - top.minitick_start = -self.minitick_length - top.minitick_end = 0.0 - top.text_start = self.text_xaxis_offset - top.text_attr["dominant-baseline"] = "text-after-edge" - - output = Fig(*self.d).SVG(self.last_window) - output.prepend(left.SVG(self.last_window)) - output.prepend(bottom.SVG(self.last_window)) - output.prepend(right.SVG(self.last_window)) - output.prepend(top.SVG(self.last_window)) - - if self.xtitle != None: - output.append( - SVG( - "text", - self.xtitle, - transform="translate(%g, %g)" - % ( - (self.x + self.width / 2.0), - (self.y + self.height + self.text_xtitle_offset), - ), - dominant_baseline="text-before-edge", - **self.text_attr, - ) - ) - if self.ytitle != None: - output.append( - SVG( - "text", - self.ytitle, - transform="translate(%g, %g) rotate(-90)" - % ( - (self.x - self.text_ytitle_offset), - (self.y + self.height / 2.0), - ), - **self.text_attr, - ) - ) - return output - - -###################################################################### - - -def pathtoPath(svg): - """Converts SVG("path", d="...") into Path(d=[...]).""" - if not isinstance(svg, SVG) or svg.t != "path": - raise TypeError("Only SVG objects can be converted into Paths") - attr = dict(svg.attr) - d = attr["d"] - del attr["d"] - for key in list(attr.keys()): - if not isinstance(key, str): - value = attr[key] - del attr[key] - attr[str(key)] = value - return Path(d, **attr) - - -class Path: - """Path represents an SVG path, an arbitrary set of curves and - straight segments. Unlike SVG("path", d="..."), Path stores - coordinates as a list of numbers, rather than a string, so that it is - transformable in a Fig. - - Path(d, attribute=value) - - d required path data - attribute=value pairs keyword list SVG attributes - - See http://www.w3.org/TR/SVG/paths.html for specification of paths - from text. - - Internally, Path data is a list of tuples with these definitions: - - * ("Z/z",): close the current path - * ("H/h", x) or ("V/v", y): a horizontal or vertical line - segment to x or y - * ("M/m/L/l/T/t", x, y, global): moveto, lineto, or smooth - quadratic curveto point (x, y). If global=True, (x, y) should - not be transformed. - * ("S/sQ/q", cx, cy, cglobal, x, y, global): polybezier or - smooth quadratic curveto point (x, y) using (cx, cy) as a - control point. If cglobal or global=True, (cx, cy) or (x, y) - should not be transformed. - * ("C/c", c1x, c1y, c1global, c2x, c2y, c2global, x, y, global): - cubic curveto point (x, y) using (c1x, c1y) and (c2x, c2y) as - control points. If c1global, c2global, or global=True, (c1x, c1y), - (c2x, c2y), or (x, y) should not be transformed. - * ("A/a", rx, ry, rglobal, x-axis-rotation, angle, large-arc-flag, - sweep-flag, x, y, global): arcto point (x, y) using the - aforementioned parameters. - * (",/.", rx, ry, rglobal, angle, x, y, global): an ellipse at - point (x, y) with radii (rx, ry). If angle is 0, the whole - ellipse is drawn; otherwise, a partial ellipse is drawn. - """ - - defaults = {} - - def __repr__(self): - return "" % (len(self.d), self.attr) - - def __init__(self, d=[], **attr): - if isinstance(d, str): - self.d = self.parse(d) - else: - self.d = list(d) - - self.attr = dict(self.defaults) - self.attr.update(attr) - - def parse_whitespace(self, index, pathdata): - """Part of Path's text-command parsing algorithm; used internally.""" - while index < len(pathdata) and pathdata[index] in (" ", "\t", "\r", "\n", ","): - index += 1 - return index, pathdata - - def parse_command(self, index, pathdata): - """Part of Path's text-command parsing algorithm; used internally.""" - index, pathdata = self.parse_whitespace(index, pathdata) - - if index >= len(pathdata): - return None, index, pathdata - command = pathdata[index] - if "A" <= command <= "Z" or "a" <= command <= "z": - index += 1 - return command, index, pathdata - else: - return None, index, pathdata - - def parse_number(self, index, pathdata): - """Part of Path's text-command parsing algorithm; used internally.""" - index, pathdata = self.parse_whitespace(index, pathdata) - - if index >= len(pathdata): - return None, index, pathdata - first_digit = pathdata[index] - - if "0" <= first_digit <= "9" or first_digit in ("-", "+", "."): - start = index - while index < len(pathdata) and ( - "0" <= pathdata[index] <= "9" - or pathdata[index] in ("-", "+", ".", "e", "E") - ): - index += 1 - end = index - - index = end - return float(pathdata[start:end]), index, pathdata - else: - return None, index, pathdata - - def parse_boolean(self, index, pathdata): - """Part of Path's text-command parsing algorithm; used internally.""" - index, pathdata = self.parse_whitespace(index, pathdata) - - if index >= len(pathdata): - return None, index, pathdata - first_digit = pathdata[index] - - if first_digit in ("0", "1"): - index += 1 - return int(first_digit), index, pathdata - else: - return None, index, pathdata - - def parse(self, pathdata): - """Parses text-commands, converting them into a list of tuples. - Called by the constructor.""" - output = [] - index = 0 - while True: - command, index, pathdata = self.parse_command(index, pathdata) - index, pathdata = self.parse_whitespace(index, pathdata) - - if command == None and index == len(pathdata): - break # this is the normal way out of the loop - if command in ("Z", "z"): - output.append((command,)) - - ###################### - elif command in ("H", "h", "V", "v"): - errstring = 'Path command "%s" requires a number at index %d' % ( - command, - index, - ) - num1, index, pathdata = self.parse_number(index, pathdata) - if num1 == None: - raise ValueError(errstring) - - while num1 != None: - output.append((command, num1)) - num1, index, pathdata = self.parse_number(index, pathdata) - - ###################### - elif command in ("M", "m", "L", "l", "T", "t"): - errstring = 'Path command "%s" requires an x,y pair at index %d' % ( - command, - index, - ) - num1, index, pathdata = self.parse_number(index, pathdata) - num2, index, pathdata = self.parse_number(index, pathdata) - - if num1 == None: - raise ValueError(errstring) - - while num1 != None: - if num2 == None: - raise ValueError(errstring) - output.append((command, num1, num2, False)) - - num1, index, pathdata = self.parse_number(index, pathdata) - num2, index, pathdata = self.parse_number(index, pathdata) - - ###################### - elif command in ("S", "s", "Q", "q"): - errstring = ( - 'Path command "%s" requires a cx,cy,x,y quadruplet at index %d' - % (command, index) - ) - num1, index, pathdata = self.parse_number(index, pathdata) - num2, index, pathdata = self.parse_number(index, pathdata) - num3, index, pathdata = self.parse_number(index, pathdata) - num4, index, pathdata = self.parse_number(index, pathdata) - - if num1 == None: - raise ValueError(errstring) - - while num1 != None: - if num2 == None or num3 == None or num4 == None: - raise ValueError(errstring) - output.append((command, num1, num2, False, num3, num4, False)) - - num1, index, pathdata = self.parse_number(index, pathdata) - num2, index, pathdata = self.parse_number(index, pathdata) - num3, index, pathdata = self.parse_number(index, pathdata) - num4, index, pathdata = self.parse_number(index, pathdata) - - ###################### - elif command in ("C", "c"): - errstring = ( - 'Path command "%s" requires a c1x,c1y,c2x,c2y,x,y sextuplet at index %d' - % (command, index) - ) - num1, index, pathdata = self.parse_number(index, pathdata) - num2, index, pathdata = self.parse_number(index, pathdata) - num3, index, pathdata = self.parse_number(index, pathdata) - num4, index, pathdata = self.parse_number(index, pathdata) - num5, index, pathdata = self.parse_number(index, pathdata) - num6, index, pathdata = self.parse_number(index, pathdata) - - if num1 == None: - raise ValueError(errstring) - - while num1 != None: - if ( - num2 == None - or num3 == None - or num4 == None - or num5 == None - or num6 == None - ): - raise ValueError(errstring) - - output.append( - ( - command, - num1, - num2, - False, - num3, - num4, - False, - num5, - num6, - False, - ) - ) - - num1, index, pathdata = self.parse_number(index, pathdata) - num2, index, pathdata = self.parse_number(index, pathdata) - num3, index, pathdata = self.parse_number(index, pathdata) - num4, index, pathdata = self.parse_number(index, pathdata) - num5, index, pathdata = self.parse_number(index, pathdata) - num6, index, pathdata = self.parse_number(index, pathdata) - - ###################### - elif command in ("A", "a"): - errstring = ( - 'Path command "%s" requires a rx,ry,angle,large-arc-flag,sweep-flag,x,y septuplet at index %d' - % (command, index) - ) - num1, index, pathdata = self.parse_number(index, pathdata) - num2, index, pathdata = self.parse_number(index, pathdata) - num3, index, pathdata = self.parse_number(index, pathdata) - num4, index, pathdata = self.parse_boolean(index, pathdata) - num5, index, pathdata = self.parse_boolean(index, pathdata) - num6, index, pathdata = self.parse_number(index, pathdata) - num7, index, pathdata = self.parse_number(index, pathdata) - - if num1 == None: - raise ValueError(errstring) - - while num1 != None: - if ( - num2 == None - or num3 == None - or num4 == None - or num5 == None - or num6 == None - or num7 == None - ): - raise ValueError(errstring) - - output.append( - ( - command, - num1, - num2, - False, - num3, - num4, - num5, - num6, - num7, - False, - ) - ) - - num1, index, pathdata = self.parse_number(index, pathdata) - num2, index, pathdata = self.parse_number(index, pathdata) - num3, index, pathdata = self.parse_number(index, pathdata) - num4, index, pathdata = self.parse_boolean(index, pathdata) - num5, index, pathdata = self.parse_boolean(index, pathdata) - num6, index, pathdata = self.parse_number(index, pathdata) - num7, index, pathdata = self.parse_number(index, pathdata) - - return output - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - if isinstance(trans, str): - trans = totrans(trans) - - x, y, X, Y = None, None, None, None - output = [] - for datum in self.d: - if not isinstance(datum, (tuple, list)): - raise TypeError("pathdata elements must be tuples/lists") - - command = datum[0] - - ###################### - if command in ("Z", "z"): - x, y, X, Y = None, None, None, None - output.append("Z") - - ###################### - elif command in ("H", "h", "V", "v"): - command, num1 = datum - - if command == "H" or (command == "h" and x == None): - x = num1 - elif command == "h": - x += num1 - elif command == "V" or (command == "v" and y == None): - y = num1 - elif command == "v": - y += num1 - - if trans == None: - X, Y = x, y - else: - X, Y = trans(x, y) - - output.append("L%g %g" % (X, Y)) - - ###################### - elif command in ("M", "m", "L", "l", "T", "t"): - command, num1, num2, isglobal12 = datum - - if trans == None or isglobal12: - if command.isupper() or X == None or Y == None: - X, Y = num1, num2 - else: - X += num1 - Y += num2 - x, y = X, Y - - else: - if command.isupper() or x == None or y == None: - x, y = num1, num2 - else: - x += num1 - y += num2 - X, Y = trans(x, y) - - COMMAND = command.capitalize() - output.append("%s%g %g" % (COMMAND, X, Y)) - - ###################### - elif command in ("S", "s", "Q", "q"): - command, num1, num2, isglobal12, num3, num4, isglobal34 = datum - - if trans == None or isglobal12: - if command.isupper() or X == None or Y == None: - CX, CY = num1, num2 - else: - CX = X + num1 - CY = Y + num2 - - else: - if command.isupper() or x == None or y == None: - cx, cy = num1, num2 - else: - cx = x + num1 - cy = y + num2 - CX, CY = trans(cx, cy) - - if trans == None or isglobal34: - if command.isupper() or X == None or Y == None: - X, Y = num3, num4 - else: - X += num3 - Y += num4 - x, y = X, Y - - else: - if command.isupper() or x == None or y == None: - x, y = num3, num4 - else: - x += num3 - y += num4 - X, Y = trans(x, y) - - COMMAND = command.capitalize() - output.append("%s%g %g %g %g" % (COMMAND, CX, CY, X, Y)) - - ###################### - elif command in ("C", "c"): - ( - command, - num1, - num2, - isglobal12, - num3, - num4, - isglobal34, - num5, - num6, - isglobal56, - ) = datum - - if trans == None or isglobal12: - if command.isupper() or X == None or Y == None: - C1X, C1Y = num1, num2 - else: - C1X = X + num1 - C1Y = Y + num2 - - else: - if command.isupper() or x == None or y == None: - c1x, c1y = num1, num2 - else: - c1x = x + num1 - c1y = y + num2 - C1X, C1Y = trans(c1x, c1y) - - if trans == None or isglobal34: - if command.isupper() or X == None or Y == None: - C2X, C2Y = num3, num4 - else: - C2X = X + num3 - C2Y = Y + num4 - - else: - if command.isupper() or x == None or y == None: - c2x, c2y = num3, num4 - else: - c2x = x + num3 - c2y = y + num4 - C2X, C2Y = trans(c2x, c2y) - - if trans == None or isglobal56: - if command.isupper() or X == None or Y == None: - X, Y = num5, num6 - else: - X += num5 - Y += num6 - x, y = X, Y - - else: - if command.isupper() or x == None or y == None: - x, y = num5, num6 - else: - x += num5 - y += num6 - X, Y = trans(x, y) - - COMMAND = command.capitalize() - output.append( - "%s%g %g %g %g %g %g" % (COMMAND, C1X, C1Y, C2X, C2Y, X, Y) - ) - - ###################### - elif command in ("A", "a"): - ( - command, - num1, - num2, - isglobal12, - angle, - large_arc_flag, - sweep_flag, - num3, - num4, - isglobal34, - ) = datum - - oldx, oldy = x, y - OLDX, OLDY = X, Y - - if trans == None or isglobal34: - if command.isupper() or X == None or Y == None: - X, Y = num3, num4 - else: - X += num3 - Y += num4 - x, y = X, Y - - else: - if command.isupper() or x == None or y == None: - x, y = num3, num4 - else: - x += num3 - y += num4 - X, Y = trans(x, y) - - if x != None and y != None: - centerx, centery = (x + oldx) / 2.0, (y + oldy) / 2.0 - CENTERX, CENTERY = (X + OLDX) / 2.0, (Y + OLDY) / 2.0 - - if trans == None or isglobal12: - RX = CENTERX + num1 - RY = CENTERY + num2 - - else: - rx = centerx + num1 - ry = centery + num2 - RX, RY = trans(rx, ry) - - COMMAND = command.capitalize() - output.append( - "%s%g %g %g %d %d %g %g" - % ( - COMMAND, - RX - CENTERX, - RY - CENTERY, - angle, - large_arc_flag, - sweep_flag, - X, - Y, - ) - ) - - elif command in (",", "."): - command, num1, num2, isglobal12, angle, num3, num4, isglobal34 = datum - if trans == None or isglobal34: - if command == "." or X == None or Y == None: - X, Y = num3, num4 - else: - X += num3 - Y += num4 - x, y = None, None - - else: - if command == "." or x == None or y == None: - x, y = num3, num4 - else: - x += num3 - y += num4 - X, Y = trans(x, y) - - if trans == None or isglobal12: - RX = X + num1 - RY = Y + num2 - - else: - rx = x + num1 - ry = y + num2 - RX, RY = trans(rx, ry) - - RX, RY = RX - X, RY - Y - - X1, Y1 = X + RX * math.cos(angle * math.pi / 180.0), Y + RX * math.sin( - angle * math.pi / 180.0 - ) - X2, Y2 = X + RY * math.sin(angle * math.pi / 180.0), Y - RY * math.cos( - angle * math.pi / 180.0 - ) - X3, Y3 = X - RX * math.cos(angle * math.pi / 180.0), Y - RX * math.sin( - angle * math.pi / 180.0 - ) - X4, Y4 = X - RY * math.sin(angle * math.pi / 180.0), Y + RY * math.cos( - angle * math.pi / 180.0 - ) - - output.append( - "M%g %gA%g %g %g 0 0 %g %gA%g %g %g 0 0 %g %gA%g %g %g 0 0 %g %gA%g %g %g 0 0 %g %g" - % ( - X1, - Y1, - RX, - RY, - angle, - X2, - Y2, - RX, - RY, - angle, - X3, - Y3, - RX, - RY, - angle, - X4, - Y4, - RX, - RY, - angle, - X1, - Y1, - ) - ) - - return SVG("path", d="".join(output), **self.attr) - - -###################################################################### - - -def funcRtoC(expr, var="t", globals=None, locals=None): - """Converts a complex "z(t)" string to a function acceptable for Curve. - - expr required string in the form "z(t)" - var default="t" name of the independent variable - globals default=None dict of global variables used in the expression; - you may want to use Python's builtin globals() - locals default=None dict of local variables - """ - g = cmath.__dict__ - if globals != None: - g.update(globals) - output = eval("lambda %s: (%s)" % (var, expr), g, locals) - split = lambda z: (z.real, z.imag) - output2 = lambda t: split(output(t)) - output2.__name__ = "%s -> %s" % (var, expr) - return output2 - - -def funcRtoR2(expr, var="t", globals=None, locals=None): - """Converts a "f(t), g(t)" string to a function acceptable for Curve. - - expr required string in the form "f(t), g(t)" - var default="t" name of the independent variable - globals default=None dict of global variables used in the expression; - you may want to use Python's builtin globals() - locals default=None dict of local variables - """ - g = math.__dict__ - if globals != None: - g.update(globals) - output = eval("lambda %s: (%s)" % (var, expr), g, locals) - output.__name__ = "%s -> %s" % (var, expr) - return output - - -def funcRtoR(expr, var="x", globals=None, locals=None): - """Converts a "f(x)" string to a function acceptable for Curve. - - expr required string in the form "f(x)" - var default="x" name of the independent variable - globals default=None dict of global variables used in the expression; - you may want to use Python's builtin globals() - locals default=None dict of local variables - """ - g = math.__dict__ - if globals != None: - g.update(globals) - output = eval("lambda %s: (%s, %s)" % (var, var, expr), g, locals) - output.__name__ = "%s -> %s" % (var, expr) - return output - - -class Curve: - """Draws a parametric function as a path. - - Curve(f, low, high, loop, attribute=value) - - f required a Python callable or string in - the form "f(t), g(t)" - low, high required left and right endpoints - loop default=False if True, connect the endpoints - attribute=value pairs keyword list SVG attributes - """ - - defaults = {} - random_sampling = True - recursion_limit = 15 - linearity_limit = 0.05 - discontinuity_limit = 5.0 - - def __repr__(self): - return "" % (self.f, self.low, self.high, self.attr) - - def __init__(self, f, low, high, loop=False, **attr): - self.f = f - self.low = low - self.high = high - self.loop = loop - - self.attr = dict(self.defaults) - self.attr.update(attr) - - ### nested class Sample - class Sample: - def __repr__(self): - t, x, y, X, Y = self.t, self.x, self.y, self.X, self.Y - if t != None: - t = "%g" % t - if x != None: - x = "%g" % x - if y != None: - y = "%g" % y - if X != None: - X = "%g" % X - if Y != None: - Y = "%g" % Y - return "" % (t, x, y, X, Y) - - def __init__(self, t): - self.t = t - - def link(self, left, right): - self.left, self.right = left, right - - def evaluate(self, f, trans): - self.x, self.y = f(self.t) - if trans == None: - self.X, self.Y = self.x, self.y - else: - self.X, self.Y = trans(self.x, self.y) - - ### end Sample - - ### nested class Samples - class Samples: - def __repr__(self): - return "" % len(self) - - def __init__(self, left, right): - self.left, self.right = left, right - - def __len__(self): - count = 0 - current = self.left - while current != None: - count += 1 - current = current.right - return count - - def __iter__(self): - self.current = self.left - return self - - def __next__(self): - current = self.current - if current == None: - raise StopIteration - self.current = self.current.right - return current - - ### end nested class - - def sample(self, trans=None): - """Adaptive-sampling algorithm that chooses the best sample points - for a parametric curve between two endpoints and detects - discontinuities. Called by SVG().""" - oldrecursionlimit = sys.getrecursionlimit() - sys.setrecursionlimit(self.recursion_limit + 100) - try: - # the best way to keep all the information while sampling is to make a linked list - if not (self.low < self.high): - raise ValueError("low must be less than high") - low, high = self.Sample(float(self.low)), self.Sample(float(self.high)) - low.link(None, high) - high.link(low, None) - - low.evaluate(self.f, trans) - high.evaluate(self.f, trans) - - # adaptive sampling between the low and high points - self.subsample(low, high, 0, trans) - - # Prune excess points where the curve is nearly linear - left = low - while left.right != None: - # increment mid and right - mid = left.right - right = mid.right - if ( - right != None - and left.X != None - and left.Y != None - and mid.X != None - and mid.Y != None - and right.X != None - and right.Y != None - ): - numer = ( - left.X * (right.Y - mid.Y) - + mid.X * (left.Y - right.Y) - + right.X * (mid.Y - left.Y) - ) - denom = math.sqrt((left.X - right.X) ** 2 + (left.Y - right.Y) ** 2) - if denom != 0.0 and abs(numer / denom) < self.linearity_limit: - # drop mid (the garbage collector will get it) - left.right = right - right.left = left - else: - # increment left - left = left.right - else: - left = left.right - - self.last_samples = self.Samples(low, high) - - finally: - sys.setrecursionlimit(oldrecursionlimit) - - def subsample(self, left, right, depth, trans=None): - """Part of the adaptive-sampling algorithm that chooses the best - sample points. Called by sample().""" - - if self.random_sampling: - mid = self.Sample(left.t + random.uniform(0.3, 0.7) * (right.t - left.t)) - else: - mid = self.Sample(left.t + 0.5 * (right.t - left.t)) - - left.right = mid - right.left = mid - mid.link(left, right) - mid.evaluate(self.f, trans) - - # calculate the distance of closest approach of mid to the line between left and right - numer = ( - left.X * (right.Y - mid.Y) - + mid.X * (left.Y - right.Y) - + right.X * (mid.Y - left.Y) - ) - denom = math.sqrt((left.X - right.X) ** 2 + (left.Y - right.Y) ** 2) - - # if we haven't sampled enough or left fails to be close enough to right, or mid fails to be linear enough... - if ( - depth < 3 - or (denom == 0 and left.t != right.t) - or denom > self.discontinuity_limit - or (denom != 0.0 and abs(numer / denom) > self.linearity_limit) - ): - # and we haven't sampled too many points - if depth < self.recursion_limit: - self.subsample(left, mid, depth + 1, trans) - self.subsample(mid, right, depth + 1, trans) - - else: - # We've sampled many points and yet it's still not a small linear gap. - # Break the line: it's a discontinuity - mid.y = mid.Y = None - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - return self.Path(trans).SVG() - - def Path(self, trans=None, local=False): - """Apply the transformation "trans" and return a Path object in - global coordinates. If local=True, return a Path in local coordinates - (which must be transformed again).""" - - if isinstance(trans, str): - trans = totrans(trans) - if isinstance(self.f, str): - self.f = funcRtoR2(self.f) - - self.sample(trans) - - output = [] - for s in self.last_samples: - if s.X != None and s.Y != None: - if s.left == None or s.left.Y == None: - command = "M" - else: - command = "L" - - if local: - output.append((command, s.x, s.y, False)) - else: - output.append((command, s.X, s.Y, True)) - - if self.loop: - output.append(("Z",)) - return Path(output, **self.attr) - - -###################################################################### - - -class Poly: - """Draws a curve specified by a sequence of points. The curve may be - piecewise linear, like a polygon, or a Bezier curve. - - Poly(d, mode, loop, attribute=value) - - d required list of tuples representing points - and possibly control points - mode default="L" "lines", "bezier", "velocity", - "foreback", "smooth", or an abbreviation - loop default=False if True, connect the first and last - point, closing the loop - attribute=value pairs keyword list SVG attributes - - The format of the tuples in d depends on the mode. - - "lines"/"L" d=[(x,y), (x,y), ...] - piecewise-linear segments joining the (x,y) points - "bezier"/"B" d=[(x, y, c1x, c1y, c2x, c2y), ...] - Bezier curve with two control points (control points - preceed (x,y), as in SVG paths). If (c1x,c1y) and - (c2x,c2y) both equal (x,y), you get a linear - interpolation ("lines") - "velocity"/"V" d=[(x, y, vx, vy), ...] - curve that passes through (x,y) with velocity (vx,vy) - (one unit of arclength per unit time); in other words, - (vx,vy) is the tangent vector at (x,y). If (vx,vy) is - (0,0), you get a linear interpolation ("lines"). - "foreback"/"F" d=[(x, y, bx, by, fx, fy), ...] - like "velocity" except that there is a left derivative - (bx,by) and a right derivative (fx,fy). If (bx,by) - equals (fx,fy) (with no minus sign), you get a - "velocity" curve - "smooth"/"S" d=[(x,y), (x,y), ...] - a "velocity" interpolation with (vx,vy)[i] equal to - ((x,y)[i+1] - (x,y)[i-1])/2: the minimal derivative - """ - - defaults = {} - - def __repr__(self): - return "" % ( - len(self.d), - self.mode, - repr(self.loop), - self.attr, - ) - - def __init__(self, d=[], mode="L", loop=False, **attr): - self.d = list(d) - self.mode = mode - self.loop = loop - - self.attr = dict(self.defaults) - self.attr.update(attr) - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - return self.Path(trans).SVG() - - def Path(self, trans=None, local=False): - """Apply the transformation "trans" and return a Path object in - global coordinates. If local=True, return a Path in local coordinates - (which must be transformed again).""" - if isinstance(trans, str): - trans = totrans(trans) - - if self.mode[0] == "L" or self.mode[0] == "l": - mode = "L" - elif self.mode[0] == "B" or self.mode[0] == "b": - mode = "B" - elif self.mode[0] == "V" or self.mode[0] == "v": - mode = "V" - elif self.mode[0] == "F" or self.mode[0] == "f": - mode = "F" - elif self.mode[0] == "S" or self.mode[0] == "s": - mode = "S" - - vx, vy = [0.0] * len(self.d), [0.0] * len(self.d) - for i in range(len(self.d)): - inext = (i + 1) % len(self.d) - iprev = (i - 1) % len(self.d) - - vx[i] = (self.d[inext][0] - self.d[iprev][0]) / 2.0 - vy[i] = (self.d[inext][1] - self.d[iprev][1]) / 2.0 - if not self.loop and (i == 0 or i == len(self.d) - 1): - vx[i], vy[i] = 0.0, 0.0 - - else: - raise ValueError( - 'mode must be "lines", "bezier", "velocity", "foreback", "smooth", or an abbreviation' - ) - - d = [] - indexes = list(range(len(self.d))) - if self.loop and len(self.d) > 0: - indexes.append(0) - - for i in indexes: - inext = (i + 1) % len(self.d) - iprev = (i - 1) % len(self.d) - - x, y = self.d[i][0], self.d[i][1] - - if trans == None: - X, Y = x, y - else: - X, Y = trans(x, y) - - if d == []: - if local: - d.append(("M", x, y, False)) - else: - d.append(("M", X, Y, True)) - - elif mode == "L": - if local: - d.append(("L", x, y, False)) - else: - d.append(("L", X, Y, True)) - - elif mode == "B": - c1x, c1y = self.d[i][2], self.d[i][3] - if trans == None: - C1X, C1Y = c1x, c1y - else: - C1X, C1Y = trans(c1x, c1y) - - c2x, c2y = self.d[i][4], self.d[i][5] - if trans == None: - C2X, C2Y = c2x, c2y - else: - C2X, C2Y = trans(c2x, c2y) - - if local: - d.append(("C", c1x, c1y, False, c2x, c2y, False, x, y, False)) - else: - d.append(("C", C1X, C1Y, True, C2X, C2Y, True, X, Y, True)) - - elif mode == "V": - c1x, c1y = ( - self.d[iprev][2] / 3.0 + self.d[iprev][0], - self.d[iprev][3] / 3.0 + self.d[iprev][1], - ) - c2x, c2y = self.d[i][2] / -3.0 + x, self.d[i][3] / -3.0 + y - - if trans == None: - C1X, C1Y = c1x, c1y - else: - C1X, C1Y = trans(c1x, c1y) - if trans == None: - C2X, C2Y = c2x, c2y - else: - C2X, C2Y = trans(c2x, c2y) - - if local: - d.append(("C", c1x, c1y, False, c2x, c2y, False, x, y, False)) - else: - d.append(("C", C1X, C1Y, True, C2X, C2Y, True, X, Y, True)) - - elif mode == "F": - c1x, c1y = ( - self.d[iprev][4] / 3.0 + self.d[iprev][0], - self.d[iprev][5] / 3.0 + self.d[iprev][1], - ) - c2x, c2y = self.d[i][2] / -3.0 + x, self.d[i][3] / -3.0 + y - - if trans == None: - C1X, C1Y = c1x, c1y - else: - C1X, C1Y = trans(c1x, c1y) - if trans == None: - C2X, C2Y = c2x, c2y - else: - C2X, C2Y = trans(c2x, c2y) - - if local: - d.append(("C", c1x, c1y, False, c2x, c2y, False, x, y, False)) - else: - d.append(("C", C1X, C1Y, True, C2X, C2Y, True, X, Y, True)) - - elif mode == "S": - c1x, c1y = ( - vx[iprev] / 3.0 + self.d[iprev][0], - vy[iprev] / 3.0 + self.d[iprev][1], - ) - c2x, c2y = vx[i] / -3.0 + x, vy[i] / -3.0 + y - - if trans == None: - C1X, C1Y = c1x, c1y - else: - C1X, C1Y = trans(c1x, c1y) - if trans == None: - C2X, C2Y = c2x, c2y - else: - C2X, C2Y = trans(c2x, c2y) - - if local: - d.append(("C", c1x, c1y, False, c2x, c2y, False, x, y, False)) - else: - d.append(("C", C1X, C1Y, True, C2X, C2Y, True, X, Y, True)) - - if self.loop and len(self.d) > 0: - d.append(("Z",)) - - return Path(d, **self.attr) - - -###################################################################### - - -class Text: - """Draws at text string at a specified point in local coordinates. - - x, y required location of the point in local coordinates - d required text/Unicode string - attribute=value pairs keyword list SVG attributes - """ - - defaults = {"stroke": "none", "fill": "black", "font-size": 5} - - def __repr__(self): - return "" % (repr(self.d), self.x, self.y, self.attr) - - def __init__(self, x, y, d, **attr): - self.x = x - self.y = y - self.d = str(d) - self.attr = dict(self.defaults) - self.attr.update(attr) - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - if isinstance(trans, str): - trans = totrans(trans) - - X, Y = self.x, self.y - if trans != None: - X, Y = trans(X, Y) - return SVG("text", self.d, x=X, y=Y, **self.attr) - - -class TextGlobal: - """Draws at text string at a specified point in global coordinates. - - x, y required location of the point in global coordinates - d required text/Unicode string - attribute=value pairs keyword list SVG attributes - """ - - defaults = {"stroke": "none", "fill": "black", "font-size": 5} - - def __repr__(self): - return "" % ( - repr(self.d), - str(self.x), - str(self.y), - self.attr, - ) - - def __init__(self, x, y, d, **attr): - self.x = x - self.y = y - self.d = str(d) - self.attr = dict(self.defaults) - self.attr.update(attr) - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - return SVG("text", self.d, x=self.x, y=self.y, **self.attr) - - -###################################################################### - -_symbol_templates = { - "dot": SVG( - "symbol", - SVG("circle", cx=0, cy=0, r=1, stroke="none", fill="black"), - viewBox="0 0 1 1", - overflow="visible", - ), - "box": SVG( - "symbol", - SVG("rect", x1=-1, y1=-1, x2=1, y2=1, stroke="none", fill="black"), - viewBox="0 0 1 1", - overflow="visible", - ), - "uptri": SVG( - "symbol", - SVG("path", d="M -1 0.866 L 1 0.866 L 0 -0.866 Z", stroke="none", fill="black"), - viewBox="0 0 1 1", - overflow="visible", - ), - "downtri": SVG( - "symbol", - SVG( - "path", d="M -1 -0.866 L 1 -0.866 L 0 0.866 Z", stroke="none", fill="black" - ), - viewBox="0 0 1 1", - overflow="visible", - ), -} - - -def make_symbol(id, shape="dot", **attr): - """Creates a new instance of an SVG symbol to avoid cross-linking objects. - - id required a new identifier (string/Unicode) - shape default="dot" the shape name from _symbol_templates - attribute=value list keyword list modify the SVG attributes of the new symbol - """ - output = copy.deepcopy(_symbol_templates[shape]) - for i in output.sub: - i.attr.update(attr_preprocess(attr)) - output["id"] = id - return output - - -_circular_dot = make_symbol("circular_dot") - - -class Dots: - """Dots draws SVG symbols at a set of points. - - d required list of (x,y) points - symbol default=None SVG symbol or a new identifier to - label an auto-generated symbol; - if None, use pre-defined _circular_dot - width, height default=1, 1 width and height of the symbols - in SVG coordinates - attribute=value pairs keyword list SVG attributes - """ - - defaults = {} - - def __repr__(self): - return "" % (len(self.d), self.attr) - - def __init__(self, d=[], symbol=None, width=1.0, height=1.0, **attr): - self.d = list(d) - self.width = width - self.height = height - - self.attr = dict(self.defaults) - self.attr.update(attr) - - if symbol == None: - self.symbol = _circular_dot - elif isinstance(symbol, SVG): - self.symbol = symbol - else: - self.symbol = make_symbol(symbol) - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - if isinstance(trans, str): - trans = totrans(trans) - - output = SVG("g", SVG("defs", self.symbol)) - id = "#%s" % self.symbol["id"] - - for p in self.d: - x, y = p[0], p[1] - - if trans == None: - X, Y = x, y - else: - X, Y = trans(x, y) - - item = SVG("use", x=X, y=Y, xlink__href=id) - if self.width != None: - item["width"] = self.width - if self.height != None: - item["height"] = self.height - output.append(item) - - return output - - -###################################################################### - -_marker_templates = { - "arrow_start": SVG( - "marker", - SVG("path", d="M 9 3.6 L 10.5 0 L 0 3.6 L 10.5 7.2 L 9 3.6 Z"), - viewBox="0 0 10.5 7.2", - refX="9", - refY="3.6", - markerWidth="10.5", - markerHeight="7.2", - markerUnits="strokeWidth", - orient="auto", - stroke="none", - fill="black", - ), - "arrow_end": SVG( - "marker", - SVG("path", d="M 1.5 3.6 L 0 0 L 10.5 3.6 L 0 7.2 L 1.5 3.6 Z"), - viewBox="0 0 10.5 7.2", - refX="1.5", - refY="3.6", - markerWidth="10.5", - markerHeight="7.2", - markerUnits="strokeWidth", - orient="auto", - stroke="none", - fill="black", - ), -} - - -def make_marker(id, shape, **attr): - """Creates a new instance of an SVG marker to avoid cross-linking objects. - - id required a new identifier (string/Unicode) - shape required the shape name from _marker_templates - attribute=value list keyword list modify the SVG attributes of the new marker - """ - output = copy.deepcopy(_marker_templates[shape]) - for i in output.sub: - i.attr.update(attr_preprocess(attr)) - output["id"] = id - return output - - -class Line(Curve): - """Draws a line between two points. - - Line(x1, y1, x2, y2, arrow_start, arrow_end, attribute=value) - - x1, y1 required the starting point - x2, y2 required the ending point - arrow_start default=None if an identifier string/Unicode, - draw a new arrow object at the - beginning of the line; if a marker, - draw that marker instead - arrow_end default=None same for the end of the line - attribute=value pairs keyword list SVG attributes - """ - - defaults = {} - - def __repr__(self): - return "" % ( - self.x1, - self.y1, - self.x2, - self.y2, - self.attr, - ) - - def __init__(self, x1, y1, x2, y2, arrow_start=None, arrow_end=None, **attr): - self.x1, self.y1, self.x2, self.y2 = x1, y1, x2, y2 - self.arrow_start, self.arrow_end = arrow_start, arrow_end - - self.attr = dict(self.defaults) - self.attr.update(attr) - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - - line = self.Path(trans).SVG() - - if (self.arrow_start != False and self.arrow_start != None) or ( - self.arrow_end != False and self.arrow_end != None - ): - defs = SVG("defs") - - if self.arrow_start != False and self.arrow_start != None: - if isinstance(self.arrow_start, SVG): - defs.append(self.arrow_start) - line.attr["marker-start"] = "url(#%s)" % self.arrow_start["id"] - elif isinstance(self.arrow_start, str): - defs.append(make_marker(self.arrow_start, "arrow_start")) - line.attr["marker-start"] = "url(#%s)" % self.arrow_start - else: - raise TypeError( - "arrow_start must be False/None or an id string for the new marker" - ) - - if self.arrow_end != False and self.arrow_end != None: - if isinstance(self.arrow_end, SVG): - defs.append(self.arrow_end) - line.attr["marker-end"] = "url(#%s)" % self.arrow_end["id"] - elif isinstance(self.arrow_end, str): - defs.append(make_marker(self.arrow_end, "arrow_end")) - line.attr["marker-end"] = "url(#%s)" % self.arrow_end - else: - raise TypeError( - "arrow_end must be False/None or an id string for the new marker" - ) - - return SVG("g", defs, line) - - return line - - def Path(self, trans=None, local=False): - """Apply the transformation "trans" and return a Path object in - global coordinates. If local=True, return a Path in local coordinates - (which must be transformed again).""" - self.f = lambda t: ( - self.x1 + t * (self.x2 - self.x1), - self.y1 + t * (self.y2 - self.y1), - ) - self.low = 0.0 - self.high = 1.0 - self.loop = False - - if trans == None: - return Path( - [ - ("M", self.x1, self.y1, not local), - ("L", self.x2, self.y2, not local), - ], - **self.attr, - ) - else: - return Curve.Path(self, trans, local) - - -class LineGlobal: - """Draws a line between two points, one or both of which is in - global coordinates. - - Line(x1, y1, x2, y2, lcoal1, local2, arrow_start, arrow_end, attribute=value) - - x1, y1 required the starting point - x2, y2 required the ending point - local1 default=False if True, interpret first point as a - local coordinate (apply transform) - local2 default=False if True, interpret second point as a - local coordinate (apply transform) - arrow_start default=None if an identifier string/Unicode, - draw a new arrow object at the - beginning of the line; if a marker, - draw that marker instead - arrow_end default=None same for the end of the line - attribute=value pairs keyword list SVG attributes - """ - - defaults = {} - - def __repr__(self): - local1, local2 = "", "" - if self.local1: - local1 = "L" - if self.local2: - local2 = "L" - - return "" % ( - local1, - str(self.x1), - str(self.y1), - local2, - str(self.x2), - str(self.y2), - self.attr, - ) - - def __init__( - self, - x1, - y1, - x2, - y2, - local1=False, - local2=False, - arrow_start=None, - arrow_end=None, - **attr, - ): - self.x1, self.y1, self.x2, self.y2 = x1, y1, x2, y2 - self.local1, self.local2 = local1, local2 - self.arrow_start, self.arrow_end = arrow_start, arrow_end - - self.attr = dict(self.defaults) - self.attr.update(attr) - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - if isinstance(trans, str): - trans = totrans(trans) - - X1, Y1, X2, Y2 = self.x1, self.y1, self.x2, self.y2 - - if self.local1: - X1, Y1 = trans(X1, Y1) - if self.local2: - X2, Y2 = trans(X2, Y2) - - line = SVG("path", d="M%s %s L%s %s" % (X1, Y1, X2, Y2), **self.attr) - - if (self.arrow_start != False and self.arrow_start != None) or ( - self.arrow_end != False and self.arrow_end != None - ): - defs = SVG("defs") - - if self.arrow_start != False and self.arrow_start != None: - if isinstance(self.arrow_start, SVG): - defs.append(self.arrow_start) - line.attr["marker-start"] = "url(#%s)" % self.arrow_start["id"] - elif isinstance(self.arrow_start, str): - defs.append(make_marker(self.arrow_start, "arrow_start")) - line.attr["marker-start"] = "url(#%s)" % self.arrow_start - else: - raise TypeError( - "arrow_start must be False/None or an id string for the new marker" - ) - - if self.arrow_end != False and self.arrow_end != None: - if isinstance(self.arrow_end, SVG): - defs.append(self.arrow_end) - line.attr["marker-end"] = "url(#%s)" % self.arrow_end["id"] - elif isinstance(self.arrow_end, str): - defs.append(make_marker(self.arrow_end, "arrow_end")) - line.attr["marker-end"] = "url(#%s)" % self.arrow_end - else: - raise TypeError( - "arrow_end must be False/None or an id string for the new marker" - ) - - return SVG("g", defs, line) - - return line - - -class VLine(Line): - """Draws a vertical line. - - VLine(y1, y2, x, attribute=value) - - y1, y2 required y range - x required x position - attribute=value pairs keyword list SVG attributes - """ - - defaults = {} - - def __repr__(self): - return "" % (self.y1, self.y2, self.x, self.attr) - - def __init__(self, y1, y2, x, **attr): - self.x = x - self.attr = dict(self.defaults) - self.attr.update(attr) - Line.__init__(self, x, y1, x, y2, **self.attr) - - def Path(self, trans=None, local=False): - """Apply the transformation "trans" and return a Path object in - global coordinates. If local=True, return a Path in local coordinates - (which must be transformed again).""" - self.x1 = self.x - self.x2 = self.x - return Line.Path(self, trans, local) - - -class HLine(Line): - """Draws a horizontal line. - - HLine(x1, x2, y, attribute=value) - - x1, x2 required x range - y required y position - attribute=value pairs keyword list SVG attributes - """ - - defaults = {} - - def __repr__(self): - return "" % (self.x1, self.x2, self.y, self.attr) - - def __init__(self, x1, x2, y, **attr): - self.y = y - self.attr = dict(self.defaults) - self.attr.update(attr) - Line.__init__(self, x1, y, x2, y, **self.attr) - - def Path(self, trans=None, local=False): - """Apply the transformation "trans" and return a Path object in - global coordinates. If local=True, return a Path in local coordinates - (which must be transformed again).""" - self.y1 = self.y - self.y2 = self.y - return Line.Path(self, trans, local) - - -###################################################################### - - -class Rect(Curve): - """Draws a rectangle. - - Rect(x1, y1, x2, y2, attribute=value) - - x1, y1 required the starting point - x2, y2 required the ending point - attribute=value pairs keyword list SVG attributes - """ - - defaults = {} - - def __repr__(self): - return "" % ( - self.x1, - self.y1, - self.x2, - self.y2, - self.attr, - ) - - def __init__(self, x1, y1, x2, y2, **attr): - self.x1, self.y1, self.x2, self.y2 = x1, y1, x2, y2 - - self.attr = dict(self.defaults) - self.attr.update(attr) - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - return self.Path(trans).SVG() - - def Path(self, trans=None, local=False): - """Apply the transformation "trans" and return a Path object in - global coordinates. If local=True, return a Path in local coordinates - (which must be transformed again).""" - if trans == None: - return Path( - [ - ("M", self.x1, self.y1, not local), - ("L", self.x2, self.y1, not local), - ("L", self.x2, self.y2, not local), - ("L", self.x1, self.y2, not local), - ("Z",), - ], - **self.attr, - ) - - else: - self.low = 0.0 - self.high = 1.0 - self.loop = False - - self.f = lambda t: (self.x1 + t * (self.x2 - self.x1), self.y1) - d1 = Curve.Path(self, trans, local).d - - self.f = lambda t: (self.x2, self.y1 + t * (self.y2 - self.y1)) - d2 = Curve.Path(self, trans, local).d - del d2[0] - - self.f = lambda t: (self.x2 + t * (self.x1 - self.x2), self.y2) - d3 = Curve.Path(self, trans, local).d - del d3[0] - - self.f = lambda t: (self.x1, self.y2 + t * (self.y1 - self.y2)) - d4 = Curve.Path(self, trans, local).d - del d4[0] - - return Path(d=(d1 + d2 + d3 + d4 + [("Z",)]), **self.attr) - - -###################################################################### - - -class Ellipse(Curve): - """Draws an ellipse from a semimajor vector (ax,ay) and a semiminor - length (b). - - Ellipse(x, y, ax, ay, b, attribute=value) - - x, y required the center of the ellipse/circle - ax, ay required a vector indicating the length - and direction of the semimajor axis - b required the length of the semiminor axis. - If equal to sqrt(ax2 + ay2), the - ellipse is a circle - attribute=value pairs keyword list SVG attributes - - (If sqrt(ax**2 + ay**2) is less than b, then (ax,ay) is actually the - semiminor axis.) - """ - - defaults = {} - - def __repr__(self): - return "" % ( - self.x, - self.y, - self.ax, - self.ay, - self.b, - self.attr, - ) - - def __init__(self, x, y, ax, ay, b, **attr): - self.x, self.y, self.ax, self.ay, self.b = x, y, ax, ay, b - - self.attr = dict(self.defaults) - self.attr.update(attr) - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - return self.Path(trans).SVG() - - def Path(self, trans=None, local=False): - """Apply the transformation "trans" and return a Path object in - global coordinates. If local=True, return a Path in local coordinates - (which must be transformed again).""" - angle = math.atan2(self.ay, self.ax) + math.pi / 2.0 - bx = self.b * math.cos(angle) - by = self.b * math.sin(angle) - - self.f = lambda t: ( - self.x + self.ax * math.cos(t) + bx * math.sin(t), - self.y + self.ay * math.cos(t) + by * math.sin(t), - ) - self.low = -math.pi - self.high = math.pi - self.loop = True - return Curve.Path(self, trans, local) - - -###################################################################### - - -def unumber(x): - """Converts numbers to a Unicode string, taking advantage of special - Unicode characters to make nice minus signs and scientific notation. - """ - output = "%g" % x - - if output[0] == "-": - output = "\u2013" + output[1:] - - index = output.find("e") - if index != -1: - uniout = str(output[:index]) + "\u00d710" - saw_nonzero = False - for n in output[index + 1 :]: - if n == "+": - pass # uniout += u"\u207a" - elif n == "-": - uniout += "\u207b" - elif n == "0": - if saw_nonzero: - uniout += "\u2070" - elif n == "1": - saw_nonzero = True - uniout += "\u00b9" - elif n == "2": - saw_nonzero = True - uniout += "\u00b2" - elif n == "3": - saw_nonzero = True - uniout += "\u00b3" - elif "4" <= n <= "9": - saw_nonzero = True - if saw_nonzero: - uniout += eval('u"\\u%x"' % (0x2070 + ord(n) - ord("0"))) - else: - uniout += n - - if uniout[:2] == "1\u00d7": - uniout = uniout[2:] - return uniout - - return output - - -class Ticks: - """Superclass for all graphics primatives that draw ticks, - miniticks, and tick labels. This class only draws the ticks. - - Ticks(f, low, high, ticks, miniticks, labels, logbase, arrow_start, - arrow_end, text_attr, attribute=value) - - f required parametric function along which ticks - will be drawn; has the same format as - the function used in Curve - low, high required range of the independent variable - ticks default=-10 request ticks according to the standard - tick specification (see below) - miniticks default=True request miniticks according to the - standard minitick specification (below) - labels True request tick labels according to the - standard tick label specification (below) - logbase default=None if a number, the axis is logarithmic with - ticks at the given base (usually 10) - arrow_start default=None if a new string identifier, draw an arrow - at the low-end of the axis, referenced by - that identifier; if an SVG marker object, - use that marker - arrow_end default=None if a new string identifier, draw an arrow - at the high-end of the axis, referenced by - that identifier; if an SVG marker object, - use that marker - text_attr default={} SVG attributes for the text labels - attribute=value pairs keyword list SVG attributes for the tick marks - - Standard tick specification: - - * True: same as -10 (below). - * Positive number N: draw exactly N ticks, including the endpoints. To - subdivide an axis into 10 equal-sized segments, ask for 11 ticks. - * Negative number -N: draw at least N ticks. Ticks will be chosen with - "natural" values, multiples of 2 or 5. - * List of values: draw a tick mark at each value. - * Dict of value, label pairs: draw a tick mark at each value, labeling - it with the given string. This lets you say things like {3.14159: "pi"}. - * False or None: no ticks. - - Standard minitick specification: - - * True: draw miniticks with "natural" values, more closely spaced than - the ticks. - * Positive number N: draw exactly N miniticks, including the endpoints. - To subdivide an axis into 100 equal-sized segments, ask for 101 miniticks. - * Negative number -N: draw at least N miniticks. - * List of values: draw a minitick mark at each value. - * False or None: no miniticks. - - Standard tick label specification: - - * True: use the unumber function (described below) - * Format string: standard format strings, e.g. "%5.2f" for 12.34 - * Python callable: function that converts numbers to strings - * False or None: no labels - """ - - defaults = {"stroke-width": "0.25pt"} - text_defaults = {"stroke": "none", "fill": "black", "font-size": 5} - tick_start = -1.5 - tick_end = 1.5 - minitick_start = -0.75 - minitick_end = 0.75 - text_start = 2.5 - text_angle = 0.0 - - def __repr__(self): - return "" % ( - self.f, - self.low, - self.high, - str(self.ticks), - str(self.labels), - self.attr, - ) - - def __init__( - self, - f, - low, - high, - ticks=-10, - miniticks=True, - labels=True, - logbase=None, - arrow_start=None, - arrow_end=None, - text_attr={}, - **attr, - ): - self.f = f - self.low = low - self.high = high - self.ticks = ticks - self.miniticks = miniticks - self.labels = labels - self.logbase = logbase - self.arrow_start = arrow_start - self.arrow_end = arrow_end - - self.attr = dict(self.defaults) - self.attr.update(attr) - - self.text_attr = dict(self.text_defaults) - self.text_attr.update(text_attr) - - def orient_tickmark(self, t, trans=None): - """Return the position, normalized local x vector, normalized - local y vector, and angle of a tick at position t. - - Normally only used internally. - """ - if isinstance(trans, str): - trans = totrans(trans) - if trans == None: - f = self.f - else: - f = lambda t: trans(*self.f(t)) - - eps = _epsilon * abs(self.high - self.low) - - X, Y = f(t) - Xprime, Yprime = f(t + eps) - xhatx, xhaty = (Xprime - X) / eps, (Yprime - Y) / eps - - norm = math.sqrt(xhatx**2 + xhaty**2) - if norm != 0: - xhatx, xhaty = xhatx / norm, xhaty / norm - else: - xhatx, xhaty = 1.0, 0.0 - - angle = math.atan2(xhaty, xhatx) + math.pi / 2.0 - yhatx, yhaty = math.cos(angle), math.sin(angle) - - return (X, Y), (xhatx, xhaty), (yhatx, yhaty), angle - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - if isinstance(trans, str): - trans = totrans(trans) - - self.last_ticks, self.last_miniticks = self.interpret() - tickmarks = Path([], **self.attr) - minitickmarks = Path([], **self.attr) - output = SVG("g") - - if (self.arrow_start != False and self.arrow_start != None) or ( - self.arrow_end != False and self.arrow_end != None - ): - defs = SVG("defs") - - if self.arrow_start != False and self.arrow_start != None: - if isinstance(self.arrow_start, SVG): - defs.append(self.arrow_start) - elif isinstance(self.arrow_start, str): - defs.append(make_marker(self.arrow_start, "arrow_start")) - else: - raise TypeError( - "arrow_start must be False/None or an id string for the new marker" - ) - - if self.arrow_end != False and self.arrow_end != None: - if isinstance(self.arrow_end, SVG): - defs.append(self.arrow_end) - elif isinstance(self.arrow_end, str): - defs.append(make_marker(self.arrow_end, "arrow_end")) - else: - raise TypeError( - "arrow_end must be False/None or an id string for the new marker" - ) - - output.append(defs) - - eps = _epsilon * (self.high - self.low) - - for t, label in list(self.last_ticks.items()): - (X, Y), (xhatx, xhaty), (yhatx, yhaty), angle = self.orient_tickmark( - t, trans - ) - - if (not self.arrow_start or abs(t - self.low) > eps) and ( - not self.arrow_end or abs(t - self.high) > eps - ): - tickmarks.d.append( - ( - "M", - X - yhatx * self.tick_start, - Y - yhaty * self.tick_start, - True, - ) - ) - tickmarks.d.append( - ("L", X - yhatx * self.tick_end, Y - yhaty * self.tick_end, True) - ) - - angle = (angle - math.pi / 2.0) * 180.0 / math.pi + self.text_angle - - ########### a HACK! ############ (to be removed when Inkscape handles baselines) - if _hacks["inkscape-text-vertical-shift"]: - if self.text_start > 0: - X += math.cos(angle * math.pi / 180.0 + math.pi / 2.0) * 2.0 - Y += math.sin(angle * math.pi / 180.0 + math.pi / 2.0) * 2.0 - else: - X += math.cos(angle * math.pi / 180.0 + math.pi / 2.0) * 2.0 * 2.5 - Y += math.sin(angle * math.pi / 180.0 + math.pi / 2.0) * 2.0 * 2.5 - ########### end hack ########### - - if label != "": - output.append( - SVG( - "text", - label, - transform="translate(%g, %g) rotate(%g)" - % ( - X - yhatx * self.text_start, - Y - yhaty * self.text_start, - angle, - ), - **self.text_attr, - ) - ) - - for t in self.last_miniticks: - skip = False - for tt in list(self.last_ticks.keys()): - if abs(t - tt) < eps: - skip = True - break - if not skip: - (X, Y), (xhatx, xhaty), (yhatx, yhaty), angle = self.orient_tickmark( - t, trans - ) - - if (not self.arrow_start or abs(t - self.low) > eps) and ( - not self.arrow_end or abs(t - self.high) > eps - ): - minitickmarks.d.append( - ( - "M", - X - yhatx * self.minitick_start, - Y - yhaty * self.minitick_start, - True, - ) - ) - minitickmarks.d.append( - ( - "L", - X - yhatx * self.minitick_end, - Y - yhaty * self.minitick_end, - True, - ) - ) - - output.prepend(tickmarks.SVG(trans)) - output.prepend(minitickmarks.SVG(trans)) - return output - - def interpret(self): - """Evaluate and return optimal ticks and miniticks according to - the standard minitick specification. - - Normally only used internally. - """ - - if self.labels == None or self.labels == False: - format = lambda x: "" - - elif self.labels == True: - format = unumber - - elif isinstance(self.labels, str): - format = lambda x: (self.labels % x) - - elif callable(self.labels): - format = self.labels - - else: - raise TypeError( - "labels must be None/False, True, a format string, or a number->string function" - ) - - # Now for the ticks - ticks = self.ticks - - # Case 1: ticks is None/False - if ticks == None or ticks == False: - return {}, [] - - # Case 2: ticks is the number of desired ticks - elif isinstance(ticks, int): - if ticks == True: - ticks = -10 - - if self.logbase == None: - ticks = self.compute_ticks(ticks, format) - else: - ticks = self.compute_logticks(self.logbase, ticks, format) - - # Now for the miniticks - if self.miniticks == True: - if self.logbase == None: - return ticks, self.compute_miniticks(ticks) - else: - return ticks, self.compute_logminiticks(self.logbase) - - elif isinstance(self.miniticks, int): - return ticks, self.regular_miniticks(self.miniticks) - - elif getattr(self.miniticks, "__iter__", False): - return ticks, self.miniticks - - elif self.miniticks == False or self.miniticks == None: - return ticks, [] - - else: - raise TypeError( - "miniticks must be None/False, True, a number of desired miniticks, or a list of numbers" - ) - - # Cases 3 & 4: ticks is iterable - elif getattr(ticks, "__iter__", False): - # Case 3: ticks is some kind of list - if not isinstance(ticks, dict): - output = {} - eps = _epsilon * (self.high - self.low) - for x in ticks: - if format == unumber and abs(x) < eps: - output[x] = "0" - else: - output[x] = format(x) - ticks = output - - # Case 4: ticks is a dict - else: - pass - - # Now for the miniticks - if self.miniticks == True: - if self.logbase == None: - return ticks, self.compute_miniticks(ticks) - else: - return ticks, self.compute_logminiticks(self.logbase) - - elif isinstance(self.miniticks, int): - return ticks, self.regular_miniticks(self.miniticks) - - elif getattr(self.miniticks, "__iter__", False): - return ticks, self.miniticks - - elif self.miniticks == False or self.miniticks == None: - return ticks, [] - - else: - raise TypeError( - "miniticks must be None/False, True, a number of desired miniticks, or a list of numbers" - ) - - else: - raise TypeError( - "ticks must be None/False, a number of desired ticks, a list of numbers, or a dictionary of explicit markers" - ) - - def compute_ticks(self, N, format): - """Return less than -N or exactly N optimal linear ticks. - - Normally only used internally. - """ - if self.low >= self.high: - raise ValueError("low must be less than high") - if N == 1: - raise ValueError( - "N can be 0 or >1 to specify the exact number of ticks or negative to specify a maximum" - ) - - eps = _epsilon * (self.high - self.low) - - if N >= 0: - output = {} - x = self.low - for i in range(N): - if format == unumber and abs(x) < eps: - label = "0" - else: - label = format(x) - output[x] = label - x += (self.high - self.low) / (N - 1.0) - return output - - N = -N - - counter = 0 - granularity = 10 ** math.ceil(math.log10(max(abs(self.low), abs(self.high)))) - lowN = math.ceil(1.0 * self.low / granularity) - highN = math.floor(1.0 * self.high / granularity) - - while lowN > highN: - countermod3 = counter % 3 - if countermod3 == 0: - granularity *= 0.5 - elif countermod3 == 1: - granularity *= 0.4 - else: - granularity *= 0.5 - counter += 1 - lowN = math.ceil(1.0 * self.low / granularity) - highN = math.floor(1.0 * self.high / granularity) - - last_granularity = granularity - last_trial = None - - while True: - trial = {} - for n in range(int(lowN), int(highN) + 1): - x = n * granularity - if format == unumber and abs(x) < eps: - label = "0" - else: - label = format(x) - trial[x] = label - - if int(highN) + 1 - int(lowN) >= N: - if last_trial == None: - v1, v2 = self.low, self.high - return {v1: format(v1), v2: format(v2)} - else: - low_in_ticks, high_in_ticks = False, False - for t in list(last_trial.keys()): - if 1.0 * abs(t - self.low) / last_granularity < _epsilon: - low_in_ticks = True - if 1.0 * abs(t - self.high) / last_granularity < _epsilon: - high_in_ticks = True - - lowN = 1.0 * self.low / last_granularity - highN = 1.0 * self.high / last_granularity - if abs(lowN - round(lowN)) < _epsilon and not low_in_ticks: - last_trial[self.low] = format(self.low) - if abs(highN - round(highN)) < _epsilon and not high_in_ticks: - last_trial[self.high] = format(self.high) - return last_trial - - last_granularity = granularity - last_trial = trial - - countermod3 = counter % 3 - if countermod3 == 0: - granularity *= 0.5 - elif countermod3 == 1: - granularity *= 0.4 - else: - granularity *= 0.5 - counter += 1 - lowN = math.ceil(1.0 * self.low / granularity) - highN = math.floor(1.0 * self.high / granularity) - - def regular_miniticks(self, N): - """Return exactly N linear ticks. - - Normally only used internally. - """ - output = [] - x = self.low - for i in range(N): - output.append(x) - x += (self.high - self.low) / (N - 1.0) - return output - - def compute_miniticks(self, original_ticks): - """Return optimal linear miniticks, given a set of ticks. - - Normally only used internally. - """ - if len(original_ticks) < 2: - original_ticks = ticks(self.low, self.high) - original_ticks = list(original_ticks.keys()) - original_ticks.sort() - - if ( - self.low > original_ticks[0] + _epsilon - or self.high < original_ticks[-1] - _epsilon - ): - raise ValueError( - "original_ticks {%g...%g} extend beyond [%g, %g]" - % (original_ticks[0], original_ticks[-1], self.low, self.high) - ) - - granularities = [] - for i in range(len(original_ticks) - 1): - granularities.append(original_ticks[i + 1] - original_ticks[i]) - spacing = 10 ** (math.ceil(math.log10(min(granularities)) - 1)) - - output = [] - x = ( - original_ticks[0] - - math.ceil(1.0 * (original_ticks[0] - self.low) / spacing) * spacing - ) - - while x <= self.high: - if x >= self.low: - already_in_ticks = False - for t in original_ticks: - if abs(x - t) < _epsilon * (self.high - self.low): - already_in_ticks = True - if not already_in_ticks: - output.append(x) - x += spacing - return output - - def compute_logticks(self, base, N, format): - """Return less than -N or exactly N optimal logarithmic ticks. - - Normally only used internally. - """ - if self.low >= self.high: - raise ValueError("low must be less than high") - if N == 1: - raise ValueError( - "N can be 0 or >1 to specify the exact number of ticks or negative to specify a maximum" - ) - - eps = _epsilon * (self.high - self.low) - - if N >= 0: - output = {} - x = self.low - for i in range(N): - if format == unumber and abs(x) < eps: - label = "0" - else: - label = format(x) - output[x] = label - x += (self.high - self.low) / (N - 1.0) - return output - - N = -N - - lowN = math.floor(math.log(self.low, base)) - highN = math.ceil(math.log(self.high, base)) - output = {} - for n in range(int(lowN), int(highN) + 1): - x = base**n - label = format(x) - if self.low <= x <= self.high: - output[x] = label - - for i in range(1, len(output)): - keys = list(output.keys()) - keys.sort() - keys = keys[::i] - values = [output[k] for k in keys] - if len(values) <= N: - for k in list(output.keys()): - if k not in keys: - output[k] = "" - break - - if len(output) <= 2: - output2 = self.compute_ticks(N=-int(math.ceil(N / 2.0)), format=format) - lowest = min(output2) - - for k in output: - if k < lowest: - output2[k] = output[k] - output = output2 - - return output - - def compute_logminiticks(self, base): - """Return optimal logarithmic miniticks, given a set of ticks. - - Normally only used internally. - """ - if self.low >= self.high: - raise ValueError("low must be less than high") - - lowN = math.floor(math.log(self.low, base)) - highN = math.ceil(math.log(self.high, base)) - output = [] - num_ticks = 0 - for n in range(int(lowN), int(highN) + 1): - x = base**n - if self.low <= x <= self.high: - num_ticks += 1 - for m in range(2, int(math.ceil(base))): - minix = m * x - if self.low <= minix <= self.high: - output.append(minix) - - if num_ticks <= 2: - return [] - else: - return output - - -###################################################################### - - -class CurveAxis(Curve, Ticks): - """Draw an axis with tick marks along a parametric curve. - - CurveAxis(f, low, high, ticks, miniticks, labels, logbase, arrow_start, arrow_end, - text_attr, attribute=value) - - f required a Python callable or string in - the form "f(t), g(t)", just like Curve - low, high required left and right endpoints - ticks default=-10 request ticks according to the standard - tick specification (see help(Ticks)) - miniticks default=True request miniticks according to the - standard minitick specification - labels True request tick labels according to the - standard tick label specification - logbase default=None if a number, the x axis is logarithmic - with ticks at the given base (10 being - the most common) - arrow_start default=None if a new string identifier, draw an - arrow at the low-end of the axis, - referenced by that identifier; if an - SVG marker object, use that marker - arrow_end default=None if a new string identifier, draw an - arrow at the high-end of the axis, - referenced by that identifier; if an - SVG marker object, use that marker - text_attr default={} SVG attributes for the text labels - attribute=value pairs keyword list SVG attributes - """ - - defaults = {"stroke-width": "0.25pt"} - text_defaults = {"stroke": "none", "fill": "black", "font-size": 5} - - def __repr__(self): - return "" % ( - self.f, - self.low, - self.high, - str(self.ticks), - str(self.labels), - self.attr, - ) - - def __init__( - self, - f, - low, - high, - ticks=-10, - miniticks=True, - labels=True, - logbase=None, - arrow_start=None, - arrow_end=None, - text_attr={}, - **attr, - ): - tattr = dict(self.text_defaults) - tattr.update(text_attr) - Curve.__init__(self, f, low, high) - Ticks.__init__( - self, - f, - low, - high, - ticks, - miniticks, - labels, - logbase, - arrow_start, - arrow_end, - tattr, - **attr, - ) - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - func = Curve.SVG(self, trans) - ticks = Ticks.SVG(self, trans) # returns a - - if self.arrow_start != False and self.arrow_start != None: - if isinstance(self.arrow_start, str): - func.attr["marker-start"] = "url(#%s)" % self.arrow_start - else: - func.attr["marker-start"] = "url(#%s)" % self.arrow_start.id - - if self.arrow_end != False and self.arrow_end != None: - if isinstance(self.arrow_end, str): - func.attr["marker-end"] = "url(#%s)" % self.arrow_end - else: - func.attr["marker-end"] = "url(#%s)" % self.arrow_end.id - - ticks.append(func) - return ticks - - -class LineAxis(Line, Ticks): - """Draws an axis with tick marks along a line. - - LineAxis(x1, y1, x2, y2, start, end, ticks, miniticks, labels, logbase, - arrow_start, arrow_end, text_attr, attribute=value) - - x1, y1 required starting point - x2, y2 required ending point - start, end default=0, 1 values to start and end labeling - ticks default=-10 request ticks according to the standard - tick specification (see help(Ticks)) - miniticks default=True request miniticks according to the - standard minitick specification - labels True request tick labels according to the - standard tick label specification - logbase default=None if a number, the x axis is logarithmic - with ticks at the given base (usually 10) - arrow_start default=None if a new string identifier, draw an arrow - at the low-end of the axis, referenced by - that identifier; if an SVG marker object, - use that marker - arrow_end default=None if a new string identifier, draw an arrow - at the high-end of the axis, referenced by - that identifier; if an SVG marker object, - use that marker - text_attr default={} SVG attributes for the text labels - attribute=value pairs keyword list SVG attributes - """ - - defaults = {"stroke-width": "0.25pt"} - text_defaults = {"stroke": "none", "fill": "black", "font-size": 5} - - def __repr__(self): - return "" % ( - self.x1, - self.y1, - self.x2, - self.y2, - str(self.ticks), - str(self.labels), - self.attr, - ) - - def __init__( - self, - x1, - y1, - x2, - y2, - start=0.0, - end=1.0, - ticks=-10, - miniticks=True, - labels=True, - logbase=None, - arrow_start=None, - arrow_end=None, - exclude=None, - text_attr={}, - **attr, - ): - self.start = start - self.end = end - self.exclude = exclude - tattr = dict(self.text_defaults) - tattr.update(text_attr) - Line.__init__(self, x1, y1, x2, y2, **attr) - Ticks.__init__( - self, - None, - None, - None, - ticks, - miniticks, - labels, - logbase, - arrow_start, - arrow_end, - tattr, - **attr, - ) - - def interpret(self): - if self.exclude != None and not ( - isinstance(self.exclude, (tuple, list)) - and len(self.exclude) == 2 - and isinstance(self.exclude[0], (int, float)) - and isinstance(self.exclude[1], (int, float)) - ): - raise TypeError("exclude must either be None or (low, high)") - - ticks, miniticks = Ticks.interpret(self) - if self.exclude == None: - return ticks, miniticks - - ticks2 = {} - for loc, label in list(ticks.items()): - if self.exclude[0] <= loc <= self.exclude[1]: - ticks2[loc] = "" - else: - ticks2[loc] = label - - return ticks2, miniticks - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - line = Line.SVG( - self, trans - ) # must be evaluated first, to set self.f, self.low, self.high - - f01 = self.f - self.f = lambda t: f01(1.0 * (t - self.start) / (self.end - self.start)) - self.low = self.start - self.high = self.end - - if self.arrow_start != False and self.arrow_start != None: - if isinstance(self.arrow_start, str): - line.attr["marker-start"] = "url(#%s)" % self.arrow_start - else: - line.attr["marker-start"] = "url(#%s)" % self.arrow_start.id - - if self.arrow_end != False and self.arrow_end != None: - if isinstance(self.arrow_end, str): - line.attr["marker-end"] = "url(#%s)" % self.arrow_end - else: - line.attr["marker-end"] = "url(#%s)" % self.arrow_end.id - - ticks = Ticks.SVG(self, trans) # returns a - ticks.append(line) - return ticks - - -class XAxis(LineAxis): - """Draws an x axis with tick marks. - - XAxis(xmin, xmax, aty, ticks, miniticks, labels, logbase, arrow_start, arrow_end, - exclude, text_attr, attribute=value) - - xmin, xmax required the x range - aty default=0 y position to draw the axis - ticks default=-10 request ticks according to the standard - tick specification (see help(Ticks)) - miniticks default=True request miniticks according to the - standard minitick specification - labels True request tick labels according to the - standard tick label specification - logbase default=None if a number, the x axis is logarithmic - with ticks at the given base (usually 10) - arrow_start default=None if a new string identifier, draw an arrow - at the low-end of the axis, referenced by - that identifier; if an SVG marker object, - use that marker - arrow_end default=None if a new string identifier, draw an arrow - at the high-end of the axis, referenced by - that identifier; if an SVG marker object, - use that marker - exclude default=None if a (low, high) pair, don't draw text - labels within this range - text_attr default={} SVG attributes for the text labels - attribute=value pairs keyword list SVG attributes for all lines - - The exclude option is provided for Axes to keep text from overlapping - where the axes cross. Normal users are not likely to need it. - """ - - defaults = {"stroke-width": "0.25pt"} - text_defaults = { - "stroke": "none", - "fill": "black", - "font-size": 5, - "dominant-baseline": "text-before-edge", - } - text_start = -1.0 - text_angle = 0.0 - - def __repr__(self): - return "" % ( - self.xmin, - self.xmax, - self.aty, - str(self.ticks), - str(self.labels), - self.attr, - ) - - def __init__( - self, - xmin, - xmax, - aty=0, - ticks=-10, - miniticks=True, - labels=True, - logbase=None, - arrow_start=None, - arrow_end=None, - exclude=None, - text_attr={}, - **attr, - ): - self.aty = aty - tattr = dict(self.text_defaults) - tattr.update(text_attr) - LineAxis.__init__( - self, - xmin, - aty, - xmax, - aty, - xmin, - xmax, - ticks, - miniticks, - labels, - logbase, - arrow_start, - arrow_end, - exclude, - tattr, - **attr, - ) - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - self.y1 = self.aty - self.y2 = self.aty - return LineAxis.SVG(self, trans) - - -class YAxis(LineAxis): - """Draws a y axis with tick marks. - - YAxis(ymin, ymax, atx, ticks, miniticks, labels, logbase, arrow_start, arrow_end, - exclude, text_attr, attribute=value) - - ymin, ymax required the y range - atx default=0 x position to draw the axis - ticks default=-10 request ticks according to the standard - tick specification (see help(Ticks)) - miniticks default=True request miniticks according to the - standard minitick specification - labels True request tick labels according to the - standard tick label specification - logbase default=None if a number, the y axis is logarithmic - with ticks at the given base (usually 10) - arrow_start default=None if a new string identifier, draw an arrow - at the low-end of the axis, referenced by - that identifier; if an SVG marker object, - use that marker - arrow_end default=None if a new string identifier, draw an arrow - at the high-end of the axis, referenced by - that identifier; if an SVG marker object, - use that marker - exclude default=None if a (low, high) pair, don't draw text - labels within this range - text_attr default={} SVG attributes for the text labels - attribute=value pairs keyword list SVG attributes for all lines - - The exclude option is provided for Axes to keep text from overlapping - where the axes cross. Normal users are not likely to need it. - """ - - defaults = {"stroke-width": "0.25pt"} - text_defaults = { - "stroke": "none", - "fill": "black", - "font-size": 5, - "text-anchor": "end", - "dominant-baseline": "middle", - } - text_start = 2.5 - text_angle = 90.0 - - def __repr__(self): - return "" % ( - self.ymin, - self.ymax, - self.atx, - str(self.ticks), - str(self.labels), - self.attr, - ) - - def __init__( - self, - ymin, - ymax, - atx=0, - ticks=-10, - miniticks=True, - labels=True, - logbase=None, - arrow_start=None, - arrow_end=None, - exclude=None, - text_attr={}, - **attr, - ): - self.atx = atx - tattr = dict(self.text_defaults) - tattr.update(text_attr) - LineAxis.__init__( - self, - atx, - ymin, - atx, - ymax, - ymin, - ymax, - ticks, - miniticks, - labels, - logbase, - arrow_start, - arrow_end, - exclude, - tattr, - **attr, - ) - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - self.x1 = self.atx - self.x2 = self.atx - return LineAxis.SVG(self, trans) - - -class Axes: - """Draw a pair of intersecting x-y axes. - - Axes(xmin, xmax, ymin, ymax, atx, aty, xticks, xminiticks, xlabels, xlogbase, - yticks, yminiticks, ylabels, ylogbase, arrows, text_attr, attribute=value) - - xmin, xmax required the x range - ymin, ymax required the y range - atx, aty default=0, 0 point where the axes try to cross; - if outside the range, the axes will - cross at the closest corner - xticks default=-10 request ticks according to the standard - tick specification (see help(Ticks)) - xminiticks default=True request miniticks according to the - standard minitick specification - xlabels True request tick labels according to the - standard tick label specification - xlogbase default=None if a number, the x axis is logarithmic - with ticks at the given base (usually 10) - yticks default=-10 request ticks according to the standard - tick specification - yminiticks default=True request miniticks according to the - standard minitick specification - ylabels True request tick labels according to the - standard tick label specification - ylogbase default=None if a number, the y axis is logarithmic - with ticks at the given base (usually 10) - arrows default=None if a new string identifier, draw arrows - referenced by that identifier - text_attr default={} SVG attributes for the text labels - attribute=value pairs keyword list SVG attributes for all lines - """ - - defaults = {"stroke-width": "0.25pt"} - text_defaults = {"stroke": "none", "fill": "black", "font-size": 5} - - def __repr__(self): - return "" % ( - self.xmin, - self.xmax, - self.ymin, - self.ymax, - self.atx, - self.aty, - self.attr, - ) - - def __init__( - self, - xmin, - xmax, - ymin, - ymax, - atx=0, - aty=0, - xticks=-10, - xminiticks=True, - xlabels=True, - xlogbase=None, - yticks=-10, - yminiticks=True, - ylabels=True, - ylogbase=None, - arrows=None, - text_attr={}, - **attr, - ): - self.xmin, self.xmax = xmin, xmax - self.ymin, self.ymax = ymin, ymax - self.atx, self.aty = atx, aty - self.xticks, self.xminiticks, self.xlabels, self.xlogbase = ( - xticks, - xminiticks, - xlabels, - xlogbase, - ) - self.yticks, self.yminiticks, self.ylabels, self.ylogbase = ( - yticks, - yminiticks, - ylabels, - ylogbase, - ) - self.arrows = arrows - - self.text_attr = dict(self.text_defaults) - self.text_attr.update(text_attr) - - self.attr = dict(self.defaults) - self.attr.update(attr) - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - atx, aty = self.atx, self.aty - if atx < self.xmin: - atx = self.xmin - if atx > self.xmax: - atx = self.xmax - if aty < self.ymin: - aty = self.ymin - if aty > self.ymax: - aty = self.ymax - - xmargin = 0.1 * abs(self.ymin - self.ymax) - xexclude = atx - xmargin, atx + xmargin - - ymargin = 0.1 * abs(self.xmin - self.xmax) - yexclude = aty - ymargin, aty + ymargin - - if self.arrows != None and self.arrows != False: - xarrow_start = self.arrows + ".xstart" - xarrow_end = self.arrows + ".xend" - yarrow_start = self.arrows + ".ystart" - yarrow_end = self.arrows + ".yend" - else: - xarrow_start = xarrow_end = yarrow_start = yarrow_end = None - - xaxis = XAxis( - self.xmin, - self.xmax, - aty, - self.xticks, - self.xminiticks, - self.xlabels, - self.xlogbase, - xarrow_start, - xarrow_end, - exclude=xexclude, - text_attr=self.text_attr, - **self.attr, - ).SVG(trans) - yaxis = YAxis( - self.ymin, - self.ymax, - atx, - self.yticks, - self.yminiticks, - self.ylabels, - self.ylogbase, - yarrow_start, - yarrow_end, - exclude=yexclude, - text_attr=self.text_attr, - **self.attr, - ).SVG(trans) - return SVG("g", *(xaxis.sub + yaxis.sub)) - - -###################################################################### - - -class HGrid(Ticks): - """Draws the horizontal lines of a grid over a specified region - using the standard tick specification (see help(Ticks)) to place the - grid lines. - - HGrid(xmin, xmax, low, high, ticks, miniticks, logbase, mini_attr, attribute=value) - - xmin, xmax required the x range - low, high required the y range - ticks default=-10 request ticks according to the standard - tick specification (see help(Ticks)) - miniticks default=False request miniticks according to the - standard minitick specification - logbase default=None if a number, the axis is logarithmic - with ticks at the given base (usually 10) - mini_attr default={} SVG attributes for the minitick-lines - (if miniticks != False) - attribute=value pairs keyword list SVG attributes for the major tick lines - """ - - defaults = {"stroke-width": "0.25pt", "stroke": "gray"} - mini_defaults = { - "stroke-width": "0.25pt", - "stroke": "lightgray", - "stroke-dasharray": "1,1", - } - - def __repr__(self): - return "" % ( - self.xmin, - self.xmax, - self.low, - self.high, - str(self.ticks), - str(self.miniticks), - self.attr, - ) - - def __init__( - self, - xmin, - xmax, - low, - high, - ticks=-10, - miniticks=False, - logbase=None, - mini_attr={}, - **attr, - ): - self.xmin, self.xmax = xmin, xmax - - self.mini_attr = dict(self.mini_defaults) - self.mini_attr.update(mini_attr) - - Ticks.__init__(self, None, low, high, ticks, miniticks, None, logbase) - - self.attr = dict(self.defaults) - self.attr.update(attr) - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - self.last_ticks, self.last_miniticks = Ticks.interpret(self) - - ticksd = [] - for t in list(self.last_ticks.keys()): - ticksd += Line(self.xmin, t, self.xmax, t).Path(trans).d - - miniticksd = [] - for t in self.last_miniticks: - miniticksd += Line(self.xmin, t, self.xmax, t).Path(trans).d - - return SVG( - "g", - Path(d=ticksd, **self.attr).SVG(), - Path(d=miniticksd, **self.mini_attr).SVG(), - ) - - -class VGrid(Ticks): - """Draws the vertical lines of a grid over a specified region - using the standard tick specification (see help(Ticks)) to place the - grid lines. - - HGrid(ymin, ymax, low, high, ticks, miniticks, logbase, mini_attr, attribute=value) - - ymin, ymax required the y range - low, high required the x range - ticks default=-10 request ticks according to the standard - tick specification (see help(Ticks)) - miniticks default=False request miniticks according to the - standard minitick specification - logbase default=None if a number, the axis is logarithmic - with ticks at the given base (usually 10) - mini_attr default={} SVG attributes for the minitick-lines - (if miniticks != False) - attribute=value pairs keyword list SVG attributes for the major tick lines - """ - - defaults = {"stroke-width": "0.25pt", "stroke": "gray"} - mini_defaults = { - "stroke-width": "0.25pt", - "stroke": "lightgray", - "stroke-dasharray": "1,1", - } - - def __repr__(self): - return "" % ( - self.ymin, - self.ymax, - self.low, - self.high, - str(self.ticks), - str(self.miniticks), - self.attr, - ) - - def __init__( - self, - ymin, - ymax, - low, - high, - ticks=-10, - miniticks=False, - logbase=None, - mini_attr={}, - **attr, - ): - self.ymin, self.ymax = ymin, ymax - - self.mini_attr = dict(self.mini_defaults) - self.mini_attr.update(mini_attr) - - Ticks.__init__(self, None, low, high, ticks, miniticks, None, logbase) - - self.attr = dict(self.defaults) - self.attr.update(attr) - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - self.last_ticks, self.last_miniticks = Ticks.interpret(self) - - ticksd = [] - for t in list(self.last_ticks.keys()): - ticksd += Line(t, self.ymin, t, self.ymax).Path(trans).d - - miniticksd = [] - for t in self.last_miniticks: - miniticksd += Line(t, self.ymin, t, self.ymax).Path(trans).d - - return SVG( - "g", - Path(d=ticksd, **self.attr).SVG(), - Path(d=miniticksd, **self.mini_attr).SVG(), - ) - - -class Grid(Ticks): - """Draws a grid over a specified region using the standard tick - specification (see help(Ticks)) to place the grid lines. - - Grid(xmin, xmax, ymin, ymax, ticks, miniticks, logbase, mini_attr, attribute=value) - - xmin, xmax required the x range - ymin, ymax required the y range - ticks default=-10 request ticks according to the standard - tick specification (see help(Ticks)) - miniticks default=False request miniticks according to the - standard minitick specification - logbase default=None if a number, the axis is logarithmic - with ticks at the given base (usually 10) - mini_attr default={} SVG attributes for the minitick-lines - (if miniticks != False) - attribute=value pairs keyword list SVG attributes for the major tick lines - """ - - defaults = {"stroke-width": "0.25pt", "stroke": "gray"} - mini_defaults = { - "stroke-width": "0.25pt", - "stroke": "lightgray", - "stroke-dasharray": "1,1", - } - - def __repr__(self): - return "" % ( - self.xmin, - self.xmax, - self.ymin, - self.ymax, - str(self.ticks), - str(self.miniticks), - self.attr, - ) - - def __init__( - self, - xmin, - xmax, - ymin, - ymax, - ticks=-10, - miniticks=False, - logbase=None, - mini_attr={}, - **attr, - ): - self.xmin, self.xmax = xmin, xmax - self.ymin, self.ymax = ymin, ymax - - self.mini_attr = dict(self.mini_defaults) - self.mini_attr.update(mini_attr) - - Ticks.__init__(self, None, None, None, ticks, miniticks, None, logbase) - - self.attr = dict(self.defaults) - self.attr.update(attr) - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - self.low, self.high = self.xmin, self.xmax - self.last_xticks, self.last_xminiticks = Ticks.interpret(self) - self.low, self.high = self.ymin, self.ymax - self.last_yticks, self.last_yminiticks = Ticks.interpret(self) - - ticksd = [] - for t in list(self.last_xticks.keys()): - ticksd += Line(t, self.ymin, t, self.ymax).Path(trans).d - for t in list(self.last_yticks.keys()): - ticksd += Line(self.xmin, t, self.xmax, t).Path(trans).d - - miniticksd = [] - for t in self.last_xminiticks: - miniticksd += Line(t, self.ymin, t, self.ymax).Path(trans).d - for t in self.last_yminiticks: - miniticksd += Line(self.xmin, t, self.xmax, t).Path(trans).d - - return SVG( - "g", - Path(d=ticksd, **self.attr).SVG(), - Path(d=miniticksd, **self.mini_attr).SVG(), - ) - - -###################################################################### - - -class XErrorBars: - """Draws x error bars at a set of points. This is usually used - before (under) a set of Dots at the same points. - - XErrorBars(d, attribute=value) - - d required list of (x,y,xerr...) points - attribute=value pairs keyword list SVG attributes - - If points in d have - - * 3 elements, the third is the symmetric error bar - * 4 elements, the third and fourth are the asymmetric lower and - upper error bar. The third element should be negative, - e.g. (5, 5, -1, 2) is a bar from 4 to 7. - * more than 4, a tick mark is placed at each value. This lets - you nest errors from different sources, correlated and - uncorrelated, statistical and systematic, etc. - """ - - defaults = {"stroke-width": "0.25pt"} - - def __repr__(self): - return "" % len(self.d) - - def __init__(self, d=[], **attr): - self.d = list(d) - - self.attr = dict(self.defaults) - self.attr.update(attr) - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - if isinstance(trans, str): - trans = totrans(trans) # only once - - output = SVG("g") - for p in self.d: - x, y = p[0], p[1] - - if len(p) == 3: - bars = [x - p[2], x + p[2]] - else: - bars = [x + pi for pi in p[2:]] - - start, end = min(bars), max(bars) - output.append( - LineAxis( - start, y, end, y, start, end, bars, False, False, **self.attr - ).SVG(trans) - ) - - return output - - -class YErrorBars: - """Draws y error bars at a set of points. This is usually used - before (under) a set of Dots at the same points. - - YErrorBars(d, attribute=value) - - d required list of (x,y,yerr...) points - attribute=value pairs keyword list SVG attributes - - If points in d have - - * 3 elements, the third is the symmetric error bar - * 4 elements, the third and fourth are the asymmetric lower and - upper error bar. The third element should be negative, - e.g. (5, 5, -1, 2) is a bar from 4 to 7. - * more than 4, a tick mark is placed at each value. This lets - you nest errors from different sources, correlated and - uncorrelated, statistical and systematic, etc. - """ - - defaults = {"stroke-width": "0.25pt"} - - def __repr__(self): - return "" % len(self.d) - - def __init__(self, d=[], **attr): - self.d = list(d) - - self.attr = dict(self.defaults) - self.attr.update(attr) - - def SVG(self, trans=None): - """Apply the transformation "trans" and return an SVG object.""" - if isinstance(trans, str): - trans = totrans(trans) # only once - - output = SVG("g") - for p in self.d: - x, y = p[0], p[1] - - if len(p) == 3: - bars = [y - p[2], y + p[2]] - else: - bars = [y + pi for pi in p[2:]] - - start, end = min(bars), max(bars) - output.append( - LineAxis( - x, start, x, end, start, end, bars, False, False, **self.attr - ).SVG(trans) - ) - - return output diff --git a/MDANSE/Src/MDANSE/Framework/Configurators/ComplexNumberConfigurator.py b/MDANSE/Src/MDANSE/Framework/Configurators/ComplexNumberConfigurator.py deleted file mode 100644 index bdc0f306de..0000000000 --- a/MDANSE/Src/MDANSE/Framework/Configurators/ComplexNumberConfigurator.py +++ /dev/null @@ -1,123 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/Framework/Configurators/ComplexNumberConfigurator.py -# @brief Implements module/class/test ComplexNumberConfigurator -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - - -from MDANSE.Mathematics.Arithmetic import ComplexNumber -from MDANSE.Framework.Configurators.IConfigurator import ( - IConfigurator, - ConfiguratorError, -) - - -class ComplexNumberConfigurator(IConfigurator): - """ - This Configurator allows to input a complex number of the form a + bj. - """ - - _default = 0 - - def __init__(self, name, mini=None, maxi=None, choices=None, **kwargs): - """ - Initializes the configurator. - - :param name: the name of the configurator as it will appear in the configuration - :type name: str - :param mini: the minimum modulus allowed for the input value. If None, no restriction for the minimum. - :type mini: float or None - :param maxi: the maximum modulus allowed for the input value. If None, no restriction for the maximum. - :type maxi: float or None - :param choices: the list of complex numbers allowed for the input value. If None, any value will be allowed. - :type choices: list of complex or None - """ - - # The base class constructor. - IConfigurator.__init__(self, name, **kwargs) - - self._mini = float(mini) if mini is not None else None - - self._maxi = float(maxi) if maxi is not None else None - - self._choices = choices if choices is not None else [] - - def configure(self, value): - """ - Configure an input value. - - :param value: the input complex number. - :type value: complex - """ - - value = ComplexNumber(value) - - if self._choices: - if not value in self._choices: - raise ConfiguratorError("the input value is not a valid choice.", self) - - if self._mini is not None: - if value.modulus() < self._mini.modulus(): - raise ConfiguratorError( - "the input value is lower than %r." % self._mini, self - ) - - if self._maxi is not None: - if value.modulus() > self._maxi.modulus(): - raise ConfiguratorError( - "the input value is higher than %r." % self._maxi, self - ) - - self["value"] = value - - @property - def mini(self): - """ - Returns the minimum value allowed for an input complex number. - - :return: the minimum value allowed for the modulus of an input complex number. - :rtype: float or None - """ - - return self._mini - - @property - def maxi(self): - """ - Returns the maximum value allowed for the modulus of an input complex number. - - :return: the maximum value allowed for an input complex number. - :rtype: float or None - """ - - return self._maxi - - @property - def choices(self): - """ - Returns the list of floats allowed for an input complex number. - - :return: the choices allowed for an input complex number. - :rtype: list of floats or None - """ - - return self._choices - - def get_information(self): - """ - Returns some informations about this configurator. - - :return: the information about this configurator - :rtype: str - """ - - return "Value: %r" % self["value"] diff --git a/MDANSE/Src/MDANSE/Framework/Configurators/OutputFilesConfigurator.py b/MDANSE/Src/MDANSE/Framework/Configurators/OutputFilesConfigurator.py index f9dbd49d3d..0333632a60 100644 --- a/MDANSE/Src/MDANSE/Framework/Configurators/OutputFilesConfigurator.py +++ b/MDANSE/Src/MDANSE/Framework/Configurators/OutputFilesConfigurator.py @@ -32,7 +32,7 @@ class OutputFilesConfigurator(IConfigurator): Once configured, this configurator will provide a list of files built by joining the given output directory, the basename and the extensions corresponding to the input file formats. - For analysis, MDANSE currently supports only the HDF, SVG and ASCII formats. To define a new output file format + For analysis, MDANSE currently supports only the HDF and ASCII formats. To define a new output file format for an analysis, you must inherit from MDANSE.Framework.Formats.IFormat.IFormat interface. """ diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/IJob.py b/MDANSE/Src/MDANSE/Framework/Jobs/IJob.py index 48690c991c..8b9603f367 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/IJob.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/IJob.py @@ -275,33 +275,10 @@ def _run_multiprocessor(self): sys.setrecursionlimit(oldrecursionlimit) def _run_remote(self): - IJob.set_pyro_server() - - import MDANSE.DistributedComputing.MasterSlave as MasterSlave - - tasks = MasterSlave.initializeMasterProcess( - self._name, slave_module="MDANSE.DistributedComputing.Slave" + raise NotImplementedError( + "Currently there is no replacement for the old Pyro remote runs." ) - tasks.setGlobalState(job=self) - - if self._status is not None: - self._status.start(self.numberOfSteps, rate=0.1) - - for index in range(self.numberOfSteps): - tasks.requestTask("run_step", MasterSlave.GlobalStateValue(1, "job"), index) - - for index in range(self.numberOfSteps): - _, _, (idx, x) = tasks.retrieveResult("run_step") - self.combine(idx, x) - - if self._status is not None: - if self._status.is_stopped(): - self._status.cleanup() - return - else: - self._status.update() - _runner = { "monoprocessor": _run_monoprocessor, "threadpool": _run_threadpool, diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/MeanSquareDisplacement.py b/MDANSE/Src/MDANSE/Framework/Jobs/MeanSquareDisplacement.py index 08e6f53ce6..a2ce464a27 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/MeanSquareDisplacement.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/MeanSquareDisplacement.py @@ -97,7 +97,7 @@ class MeanSquareDisplacement(IJob): ) settings["output_files"] = ( "OutputFilesConfigurator", - {"formats": ["MDAFormat", "ASCIIFormat", "svg"]}, + {"formats": ["MDAFormat", "ASCIIFormat"]}, ) settings["running_mode"] = ("RunningModeConfigurator", {}) diff --git a/MDANSE/Src/MDANSE/Logging/Formatters.py b/MDANSE/Src/MDANSE/Logging/Formatters.py deleted file mode 100644 index 5b0d77a900..0000000000 --- a/MDANSE/Src/MDANSE/Logging/Formatters.py +++ /dev/null @@ -1,106 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/Logging/Formatters.py -# @brief Implements module/class/test Formatters -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import logging - - -class Formatter(logging.Formatter): - """ - Converts the log record to a string. - """ - - FORMATS = { - "DEBUG": "%(asctime)s - %(levelname)-8s - %(message)s --- %(pathname)s %(funcName)s line %(lineno)s", - "INFO": "%(asctime)s - %(levelname)-8s - %(message)s", - "WARNING": "%(asctime)s - %(levelname)-8s - %(message)s", - "ERROR": "%(asctime)s - %(levelname)-8s - %(message)s", - "CRITICAL": "%(asctime)s - %(levelname)-8s - %(message)s", - "FATAL": "%(asctime)s - %(levelname)-8s - %(message)s", - } - - def formatTime(self, record, datefmt=None): - """ - Return the creation time of the specified LogRecord as formatted text. - - This method should be called from format() by a formatter which - wants to make use of a formatted time. This method can be overridden - in formatters to provide for any specific requirement, but the - basic behaviour is as follows: if datefmt (a string) is specified, - it is used with time.strftime() to format the creation time of the - record. Otherwise, the ISO8601 format is used. The resulting - string is returned. This function uses a user-configurable function - to convert the creation time to a tuple. By default, time.localtime() - is used; to change this for a particular formatter instance, set the - 'converter' attribute to a function with the same signature as - time.localtime() or time.gmtime(). To change it for all formatters, - for example if you want all logging times to be shown in GMT, - set the 'converter' attribute in the Formatter class. - - :param record: the log record. - :type record: logging.LogRecord - - :param datefmt: the format that will be used to produce the stringified date. - :type datefmt: str - """ - - import time - - # The log time is converted to local time. - ct = self.converter(record.created) - - # Case where datefmt was set, use it. - if datefmt: - s = time.strftime(datefmt, ct) - - # Otherwise use a default format. - else: - s = time.strftime("%Y-%m-%d %H:%M:%S", ct) - - return s - - def format(self, record): - """ - Format the logging record to a string that will further throw to the logger's handlers. - - The record's attribute dictionary is used as the operand to a - string formatting operation which yields the returned string. - Before formatting the dictionary, a couple of preparatory steps - are carried out. The message attribute of the record is computed - using LogRecord.getMessage(). If the formatting string uses the - time (as determined by a call to usesTime(), formatTime() is - called to format the event time. If there is exception information, - its value are used to overwrite the pathname, lineno and funcName - attribute of the record being processed and appended to the message. - - @param record: the loggign record to be formatted. - @type record: logging.LogRecord - """ - - # The format is set according to the record level. - fmt = Formatter.FORMATS[record.levelname] - - # Get the record message. - record.message = record.getMessage() - - if not record.message: - s = record.message - - else: - record.asctime = self.formatTime(record, self.datefmt) - # Creates the actual output string. - s = fmt % record.__dict__ - s = s.replace("\n", "\n" + " " * 33) - - return s diff --git a/MDANSE/Src/MDANSE/Logging/Logger.py b/MDANSE/Src/MDANSE/Logging/Logger.py deleted file mode 100644 index 416fbf83f9..0000000000 --- a/MDANSE/Src/MDANSE/Logging/Logger.py +++ /dev/null @@ -1,88 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/Logging/Logger.py -# @brief Implements module/class/test Logger -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import logging - -from MDANSE.Core.Singleton import Singleton - - -class Logger(metaclass=Singleton): - levels = { - "debug": logging.DEBUG, - "info": logging.INFO, - "warning": logging.WARNING, - "error": logging.ERROR, - "fatal": logging.CRITICAL, - "critical": logging.FATAL, - } - - def __call__(self, message, level="info", loggers=None): - lvl = Logger.levels.get(level, None) - - # If the logging level is unkwnown, skip that log - if lvl is None: - return - - if loggers is None: - loggers = list(logging.Logger.manager.loggerDict.keys()) - else: - loggers = [n for n in loggers if n in logging.Logger.manager.loggerDict] - - for n in loggers: - logging.getLogger(n).log(lvl, message) - - def start(self, loggers=None): - if loggers is None: - loggers = list(logging.Logger.manager.loggerDict.keys()) - else: - loggers = [n for n in loggers if n in logging.Logger.manager.loggerDict] - - for n in loggers: - logging.getLogger(n).disabled = False - - def stop(self, loggers=None): - if loggers is None: - loggers = list(logging.Logger.manager.loggerDict.keys()) - else: - loggers = [n for n in loggers if n in logging.Logger.manager.loggerDict] - - for n in loggers: - logging.getLogger(n).disabled = True - - def set_level(self, level, loggers=None): - lvl = Logger.levels.get(level, None) - if lvl is None: - return - - if loggers is None: - loggers = list(logging.Logger.manager.loggerDict.keys()) - else: - loggers = [n for n in loggers if n in logging.Logger.manager.loggerDict] - - for loggerName in loggers: - logging.getLogger(loggerName).setLevel(lvl) - - def add_handler(self, name, handler, level="error", start=True): - if name in logging.Logger.manager.loggerDict: - return - - logging.getLogger(name).addHandler(handler) - - logging.getLogger(name).disabled = not start - - self.set_level(level, loggers=[name]) - - -LOGGER = Logger() diff --git a/MDANSE/Src/MDANSE/Logging/__init__.py b/MDANSE/Src/MDANSE/Logging/__init__.py deleted file mode 100644 index 99e417cec4..0000000000 --- a/MDANSE/Src/MDANSE/Logging/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/Logging/__init__.py -# @brief Implements module/class/test __init__ -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** diff --git a/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py b/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py index 522a990fb3..1c27f38fbf 100644 --- a/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py +++ b/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py @@ -21,20 +21,6 @@ import numpy as np -def pgcd(numbers: "list[int]"): - """Computes the Greatest Common Denominator - of an iterable (e.g. list) of integer numbers. - - @param n: n. - @type: list of integers - - @return: pgcd([i1,i2,i3...]). - @rtype: integer - """ - - return math.gcd(*numbers) # this is valid since Python 3.9 - - def get_weights(props, contents, dim): normFactor = None @@ -81,11 +67,3 @@ def weight(props, values, contents, dim, key, symmetric=True): weightedSum += w * val return weightedSum - - -class ComplexNumber(complex): - def argument(self): - return cmath.phase(self) - - def modulus(self): - return np.abs(self) diff --git a/MDANSE/Src/MDANSE/Scripts/mdanse.py b/MDANSE/Src/MDANSE/Scripts/mdanse.py index 0d1e63451b..a6acb7ae01 100644 --- a/MDANSE/Src/MDANSE/Scripts/mdanse.py +++ b/MDANSE/Src/MDANSE/Scripts/mdanse.py @@ -21,7 +21,6 @@ import sys import textwrap -from MDANSE import LOGGER from MDANSE.Core.Error import Error from MDANSE import PLATFORM, REGISTRY from MDANSE.Framework.Handlers.IHandler import IHandler @@ -96,14 +95,6 @@ class CommandLineParser(optparse.OptionParser): def __init__(self, *args, **kwargs): optparse.OptionParser.__init__(self, *args, **kwargs) - LOGGER.add_handler( - "terminal", - IHandler.create("ColorizingStreamHandler"), - level="info", - start=True, - ) - LOGGER.start() - def check_job(self, option, opt_str, value, parser): """Display the jobs list @@ -378,7 +369,6 @@ def save_job_template(self, option, opt_str, value, parser): try: IJob.save_template(shortname, classname) except (IOError, KeyError) as e: - LOGGER(str(e), "error", ["console"]) return diff --git a/MDANSE/Src/MDANSE/__init__.py b/MDANSE/Src/MDANSE/__init__.py index caaa27d8ce..5403c73f23 100644 --- a/MDANSE/Src/MDANSE/__init__.py +++ b/MDANSE/Src/MDANSE/__init__.py @@ -19,8 +19,6 @@ from .__pkginfo__ import __version__, __author__, __date__ -from MDANSE.Logging.Logger import LOGGER - from MDANSE.Core.Platform import PLATFORM from MDANSE.Core.ClassRegistry import REGISTRY diff --git a/MDANSE_GUI/MANIFEST.in b/MDANSE_GUI/MANIFEST.in index f0bbb8c44e..ae71e258a1 100644 --- a/MDANSE_GUI/MANIFEST.in +++ b/MDANSE_GUI/MANIFEST.in @@ -1,9 +1,8 @@ include LICENSE include requirements.txt -recursive-include Src/MDANSE_GUI/GUI/Resources/Icons *.png -recursive-include Src/MDANSE_GUI/PyQtGUI/Icons *.png -recursive-include Src/MDANSE_GUI/PyQtGUI/MolecularViewer/database *.yml +recursive-include Src/MDANSE_GUI/Icons *.png +recursive-include Src/MDANSE_GUI/MolecularViewer/database *.yml recursive-include Doc * diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/BackEnd.py b/MDANSE_GUI/Src/MDANSE_GUI/BackEnd.py similarity index 95% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/BackEnd.py rename to MDANSE_GUI/Src/MDANSE_GUI/BackEnd.py index 6550b9705f..b87e04f77a 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/BackEnd.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/BackEnd.py @@ -17,9 +17,7 @@ from icecream import ic from qtpy.QtCore import Slot, QObject, QThread, QMutex, Signal, QProcess -from MDANSE import LOGGER, PLATFORM from MDANSE.__pkginfo__ import __author__, __commit__, __version__, __beta__ -from MDANSE.Core.Platform import PLATFORM from MDANSE.Framework.Jobs.IJob import IJob from MDANSE.Framework.Converters.Converter import Converter from MDANSE.Framework.InstrumentResolutions.IInstrumentResolution import ( @@ -35,9 +33,9 @@ from MDANSE.Framework.Selectors.ISelector import ISelector -from MDANSE_GUI.PyQtGUI.DataViewModel.TrajectoryHolder import DataTreeModel -from MDANSE_GUI.PyQtGUI.DataViewModel.JobHolder import JobHolder -from MDANSE_GUI.PyQtGUI.DataViewModel.ActionsHolder import ActionsSuperModel +from MDANSE_GUI.DataViewModel.TrajectoryHolder import DataTreeModel +from MDANSE_GUI.DataViewModel.JobHolder import JobHolder +from MDANSE_GUI.DataViewModel.ActionsHolder import ActionsSuperModel class BackEnd(QObject): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/DataViewModel/ActionsHolder.py b/MDANSE_GUI/Src/MDANSE_GUI/DataViewModel/ActionsHolder.py similarity index 96% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/DataViewModel/ActionsHolder.py rename to MDANSE_GUI/Src/MDANSE_GUI/DataViewModel/ActionsHolder.py index de3b861ef5..dd39599d73 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/DataViewModel/ActionsHolder.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/DataViewModel/ActionsHolder.py @@ -20,11 +20,10 @@ from qtpy.QtCore import QObject, Slot, Qt, QMutex from qtpy.QtWidgets import QTreeView -from MDANSE import LOGGER, PLATFORM from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE_GUI.PyQtGUI.SubclassViewer import JobTree -from MDANSE_GUI.PyQtGUI.DataViewModel.TrajectoryHolder import DataTreeItem +from MDANSE_GUI.SubclassViewer import JobTree +from MDANSE_GUI.DataViewModel.TrajectoryHolder import DataTreeItem class ActionsHolder(QStandardItemModel): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/DataViewModel/JobHolder.py b/MDANSE_GUI/Src/MDANSE_GUI/DataViewModel/JobHolder.py similarity index 99% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/DataViewModel/JobHolder.py rename to MDANSE_GUI/Src/MDANSE_GUI/DataViewModel/JobHolder.py index f6f156b116..d0f6dd1acc 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/DataViewModel/JobHolder.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/DataViewModel/JobHolder.py @@ -18,7 +18,7 @@ from qtpy.QtGui import QStandardItemModel, QStandardItem from qtpy.QtCore import QObject, Slot, Signal, QProcess, QThread, QMutex -from MDANSE_GUI.PyQtGUI.DataViewModel.JobStatusQt import JobStatusQt +from MDANSE_GUI.DataViewModel.JobStatusQt import JobStatusQt class JobThread(QThread): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/DataViewModel/JobStatusQt.py b/MDANSE_GUI/Src/MDANSE_GUI/DataViewModel/JobStatusQt.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/DataViewModel/JobStatusQt.py rename to MDANSE_GUI/Src/MDANSE_GUI/DataViewModel/JobStatusQt.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/DataViewModel/TrajectoryHolder.py b/MDANSE_GUI/Src/MDANSE_GUI/DataViewModel/TrajectoryHolder.py similarity index 99% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/DataViewModel/TrajectoryHolder.py rename to MDANSE_GUI/Src/MDANSE_GUI/DataViewModel/TrajectoryHolder.py index e359582f04..ac267d65ee 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/DataViewModel/TrajectoryHolder.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/DataViewModel/TrajectoryHolder.py @@ -20,7 +20,6 @@ from qtpy.QtGui import QStandardItemModel, QStandardItem from qtpy.QtCore import QObject, Slot -from MDANSE import LOGGER, PLATFORM from MDANSE.Framework.InputData import InputFileData from MDANSE.Framework.InputData.HDFTrajectoryInputData import HDFTrajectoryInputData diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/DataViewModel/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/DataViewModel/__init__.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/DataViewModel/__init__.py rename to MDANSE_GUI/Src/MDANSE_GUI/DataViewModel/__init__.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/ElementsDatabaseEditor.py b/MDANSE_GUI/Src/MDANSE_GUI/ElementsDatabaseEditor.py similarity index 96% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/ElementsDatabaseEditor.py rename to MDANSE_GUI/Src/MDANSE_GUI/ElementsDatabaseEditor.py index e4c65607f4..bbb1189cd4 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/ElementsDatabaseEditor.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/ElementsDatabaseEditor.py @@ -16,22 +16,17 @@ from qtpy.QtWidgets import ( QDialog, QPushButton, - QFrame, - QGridLayout, QVBoxLayout, - QWidget, - QLabel, QApplication, - QSizePolicy, QMenu, QLineEdit, QTableView, ) -from qtpy.QtCore import Signal, Slot, Qt, QPoint, QSize, QSortFilterProxyModel -from qtpy.QtGui import QFont, QEnterEvent, QStandardItem, QStandardItemModel +from qtpy.QtCore import Signal, Slot, Qt, QSortFilterProxyModel +from qtpy.QtGui import QStandardItem, QStandardItemModel from MDANSE.Chemistry import ATOMS_DATABASE -from MDANSE_GUI.PyQtGUI.Widgets.GeneralWidgets import InputVariable, InputDialog +from MDANSE_GUI.Widgets.GeneralWidgets import InputVariable, InputDialog class ElementView(QTableView): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Apps.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Apps.py deleted file mode 100644 index 621446fb2e..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Apps.py +++ /dev/null @@ -1,87 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Apps.py -# @brief Implements module/class/test Apps -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx - -from MDANSE.GUI.Plugins.JobPlugin import JobDialog -from MDANSE.GUI.Plugins.PlotterPlugin import PlotterFrame -from MDANSE.GUI.ElementsDatabaseEditor import ElementsDatabaseEditor -from MDANSE.GUI.MainFrame import MainFrame -from MDANSE.GUI.PeriodicTableViewer import PeriodicTableViewer -from MDANSE.GUI.UnitsEditor import UnitsEditor -from MDANSE.GUI.UserDefinitionViewer import UserDefinitionViewer - - -class ElementsDatabaseEditorApp(wx.App): - def OnInit(self): - f = ElementsDatabaseEditor(None) - f.Show() - self.SetTopWindow(f) - return True - - -class MainApplication(wx.App): - def OnInit(self): - f = MainFrame(None) - f.Show() - self.SetTopWindow(f) - return True - - -class PeriodicTableViewerApp(wx.App): - def OnInit(self): - f = PeriodicTableViewer(None) - f.Show() - self.SetTopWindow(f) - return True - - -class PlotterApp(wx.App): - def OnInit(self): - f = PlotterFrame(None) - self.SetTopWindow(f) - f.Show(True) - return True - - -class UnitsEditorApp(wx.App): - def OnInit(self): - f = UnitsEditor(None, standalone=True) - self.SetTopWindow(f) - f.ShowModal() - return True - - -class UserDefinitionViewerApp(wx.App): - def OnInit(self): - f = UserDefinitionViewer(None) - self.SetTopWindow(f) - f.ShowModal() - return True - - -class JobApp(wx.App): - def __init__(self, job, data, *args, **kwargs): - self._job = job - - self._data = data - - wx.App.__init__(self, *args, **kwargs) - - def OnInit(self): - f = JobDialog(None, self._job, self._data) - self.SetTopWindow(f) - f.ShowModal() - return True diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/ComboWidgets/ComboCheckbox.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/ComboWidgets/ComboCheckbox.py deleted file mode 100644 index 924206c57c..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/ComboWidgets/ComboCheckbox.py +++ /dev/null @@ -1,64 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/ComboWidgets/ComboCheckbox.py -# @brief Implements module/class/test ComboCheckbox -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx - - -class ComboCheckbox(wx.ComboPopup): - def __init__(self, items, maxNumberOfItems=None): - wx.ComboPopup.__init__(self) - - self._items = items - self._maxNumberOfItems = maxNumberOfItems - self._currentItem = -1 - - def OnMotion(self, event): - item = self._checkboxListCtrl.HitTest(event.GetPosition()) - if item >= 0: - self._checkboxListCtrl.Select(item) - self._currentItem = item - - def Create(self, parent): - self._checkboxListCtrl = wx.CheckListBox(parent, wx.ID_ANY, choices=self._items) - self._checkboxListCtrl.Bind(wx.EVT_MOTION, self.OnMotion) - self._checkboxListCtrl.Bind(wx.EVT_LEFT_DOWN, self.on_check_item) - - return True - - def GetControl(self): - return self._checkboxListCtrl - - def GetAdjustedSize(self, minWidth, prefHeight, maxHeight): - size = self.GetControl().GetSize() - return wx.Size(minWidth, size[1]) - - def GetStringValue(self): - return self.GetCheckedStrings() - - def on_check_item(self, event): - # Control only if ele;ent is checked - if not self._checkboxListCtrl.IsChecked(self._currentItem): - # Control max number of items - if self._maxNumberOfItems is None: - # Accept the event - self._checkboxListCtrl.Check(self._currentItem, True) - else: - # Control the number of checked items - nCheckedItems = len(self._checkboxListCtrl.GetChecked()) - if nCheckedItems < self._maxNumberOfItems: - # Chech the item - self._checkboxListCtrl.Check(self._currentItem, True) - else: - self._checkboxListCtrl.Check(self._currentItem, False) diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/ComboWidgets/ConfigurationPanel.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/ComboWidgets/ConfigurationPanel.py deleted file mode 100644 index 7d54b6427b..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/ComboWidgets/ConfigurationPanel.py +++ /dev/null @@ -1,76 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/ComboWidgets/ConfigurationPanel.py -# @brief Implements module/class/test ConfigurationPanel -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx - -from MDANSE import REGISTRY - -from MDANSE.Framework.Configurators.IConfigurator import ConfiguratorError - - -class ConfigurationPanel(wx.Panel): - def __init__(self, parent, configurable, type): - wx.Panel.__init__(self, parent, wx.ID_ANY) - - self._configurable = configurable - - self._type = type - - self._widgets = {} - - self.build_panel() - - def build_panel(self): - self.panelSizer = wx.BoxSizer(wx.VERTICAL) - - self._configurable.build_configuration() - - for cfgName in list(self._configurable.settings.keys()): - widget = self._configurable.configuration[cfgName].widget - - widgetClass = REGISTRY["widget"][widget] - - self._widgets[cfgName] = widgetClass( - self, cfgName, self._configurable.configuration[cfgName], widget - ) - - self.panelSizer.Add(self._widgets[cfgName], 0, wx.ALL | wx.EXPAND, 5) - - self.SetSizer(self.panelSizer) - - self.Layout() - - self.Fit() - - @property - def type(self): - return self._type - - @property - def widgets(self): - return self._widgets - - def get_value(self): - return dict([(k, v.get_value()) for k, v in list(self._widgets.items())]) - - def validate(self): - parameters = {} - try: - parameters.update(self.get_value()) - except ConfiguratorError as e: - wx.MessageBox(self, str(e), "Invalid input", style=wx.ICON_ERROR | wx.OK) - return False - finally: - return True diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/ComboWidgets/JobHelpFrame.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/ComboWidgets/JobHelpFrame.py deleted file mode 100644 index 24f0dfff95..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/ComboWidgets/JobHelpFrame.py +++ /dev/null @@ -1,50 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/ComboWidgets/JobHelpFrame.py -# @brief Implements module/class/test JobHelpFrame -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import os - -import wx -import wx.html as wxhtml - -from MDANSE import PLATFORM, REGISTRY - - -class JobHelpFrame(wx.Frame): - def __init__(self, parent, job): - wx.Frame.__init__( - self, parent, wx.ID_ANY, title="About %s" % job.label, size=(800, 600) - ) - - self.nolog = wx.LogNull() - - moduleFullName = PLATFORM.full_dotted_module(job.__class__) - - if moduleFullName is None: - self._doc = "" - else: - self._doc = os.path.join(PLATFORM.help_path(), moduleFullName + ".html") - - self.build() - - def build(self): - htmlPanel = wxhtml.HtmlWindow(self, wx.ID_ANY) - htmlPanel.LoadPage(self._doc) - - -if __name__ == "__main__": - app = wx.App(False) - f = JobHelpFrame(None, REGISTRY["job"]["msd"]()) - f.Show() - app.MainLoop() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/ComboWidgets/ProgressBar.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/ComboWidgets/ProgressBar.py deleted file mode 100644 index 9e2c475bec..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/ComboWidgets/ProgressBar.py +++ /dev/null @@ -1,73 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/ComboWidgets/ProgressBar.py -# @brief Implements module/class/test ProgressBar -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx -import wx.lib.agw.pygauge as pygauge - -from MDANSE.Framework.Status import Status -from MDANSE.GUI.Icons import ICONS - - -class ProgressBar(wx.Panel, Status): - def __init__(self, *args, **kwargs): - wx.Panel.__init__(self, *args, **kwargs) - Status.__init__(self) - - sizer = wx.BoxSizer(wx.HORIZONTAL) - - self._progress = pygauge.PyGauge(self, wx.ID_ANY) - self._stop = wx.BitmapButton(self, wx.ID_ANY, ICONS["stop", 24, 24]) - - sizer.Add(self._progress, 1, wx.ALL | wx.EXPAND, 5) - sizer.Add(self._stop, 0, wx.ALL | wx.EXPAND, 5) - - self.SetSizer(sizer) - - self.Layout() - - self.Bind(wx.EVT_BUTTON, self.on_stop, self._stop) - - def finish_status(self): - self._progress.SetBarColor(wx.BLUE) - self._progress.Refresh() - self._stop.Disable() - - def on_stop(self, event): - d = wx.MessageDialog( - None, - "This will stop the current task. Do you really want to stop it ?", - "Question", - wx.YES_NO | wx.YES_DEFAULT | wx.ICON_WARNING, - ) - - if d.ShowModal() == wx.ID_NO: - return - - self._stop.Disable() - self.stop() - - def start_status(self): - self._stop.Enable() - self._progress.SetValue(0) - self._progress.SetRange(self.nSteps) - self._progress.SetBarColor(wx.GREEN) - - def stop_status(self): - self._progress.SetBarColor(wx.RED) - self._progress.Refresh() - - def update_status(self): - self._progress.SetValue(self.currentStep) - self._progress.Refresh() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/ComboWidgets/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/ComboWidgets/__init__.py deleted file mode 100644 index 85a85828fe..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/ComboWidgets/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/ComboWidgets/__init__.py -# @brief Implements module/class/test __init__ -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/ControllerPanel.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/ControllerPanel.py deleted file mode 100644 index 0c9cca90e8..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/ControllerPanel.py +++ /dev/null @@ -1,88 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/ControllerPanel.py -# @brief Implements module/class/test ControllerPanel -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import collections - -import wx -import wx.aui as wxaui -import wx.py as wxpy - -from MDANSE.GUI.JobControllerPanel import JobControllerPanel -from MDANSE.GUI.Icons import ICONS - - -class ControllerPanel(wx.Panel): - def __init__(self, parent): - wx.Panel.__init__(self, parent, wx.ID_ANY) - - self.build_panel() - - self.build_layout() - - @property - def pages(self): - return self._pages - - def build_panel(self): - self._notebook = wxaui.AuiNotebook( - self, style=wxaui.AUI_NB_DEFAULT_STYLE & ~wxaui.AUI_NB_CLOSE_ON_ACTIVE_TAB - ) - - self._pages = collections.OrderedDict() - self._pages["logger"] = wx.TextCtrl( - self, - style=wx.TE_MULTILINE - | wx.TE_READONLY - | wx.TE_BESTWRAP - | wx.HSCROLL - | wx.TE_AUTO_URL, - ) - self._pages["console"] = wxpy.shell.Shell(self) - self._pages["jobs"] = JobControllerPanel(self) - - # wxpython 2.9 compatibility - if wx.VERSION[:2] > (2, 8): - il = wx.ImageList(16, 16) - il.Add(ICONS["log", 16, 16]) - il.Add(ICONS["shell", 16, 16]) - il.Add(ICONS["hourglass", 16, 16]) - - self._notebook.AddPage(self._pages["logger"], "Logger") - self._notebook.AddPage(self._pages["console"], "Console") - self._notebook.AddPage(self._pages["jobs"], "Jobs") - - self._notebook.AssignImageList(il) - - self._notebook.SetPageImage(0, 0) - self._notebook.SetPageImage(1, 1) - self._notebook.SetPageImage(2, 2) - - else: - self._notebook.AddPage( - self._pages["logger"], "Logger", bitmap=ICONS["log", 16, 16] - ) - self._notebook.AddPage( - self._pages["console"], "Console", bitmap=ICONS["shell", 16, 16] - ) - self._notebook.AddPage( - self._pages["jobs"], "Jobs", bitmap=ICONS["hourglass", 16, 16] - ) - - def build_layout(self): - sizer = wx.BoxSizer(wx.VERTICAL) - - sizer.Add(self._notebook, 1, wx.EXPAND, 0) - - self.SetSizer(sizer) diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/DataController.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/DataController.py deleted file mode 100644 index ba57fbe8ed..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/DataController.py +++ /dev/null @@ -1,59 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/DataController.py -# @brief Implements module/class/test DataController -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import collections -import weakref - -from MDANSE.Core.Singleton import Singleton - -from MDANSE.GUI import PUBLISHER - - -class DataController(collections.OrderedDict, metaclass=Singleton): - def __delitem__(self, item): - if item not in self: - return - - if self.has_proxy(item): - return - else: - collections.OrderedDict.__delitem__(self, item) - PUBLISHER.sendMessage("msg_delete_input_data", message=item) - - def __getitem__(self, key): - data = collections.OrderedDict.__getitem__(self, key) - - return weakref.proxy(data) - - def __setitem__(self, item, value): - if item in self: - return - - collections.OrderedDict.__setitem__(self, item, value) - - PUBLISHER.sendMessage("msg_load_input_data", message=value) - - def has_proxy(self, item): - """ - Return the number of weak references related to a data stored in the data controller - """ - - return ( - weakref.getweakrefcount(collections.OrderedDict.__getitem__(self, item)) - != 0 - ) - - -DATA_CONTROLLER = DataController() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/DataTreePanel.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/DataTreePanel.py deleted file mode 100644 index af14cb8562..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/DataTreePanel.py +++ /dev/null @@ -1,155 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/DataTreePanel.py -# @brief Implements module/class/test DataTreePanel -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx - -from MDANSE.GUI import PUBLISHER -from MDANSE.GUI.DataController import DATA_CONTROLLER - - -class DataObject(wx.TextDataObject): - def __init__(self, pluginStr): - wx.TextDataObject.__init__(self) - - self.SetText(pluginStr) - - -class DataTreePanel(wx.Panel): - def __init__(self, parent): - wx.Panel.__init__(self, parent, wx.ID_ANY) - - self.build_panel() - - self.build_layout() - - self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.on_double_click_data) - self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.on_drag_data) - self.Bind(wx.EVT_TREE_KEY_DOWN, self.on_delete_data, self._tree) - - self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy) - - PUBLISHER.subscribe(self.msg_load_input_data, "msg_load_input_data") - PUBLISHER.subscribe(self.msg_delete_input_data, "msg_delete_input_data") - - @property - def tree(self): - return self._tree - - def OnDestroy(self, event): - PUBLISHER.unsubscribe(self.msg_load_input_data, "msg_load_input_data") - PUBLISHER.unsubscribe(self.msg_delete_input_data, "msg_delete_input_data") - event.Skip() - - def msg_load_input_data(self, message): - if message is None: - return - - self.add_data(message) - - def msg_delete_input_data(self, message): - if message is None: - return - - item = self.get_tree_item(self._root, message) - - if item is None: - return - - parentItem = self._tree.GetItemParent(item) - - self._tree.Delete(item) - - if not self._tree.ItemHasChildren(parentItem): - self._tree.Delete(parentItem) - - def get_tree_item(self, node, name): - for item in self.get_children(node): - data = self._tree.GetItemData(item) - if data is not None: - if data.GetData() == name: - return item - match = self.get_tree_item(item, name) - if match is not None: - return match - - return None - - def get_children(self, item): - item, _ = self._tree.GetFirstChild(item) - - while item.IsOk(): - yield item - item = self._tree.GetNextSibling(item) - - def add_data(self, data): - item = None - for cItem in self.get_children(self._root): - if data._type == self._tree.GetItemText(cItem): - item = cItem - break - if item is None: - item = self._tree.AppendItem(self._root, data._type, data=None) - - self._tree.AppendItem(item, data.shortname, data=data.name) - - self._tree.ExpandAll() - - def build_panel(self): - self._tree = wx.TreeCtrl( - self, wx.ID_ANY, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT - ) - - self._root = self._tree.AddRoot("root") - - def build_layout(self): - sizer = wx.BoxSizer(wx.VERTICAL) - - sizer.Add(self._tree, 1, wx.EXPAND, 0) - - self.SetSizer(sizer) - - def on_delete_data(self, event): - keycode = event.GetKeyCode() - - if keycode == wx.WXK_DELETE: - item = self._tree.GetSelection() - itemData = self._tree.GetItemData(item) - - if itemData is None: - return - - if itemData.GetData() is None: - return - - del DATA_CONTROLLER[itemData.GetData()] - - def on_double_click_data(self, event): - itemData = self._tree.GetItemData(event.GetItem()) - - self.TopLevelParent.panels["working"].drop(itemData) - - def on_drag_data(self, event): - containerStr = self._tree.GetItemData(event.GetItem()).GetData() - - if containerStr is None: - return - - dropSource = wx.DropSource(self) - - data = DataObject(containerStr) - - dropSource.SetData(data) - - dropSource.DoDragDrop(wx.Drag_CopyOnly) diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/ElementsDatabaseEditor.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/ElementsDatabaseEditor.py deleted file mode 100644 index 2b0711cdd7..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/ElementsDatabaseEditor.py +++ /dev/null @@ -1,423 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/ElementsDatabaseEditor.py -# @brief Implements module/class/test ElementsDatabaseEditor -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx -import wx.grid as wxgrid - -from MDANSE import PLATFORM -from MDANSE.Chemistry import ATOMS_DATABASE -from MDANSE.Core.Error import Error -from MDANSE.Core.Singleton import Singleton - - -class ElementsDatabaseError(Error): - pass - - -class NewElementDialog(wx.Dialog): - """ - This class pops up a dialog that prompts the user for registering a new element in the database. - """ - - def __init__(self, *args, **kwargs): - """ - The constructor. - """ - - # The base class constructor - wx.Dialog.__init__(self, *args, **kwargs) - - self.Center() - - panel = wx.Panel(self, wx.ID_ANY) - - # Create text and answer box widgets - staticLabel0 = wx.StaticText(panel, -1, "Enter element settings") - staticLabel1 = wx.StaticText(panel, wx.ID_ANY, "Short name") - self._entry = wx.TextCtrl(panel, wx.ID_ANY) - staticLabel2 = wx.StaticText(panel, wx.ID_ANY, "Long name") - self._element = wx.TextCtrl(panel, id=wx.ID_ANY) - staticLabel3 = wx.StaticText(panel, wx.ID_ANY, "Symbol") - self._symbol = wx.TextCtrl(panel, wx.ID_ANY) - - # Create buttons - ok = wx.Button(panel, wx.ID_OK, "OK") - ok.SetDefault() - cancel = wx.Button(panel, wx.ID_CANCEL, "Cancel") - - # Create main sizer and add the instruction text to the top - main_sizer = wx.FlexGridSizer(rows=3, cols=1, vgap=10, hgap=10) - main_sizer.Add(staticLabel0, 0, wx.ALL | wx.ALIGN_LEFT, 5) - - # Place the other text and answer box widgets in a grid - body_sizer = wx.FlexGridSizer(rows=4, cols=2, vgap=10, hgap=20) - body_sizer.Add(staticLabel1, flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=10) - body_sizer.Add( - self._entry, flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.EXPAND, border=10 - ) - body_sizer.Add(staticLabel2, flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=10) - body_sizer.Add( - self._element, - flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.EXPAND, - border=10, - ) - body_sizer.Add(staticLabel3, flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=10) - body_sizer.Add( - self._symbol, - flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.EXPAND, - border=10, - ) - main_sizer.Add(body_sizer, 0, wx.ALL | wx.EXPAND, 5) - - # Place buttons to appear as a standard dialogue - button_sizer = wx.StdDialogButtonSizer() - button_sizer.AddButton(cancel) - button_sizer.AddButton(ok) - main_sizer.Add(button_sizer, 0, wx.EXPAND) - button_sizer.Realize() - - # Add growth properties - main_sizer.AddGrowableCol(0) - main_sizer.AddGrowableRow(0) - body_sizer.AddGrowableCol(1) - - # Give a minimum size for the dialog but ensure that everything fits inside - self.SetMinSize(wx.Size(400, 160)) - panel.SetSizerAndFit(main_sizer) - self.Fit() - - def GetValue(self, event=None): - """ - Handler called when the user clicks on the OK button of the property dialog. - """ - - entry = str(self._entry.GetValue().strip()) - if not entry: - raise ElementsDatabaseError("Empty entry name") - - element = str(self._element.GetValue().strip()) - if not element: - raise ElementsDatabaseError("Empty name") - - symbol = str(self._symbol.GetValue().strip()) - if not symbol: - raise ElementsDatabaseError("Empty symbol") - - return entry, element, symbol - - -class NewPropertyDialog(wx.Dialog): - """ - This class pops up a dialog that prompts the user for registering a new property in the database. - """ - - def __init__(self, *args, **kwargs): - """ - The constructor. - """ - - # The base class constructor - wx.Dialog.__init__(self, *args, **kwargs) - - self.Center() - - panel = wx.Panel(self, wx.ID_ANY) - - # Create text and answer box widgets - staticLabel0 = wx.StaticText(panel, -1, "Enter property settings") - staticLabel1 = wx.StaticText(panel, wx.ID_ANY, "Name") - self.name = wx.TextCtrl(panel, wx.ID_ANY) - staticLabel2 = wx.StaticText(panel, wx.ID_ANY, "Property type") - self.propertyType = wx.ComboBox( - panel, - id=wx.ID_ANY, - choices=list(ATOMS_DATABASE._TYPES.keys()), - style=wx.CB_READONLY, - ) - - # Create button widgets - cancel = wx.Button(panel, wx.ID_CANCEL, "Cancel") - ok = wx.Button(panel, wx.ID_OK, "OK") - ok.SetDefault() - - # Create the main sizer and add the instruction - main_sizer = wx.FlexGridSizer(rows=3, cols=1, vgap=10, hgap=10) - main_sizer.Add(staticLabel0, 0, wx.ALL | wx.ALIGN_LEFT, 5) - - # Create sizer for the other texts and the answer boxes, and add the widets - body_sizer = wx.FlexGridSizer(rows=2, cols=2, vgap=15, hgap=20) - main_sizer.Add(body_sizer, flag=wx.EXPAND) - body_sizer.Add( - staticLabel1, - flag=wx.ALIGN_LEFT | wx.LEFT | wx.ALIGN_CENTER_VERTICAL, - border=10, - ) - body_sizer.Add(self.name, flag=wx.ALIGN_LEFT | wx.EXPAND | wx.RIGHT, border=10) - body_sizer.Add(staticLabel2, flag=wx.ALIGN_LEFT | wx.LEFT, border=10) - body_sizer.Add( - self.propertyType, flag=wx.ALIGN_LEFT | wx.EXPAND | wx.RIGHT, border=10 - ) - - # Button sizer and widgets - button_sizer = wx.StdDialogButtonSizer() - button_sizer.AddButton(cancel) - button_sizer.AddButton(ok) - button_sizer.Realize() - main_sizer.Add(button_sizer, 0, wx.EXPAND) - - # Allow for changing size - main_sizer.AddGrowableCol(0) - main_sizer.AddGrowableRow(1) - body_sizer.AddGrowableCol(1) - - # Give a minimum size for the dialog but ensure that everything fits inside - self.SetMinSize(wx.Size(400, 160)) - panel.SetSizerAndFit(main_sizer) - self.Fit() - - def GetValue(self, event=None): - """ - Handler called when the user clicks on the OK button of the property dialog. - """ - - pname = str(self.name.GetValue().strip()) - - pclass = str(self.propertyType.GetValue()) - - return pname, pclass - - -class Database(wxgrid.PyGridTableBase, metaclass=Singleton): - def GetColLabelValue(self, col): - return "%s" % ATOMS_DATABASE.properties[col] - - def GetNumberCols(self): - return ATOMS_DATABASE.n_properties - - def GetNumberRows(self): - return ATOMS_DATABASE.n_atoms - - def GetRowLabelValue(self, row): - return ATOMS_DATABASE.atoms[row] - - def GetValue(self, row, col): - atom = ATOMS_DATABASE.atoms[row] - pname = ATOMS_DATABASE.properties[col] - return ATOMS_DATABASE.get_value(atom, pname) - - def SetValue(self, row, col, val): - atom = ATOMS_DATABASE.atoms[row] - pname = ATOMS_DATABASE.properties[col] - - ATOMS_DATABASE.set_value(atom, pname, val) - - def add_column(self, pname, ptype): - ATOMS_DATABASE.add_property(pname, ptype) - - self.notify_grid(wxgrid.GRIDTABLE_NOTIFY_COLS_APPENDED, 1) - - def add_row(self, entry, element, symbol): - if ATOMS_DATABASE.has_atom(entry): - return - - ATOMS_DATABASE.add_atom(entry) - ATOMS_DATABASE.set_value(entry, "element", element) - ATOMS_DATABASE.set_value(entry, "symbol", symbol) - - self.notify_grid(wxgrid.GRIDTABLE_NOTIFY_ROWS_APPENDED, 1) - - def notify_grid(self, msg, count): - """Notifies the grid of the message and the affected count.""" - - tbl_msg = wxgrid.GridTableMessage(self, msg, count) - - self.GetView().ProcessTableMessage(tbl_msg) - - @staticmethod - def save(): - ATOMS_DATABASE.save() - - -class ElementsDatabaseEditor(wx.Frame): - def __init__(self, parent): - """ - The constructor. - :Parameters: - #. parent (wx window): the parent window. - """ - - wx.Frame.__init__( - self, - parent, - wx.ID_ANY, - title="Elements database editor", - style=wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER, - ) - - self._database = Database() - - self.build_dialog() - - self.build_menu() - - self.CenterOnParent() - - def build_dialog(self): - mainPanel = wx.Panel(self, wx.ID_ANY) - - mainSizer = wx.BoxSizer(wx.VERTICAL) - - # The wx grid that will store the database. - self._grid = wxgrid.Grid(mainPanel) - - # The grid style is set. This will be a standard text editor. - self._grid.SetDefaultEditor(wxgrid.GridCellTextEditor()) - - self._grid.SetTable(self._database) - - self._grid.SetDefaultCellBackgroundColour(wx.Colour("LIGHT BLUE")) - - self._grid.SetColLabelAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) - - self._grid.SetRowLabelAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTRE) - - self._grid.SetColMinimalAcceptableWidth(100) - - self._grid.Bind(wxgrid.EVT_GRID_CELL_CHANGED, self.on_edit_cell) - self._grid.Bind(wxgrid.EVT_GRID_CELL_RIGHT_CLICK, self.on_show_popup_menu) - mainSizer.Add(self._grid, 1, wx.EXPAND | wx.ALL, 5) - - mainPanel.SetSizer(mainSizer) - - self.SetSize((800, 400)) - - self.Bind(wx.EVT_CONTEXT_MENU, self.on_show_popup_menu) - - self.Bind(wx.EVT_CLOSE, self.on_close) - - def build_menu(self): - menubar = wx.MenuBar() - - fileMenu = wx.Menu() - saveItem = fileMenu.Append(wx.ID_ANY, "&Save database\tCtrl+S") - menubar.Append(fileMenu, "File") - - databaseMenu = wx.Menu() - addElementItem = databaseMenu.Append(wx.ID_ANY, "New element") - addPropertyItem = databaseMenu.Append(wx.ID_ANY, "New property") - menubar.Append(databaseMenu, "Database") - - self.Bind(wx.EVT_MENU, self.on_add_element, addElementItem) - self.Bind(wx.EVT_MENU, self.on_add_property, addPropertyItem) - - self.Bind(wx.EVT_MENU, self.on_save_database, saveItem) - - self.SetMenuBar(menubar) - - def on_show_popup_menu(self, event): - menu = wx.Menu() - - saveItem = menu.Append(wx.ID_ANY, "Save database") - menu.AppendSeparator() - - addElementItem = menu.Append(wx.ID_ANY, "New element") - addPropertyItem = menu.Append(wx.ID_ANY, "New property") - - self.Bind(wx.EVT_MENU, self.on_add_element, addElementItem) - self.Bind(wx.EVT_MENU, self.on_add_property, addPropertyItem) - - self.Bind(wx.EVT_MENU, self.on_save_database, saveItem) - - self.PopupMenu(menu) - - menu.Destroy() - - def on_close(self, event): - d = wx.MessageDialog( - None, - "This will close the database editor. Continue ?", - "Question", - wx.YES_NO | wx.YES_DEFAULT | wx.ICON_WARNING, - ) - - if d.ShowModal() == wx.ID_NO: - return - - self.Destroy() - - def on_edit_cell(self, event): - event.Skip() - - self._grid.Refresh() - - def on_add_element(self, event): - """ - Handler called when the user add new elements to the database. - """ - - d = NewElementDialog(self, title="Add element", size=(400, 220)) - - # If the new element dialog is closed by clicking on OK. - if d.ShowModal() == wx.ID_CANCEL: - return - - # Get rid of wxpython unicode string formatting - entry, element, symbol = d.GetValue() - - self._database.add_row(entry, element, symbol) - - def on_add_property(self, message): - """ - Handler called when the user add a property to the database. - """ - - d = NewPropertyDialog(self, title="Add property") - - if d.ShowModal() == wx.ID_CANCEL: - return - - pname, ptype = d.GetValue() - - if not pname: - return - - # Get rid of wxpython unicode string formatting - pname = str(pname) - - self._database.add_column(pname, ptype) - - def on_save_database(self, event=None): - """ - Handler called when the user saves the database to its defaut location. - """ - - d = wx.MessageDialog( - None, - "This will overwrite your database. Continue ?", - "Question", - wx.YES_NO | wx.YES_DEFAULT | wx.ICON_WARNING, - ) - - if d.ShowModal() == wx.ID_NO: - return - - self._database.save() - - -if __name__ == "__main__": - app = wx.App(False) - f = ElementsDatabaseEditor(None) - f.Show() - app.MainLoop() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Events/JobControllerEvent.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Events/JobControllerEvent.py deleted file mode 100644 index f0742cd753..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Events/JobControllerEvent.py +++ /dev/null @@ -1,45 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Events/JobControllerEvent.py -# @brief Implements module/class/test JobControllerEvent -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx - -EVT_JOB_CONTROLLER_ID = wx.NewId() -EVT_JOB_CRASH_ID = wx.NewId() - - -def EVT_JOB_CONTROLLER(win, func): - win.Connect(-1, -1, EVT_JOB_CONTROLLER_ID, func) - - -def EVT_JOB_CRASH(win, func): - win.Connect(-1, -1, EVT_JOB_CRASH_ID, func) - - -class JobControllerEvent(wx.PyEvent): - def __init__(self, runningJobs): - wx.PyEvent.__init__(self) - - self.SetEventType(EVT_JOB_CONTROLLER_ID) - - self.runningJobs = runningJobs - - -class JobCrashEvent(wx.PyEvent): - def __init__(self, traceback): - wx.PyEvent.__init__(self) - - self.SetEventType(EVT_JOB_CRASH_ID) - - self.traceback = traceback diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Events/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Events/__init__.py deleted file mode 100644 index 09933a42f0..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Events/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Events/__init__.py -# @brief Implements module/class/test __init__ -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Handlers/ConsoleHandler.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Handlers/ConsoleHandler.py deleted file mode 100644 index bdfd11c459..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Handlers/ConsoleHandler.py +++ /dev/null @@ -1,92 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Handlers/ConsoleHandler.py -# @brief Implements module/class/test ConsoleHandler -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import logging - -import wx - -from MDANSE import REGISTRY -from MDANSE.Framework.Handlers.IHandler import IHandler -from MDANSE.Logging.Formatters import Formatter - - -class ConsoleHandler(IHandler, logging.Handler): - """Sets up a GUI handler for the MDANSE logger. - - Emits the logging message to the MDANSE GUI console. - - @note: inherits from logging.Handler class that sets a generic handler. - """ - - COLORS = { - "DEBUG": wx.GREEN, - "INFO": wx.BLACK, - "WARNING": wx.BLUE, - "ERROR": wx.RED, - "CRITICAL": wx.RED, - "FATAL": wx.RED, - } - - def __init__(self, window): - """ - The constructor. - - @param console: the parent widget for the textctrl. - @type console: wx widget - """ - - logging.Handler.__init__(self) - - self.setFormatter(Formatter()) - - self._window = window - - # Creates a wx text attribute. - self.style = wx.TextAttr() - - # Set its font to a non proporiotnal font. - self.style.SetFont(wx.Font(10, wx.FONTFAMILY_MODERN, wx.NORMAL, wx.NORMAL)) - - def emit(self, record): - """ - Send the log message to a wx.TextCtrl widget. - - @param record: the log message. - @type record: logging.LogRecord - """ - - record.msg = record.msg.strip() - if not record.msg: - return - - self.style.SetTextColour(ConsoleHandler.COLORS.get(record.levelname, wx.BLACK)) - - # Set the the created text attribute as the default style for the text ctrl. - self._window.SetDefaultStyle(self.style) - - # Append the log message to the text ctrl. - self._window.AppendText(self.format(record)) - - self._window.AppendText("\n") - - def write(self, message): - record = logging.LogRecord( - "console", logging.INFO, None, None, message, None, None, None - ) - - self.emit(record) - - -REGISTRY["console"] = ConsoleHandler diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Handlers/DialogHandler.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Handlers/DialogHandler.py deleted file mode 100644 index 6f0b20dba7..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Handlers/DialogHandler.py +++ /dev/null @@ -1,43 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Handlers/DialogHandler.py -# @brief Implements module/class/test DialogHandler -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import logging - -import wx - -from MDANSE import REGISTRY -from MDANSE.Framework.Handlers.IHandler import IHandler - - -class DialogHandler(IHandler, logging.Handler): - ICONS = { - "DEBUG": wx.ICON_INFORMATION, - "CRITICAL": wx.ICON_ERROR, - "ERROR": wx.ICON_ERROR, - "INFO": wx.ICON_INFORMATION, - "WARNING": wx.ICON_WARNING, - } - - def emit(self, record): - icon = DialogHandler.ICONS[record.levelname] - - d = wx.MessageDialog( - None, message=self.format(record), style=wx.OK | wx.STAY_ON_TOP | icon - ) - - d.ShowModal() - - -REGISTRY["dialog"] = DialogHandler diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Handlers/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Handlers/__init__.py deleted file mode 100644 index 0f8ad88e3f..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Handlers/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Handlers/__init__.py -# @brief Implements module/class/test __init__ -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/__init__.py deleted file mode 100644 index a7f2b1943d..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/__init__.py +++ /dev/null @@ -1,38 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Icons/__init__.py -# @brief Implements module/class/test __init__ -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import os - -import wx - -from MDANSE.Core.Singleton import Singleton - - -class Icons(object, metaclass=Singleton): - def __getitem__(self, item): - name, width, height = item - - icon = os.path.join(os.path.dirname(__file__), name + ".png") - - image = wx.Bitmap(icon).ConvertToImage() - image = image.Scale(width, height, wx.IMAGE_QUALITY_HIGH) - - return wx.Bitmap(image) - - def add_icon(self, name, path): - self._icons[name] = path - - -ICONS = Icons() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/mdanse.png b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/mdanse.png deleted file mode 100644 index d413a8da29..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/mdanse.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/JobControllerPanel.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/JobControllerPanel.py deleted file mode 100644 index 287cdc04c6..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/JobControllerPanel.py +++ /dev/null @@ -1,434 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/JobControllerPanel.py -# @brief Implements module/class/test JobControllerPanel -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import collections -import pickle -import datetime -import glob -import os -import threading -import time - -import wx -import wx.lib.intctrl as intctrl - -from MDANSE.Core.Platform import PLATFORM -from MDANSE.Core.Singleton import Singleton -from MDANSE.Framework.Status import convert_duration, total_seconds - -from MDANSE.GUI import PUBLISHER -from MDANSE.GUI.Icons import ICONS -from MDANSE.GUI.Events.JobControllerEvent import EVT_JOB_CONTROLLER, JobControllerEvent - - -class JobController(threading.Thread, metaclass=Singleton): - """ - This class sets up the job controlling daemon that will regurlarly check for the status of running MDANSE jobs. - - The job controller run on a separate thread in order to non-block the main thread. - - When the thread is running, it will check every 10s the status of the MDANSE running jobs by looking at their - corresponding temporary pickle files. It unpickles them and updates the :py:attr:`_runningJobs` dictionnary used to store - the information about each running jobs (state, progress, eta, name ...). That dictionnary is passed to the job - controller panel widget using wx.PostEvent mechanism. In doing the job controller panel widget just has to bind - to EVT_JOB_CONTROLLER and it will receive the updated version of :py:attr:`_runningJobs` dictionnary every time - the :py:meth:run is called. - """ - - def __init__(self, window, start=False): - """ - - :param window: the wx object that will be notify when job controller is updated - :type window: wx object - :param start: if True the job controller thread is started at __init__ stage. - :type start: bool - """ - - threading.Thread.__init__(self) - - self.setDaemon(True) - - # The wx object related to this thread - self._window = window - - self._stop = threading.Event() - - self._runningJobs = collections.OrderedDict() - - # This variable is used to keep track whether or not it is the first run of the thread. - self._firstThreadRun = True - - if start: - self.start() - - @property - def runningJobs(self): - return self._runningJobs - - def kill_job(self, info): - if info["name"] in self._runningJobs: - if info["state"] == "running": - try: - PLATFORM.kill_process(info["pid"]) - except: - pass - - del self._runningJobs[info["name"]] - - if os.path.exists(info["temporary_file"]): - try: - os.unlink(info["temporary_file"]) - except: - pass - - self.update() - - def run(self): - while not self._stop.is_set(): - self.update() - self._stop.wait(10.0) - - def stop(self): - self._stop.set() - - def update(self, init=False): - pids = PLATFORM.get_processes_info() - - # The list of the registered jobs. - jobs = [ - f - for f in glob.glob(os.path.join(PLATFORM.temporary_files_directory(), "*")) - ] - - # Loop over the job registered at the previous controller check point - for job in list(self._runningJobs.keys()): - # Case where a job has finished during two controller check points (i.e. its temporary file has been deleted) - if self._runningJobs[job]["state"] == "finished": - continue - - # Case where the jobs has finished properly (e.g. its temporary file has been removed) - if not job in jobs: - self._runningJobs[job]["eta"] = "N/A" - self._runningJobs[job]["progress"] = 100 - self._runningJobs[job]["state"] = "finished" - start = datetime.datetime.strptime( - self._runningJobs[job]["start"], "%d-%m-%Y %H:%M:%S" - ) - self._runningJobs[job]["elapsed"] = ( - "%02d:%02dh:%02dm:%02ds" - % convert_duration(total_seconds(datetime.datetime.today() - start)) - ) - - # Loop over the job whose temporary files are still present - for job in jobs: - # Open the job temporary file - try: - f = open(job, "rb") - info = pickle.load(f) - f.close() - - # If the file could not be opened/unpickled for whatever reason, try at the next checkpoint - except: - continue - - # The job file could be opened and unpickled properly - else: - name = info["name"] - - # Check that the pid of the running job corresponds to an active pid. - running = info["pid"] in pids - - # If so, check that the corresponding pid actually corresponds to the job by comparing - # the job starting date and the pid creation date. - if running: - jobStartingTime = datetime.datetime.strptime( - info["start"], "%d-%m-%Y %H:%M:%S" - ) - procStartingTime = datetime.datetime.strptime( - pids[info["pid"]], "%d-%m-%Y %H:%M:%S" - ) - running = jobStartingTime >= procStartingTime - - if not running: - info["state"] = "aborted" - - # If the job was aborted, display the traceback on the dialog logger and remove the corresponding job temporary file - if self._firstThreadRun and info["state"] == "aborted": - self.kill_job(info) - continue - - self._runningJobs[name] = info - - wx.PostEvent(self._window, JobControllerEvent(self._runningJobs)) - - self._firstThreadRun = False - - -class JobControllerPanel(wx.ScrolledWindow): - columns = [ - ("name", (180, -1)), - ("pid", (60, -1)), - ("start", (150, -1)), - ("elapsed", (140, -1)), - ("state", (90, -1)), - ("progress", (-1, -1)), - ("eta", (120, -1)), - ("kill", (50, -1)), - ] - - def __init__(self, parent): - wx.ScrolledWindow.__init__(self, parent, id=wx.ID_ANY) - - self.SetScrollbars(pixelsPerUnitX=1, pixelsPerUnitY=1, noUnitsX=50, noUnitsY=50) - - self.parent = parent - - self._gbSizer = wx.GridBagSizer(0, 0) - - for i, (col, s) in enumerate(JobControllerPanel.columns): - self._gbSizer.Add( - wx.TextCtrl( - self, - wx.ID_ANY, - value=col.upper(), - size=s, - style=wx.TE_READONLY | wx.ALIGN_CENTER_HORIZONTAL, - ), - pos=(0, i), - flag=wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL, - ) - - self._gbSizer.AddGrowableCol(5) - - self.SetSizer(self._gbSizer) - - self._jobsController = JobController(self, True) - - self._jobs = {} - - EVT_JOB_CONTROLLER(self, self.on_update) - - self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy) - - PUBLISHER.subscribe(self.msg_start_job, "msg_start_job") - - def __del__(self): - self._jobsController.stop() - while self._jobsController.is_alive(): - time.sleep(0.01) - - def OnDestroy(self, event): - PUBLISHER.subscribe(self.msg_start_job, "msg_start_job") - event.Skip() - - def msg_start_job(self, message): - t = threading.Thread(target=self.updateJobsController) - t.start() - - def updateJobsController(self): - time.sleep(PLATFORM.jobs_launch_delay()) - self._jobsController.update() - - def on_display_info(self, event): - row = self._gbSizer.GetItemPosition(event.GetEventObject())[0] - name = self._gbSizer.FindItemAtPosition((row, 0)).Window.GetLabel() - - f = wx.Frame(self, size=(800, 500)) - - panel = wx.Panel(f, wx.ID_ANY) - - sizer = wx.BoxSizer(wx.VERTICAL) - - info = self._jobsController.runningJobs[name]["info"].strip() - if not info: - info = "No information available about %r job." % name - - self._info = wx.TextCtrl( - panel, wx.ID_ANY, style=wx.TE_AUTO_SCROLL | wx.TE_READONLY | wx.TE_MULTILINE - ) - self._info.SetValue(info) - - sizer.Add(self._info, 1, wx.ALL | wx.EXPAND, 5) - - panel.SetSizer(sizer) - - f.Show() - - def on_display_traceback(self, event): - row = self._gbSizer.GetItemPosition(event.GetEventObject())[0] - name = self._gbSizer.FindItemAtPosition((row, 0)).Window.GetLabel() - - f = wx.Frame(self, size=(800, 500)) - - panel = wx.Panel(f, wx.ID_ANY) - - sizer = wx.BoxSizer(wx.VERTICAL) - - tb = self._jobsController.runningJobs[name]["traceback"].strip() - if not tb: - tb = "No traceback available about %r job." % name - - self._tb = wx.TextCtrl( - panel, wx.ID_ANY, style=wx.TE_AUTO_SCROLL | wx.TE_READONLY | wx.TE_MULTILINE - ) - self._tb.SetValue(tb) - - sizer.Add(self._tb, 1, wx.ALL | wx.EXPAND, 5) - - panel.SetSizer(sizer) - - f.Show() - - def on_kill_job(self, event): - row = self._gbSizer.GetItemPosition(event.GetEventObject())[0] - name = self._gbSizer.FindItemAtPosition((row, 0)).Window.GetLabel() - - d = wx.MessageDialog( - None, - "Do you really want to kill job %r ?" % name, - "Question", - wx.YES_NO | wx.YES_DEFAULT | wx.ICON_EXCLAMATION, - ) - if d.ShowModal() == wx.ID_YES: - self._jobsController.kill_job(self._jobsController.runningJobs[name]) - - def on_update(self, event): - runningJobs = event.runningJobs - - # Remove the widgets corresponding to the jobs that are not running anymore - for k, v in list(self._jobs.items()): - if k in runningJobs: - continue - - row, _ = self._gbSizer.GetItemPosition(v["name"]) - for c in range(self._gbSizer.GetCols()): - w = self._gbSizer.FindItemAtPosition((row, c)) - w.GetWindow().Destroy() - del self._jobs[k] - - for r in range(row + 1, self._gbSizer.GetRows()): - for i in range(self._gbSizer.GetCols()): - w = self._gbSizer.FindItemAtPosition((r, i)) - if w is None: - continue - self._gbSizer.SetItemPosition(w.GetWindow(), (r - 1, i)) - - for jobName, jobStatus in list(runningJobs.items()): - if jobName in self._jobs: - self._jobs[jobName]["progress"].SetValue(jobStatus["progress"]) - self._jobs[jobName]["elapsed"].SetValue(jobStatus["elapsed"]) - self._jobs[jobName]["state"].SetLabel(jobStatus["state"]) - self._jobs[jobName]["eta"].SetValue(jobStatus["eta"]) - else: - self._jobs[jobName] = {} - self._jobs[jobName]["name"] = wx.Button( - self, wx.ID_ANY, style=wx.BU_EXACTFIT, label=jobStatus["name"] - ) - self._jobs[jobName]["pid"] = intctrl.IntCtrl( - self, - wx.ID_ANY, - style=wx.TE_READONLY | wx.ALIGN_CENTER_HORIZONTAL, - value=jobStatus["pid"], - ) - self._jobs[jobName]["start"] = wx.TextCtrl( - self, - wx.ID_ANY, - style=wx.TE_READONLY | wx.ALIGN_CENTER_HORIZONTAL, - value=jobStatus["start"], - ) - self._jobs[jobName]["elapsed"] = wx.TextCtrl( - self, - wx.ID_ANY, - style=wx.TE_READONLY | wx.ALIGN_CENTER_HORIZONTAL, - value=jobStatus["elapsed"], - ) - self._jobs[jobName]["state"] = wx.Button( - self, wx.ID_ANY, style=wx.BU_EXACTFIT, label=jobStatus["state"] - ) - self._jobs[jobName]["progress"] = wx.Gauge(self, wx.ID_ANY, range=100) - self._jobs[jobName]["progress"].SetValue(jobStatus["progress"]) - self._jobs[jobName]["eta"] = wx.TextCtrl( - self, - wx.ID_ANY, - style=wx.TE_READONLY | wx.ALIGN_CENTER_HORIZONTAL, - value=jobStatus["eta"], - ) - self._jobs[jobName]["kill"] = wx.BitmapButton( - self, wx.ID_ANY, ICONS["stop", 16, 16] - ) - - r = len(self._jobs) - - self._gbSizer.Add( - self._jobs[jobName]["name"], - pos=(r, 0), - flag=wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL, - ) - self._gbSizer.Add( - self._jobs[jobName]["pid"], - pos=(r, 1), - flag=wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL, - ) - self._gbSizer.Add( - self._jobs[jobName]["start"], - pos=(r, 2), - flag=wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL, - ) - self._gbSizer.Add( - self._jobs[jobName]["elapsed"], - pos=(r, 3), - flag=wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL, - ) - self._gbSizer.Add( - self._jobs[jobName]["state"], - pos=(r, 4), - flag=wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL, - ) - self._gbSizer.Add( - self._jobs[jobName]["progress"], - pos=(r, 5), - flag=wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL, - ) - self._gbSizer.Add( - self._jobs[jobName]["eta"], - pos=(r, 6), - flag=wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL, - ) - self._gbSizer.Add( - self._jobs[jobName]["kill"], - pos=(r, 7), - flag=wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL, - ) - - if jobStatus["state"] == "aborted": - self._jobs[jobName]["name"].SetBackgroundColour(wx.RED) - - self.Bind(wx.EVT_BUTTON, self.on_display_info, self._jobs[jobName]["name"]) - self.Bind( - wx.EVT_BUTTON, self.on_display_traceback, self._jobs[jobName]["state"] - ) - self.Bind(wx.EVT_BUTTON, self.on_kill_job, self._jobs[jobName]["kill"]) - - self._gbSizer.Layout() - - -if __name__ == "__main__": - app = wx.App(0) - frame = wx.Frame(None, -1, "Job Controller") - - JobController = JobControllerPanel(frame) - - frame.Show(True) - app.MainLoop() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/JobTemplateEditor.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/JobTemplateEditor.py deleted file mode 100644 index 9ac736e3d2..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/JobTemplateEditor.py +++ /dev/null @@ -1,110 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/JobTemplateEditor.py -# @brief Implements module/class/test JobTemplateEditor -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx - -from MDANSE import LOGGER - - -class JobTemplateEditor(wx.Dialog): - def __init__(self, *args, **kwargs): - """ - The constructor. - """ - - # The base class constructor - wx.Dialog.__init__(self, *args, **kwargs) - - self.Center() - - panel = wx.Panel(self, wx.ID_ANY) - - staticLabel0 = wx.StaticText(panel, -1, "Enter property settings") - - subPanel = wx.Panel(panel, wx.ID_ANY) - staticLabel1 = wx.StaticText(subPanel, wx.ID_ANY, "Short name") - self._shortName = wx.TextCtrl(subPanel, wx.ID_ANY) - staticLabel2 = wx.StaticText(subPanel, wx.ID_ANY, "Class name") - self._className = wx.TextCtrl(subPanel, id=wx.ID_ANY) - - staticLine = wx.StaticLine(self, wx.ID_ANY) - - buttonPanel = wx.Panel(self, wx.ID_ANY) - cancelButton = wx.Button(buttonPanel, wx.ID_CANCEL, "Cancel") - saveButton = wx.Button(buttonPanel, wx.ID_OK, "Save") - saveButton.SetDefault() - - panelSizer = wx.BoxSizer(wx.VERTICAL) - panelSizer.Add(staticLabel0, 0, wx.ALL | wx.ALIGN_LEFT, 5) - subsizer = wx.GridBagSizer(5, 5) - subsizer.Add(staticLabel1, pos=(0, 0), flag=wx.ALIGN_CENTER_VERTICAL) - subsizer.Add( - self._shortName, pos=(0, 1), flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND - ) - subsizer.Add(staticLabel2, pos=(1, 0), flag=wx.ALIGN_CENTER_VERTICAL) - subsizer.Add( - self._className, pos=(1, 1), flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND - ) - subsizer.AddGrowableCol(1) - subPanel.SetSizer(subsizer) - panelSizer.Add(subPanel, 0, wx.ALL | wx.EXPAND, 5) - panel.SetSizer(panelSizer) - - btnsizer = wx.StdDialogButtonSizer() - btnsizer.AddButton(cancelButton) - btnsizer.AddButton(saveButton) - btnsizer.Realize() - buttonPanel.SetSizer(btnsizer) - - dlgsizer = wx.BoxSizer(wx.VERTICAL) - dlgsizer.Add(panel, 1, wx.ALL | wx.EXPAND, 5) - dlgsizer.Add(staticLine, 0, wx.ALL | wx.EXPAND, 5) - dlgsizer.Add(buttonPanel, 0, wx.ALL | wx.ALIGN_RIGHT | wx.EXPAND, 5) - - # Bind the top sizer to the dialog. - self.SetSizer(dlgsizer) - - self.Bind(wx.EVT_BUTTON, self.on_save, saveButton) - - def on_save(self, event): - shortName = str(self._shortName.GetValue()).strip() - className = str(self._className.GetValue()).strip() - - if not shortName or not className: - wx.MessageBox( - "You must provide a short name and a class name", - "Invalid input", - wx.OK | wx.ICON_ERROR, - ) - return - - from MDANSE.Framework.Jobs.IJob import IJob - - try: - filename = IJob.save_template(shortName, className) - except (IOError, KeyError) as e: - LOGGER(str(e), "error", ["console"]) - return - - LOGGER("Job template successfully saved to %r." % filename, "info", ["console"]) - self.EndModal(wx.ID_OK) - - -if __name__ == "__main__": - app = wx.App(False) - f = JobTemplateEditor(None) - f.ShowModal() - f.Destroy() - app.MainLoop() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/LogfileFrame.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/LogfileFrame.py deleted file mode 100644 index 22b458384a..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/LogfileFrame.py +++ /dev/null @@ -1,57 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/LogfileFrame.py -# @brief Implements module/class/test LogfileFrame -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import os - -import wx - -from MDANSE import PLATFORM - - -class LogfileFrame(wx.Frame): - def __init__(self, parent, jobName, *args, **kwargs): - wx.Frame.__init__(self, parent, size=(800, 500), *args, **kwargs) - - self._logfile = os.path.join(PLATFORM.logfiles_directory(), jobName) + ".txt" - - panel = wx.Panel(self, wx.ID_ANY) - - sizer = wx.BoxSizer(wx.VERTICAL) - - self._logFileContents = wx.TextCtrl( - panel, wx.ID_ANY, style=wx.TE_AUTO_SCROLL | wx.TE_READONLY | wx.TE_MULTILINE - ) - - updateButton = wx.Button(panel, wx.ID_ANY, label="Update") - - sizer.Add(self._logFileContents, 1, wx.ALL | wx.EXPAND, 5) - sizer.Add(updateButton, 0, wx.ALL | wx.EXPAND, 5) - - panel.SetSizer(sizer) - - self.update() - - self.Bind(wx.EVT_BUTTON, self.on_update, updateButton) - - def update(self): - try: - f = open(self._logfile, "r") - except IOError: - self._logFileContents.SetValue("Error opening %r file." % self._logfile) - else: - self._logFileContents.SetValue(f.read()) - - def on_update(self, event): - self.update() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/MainFrame.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/MainFrame.py deleted file mode 100644 index e5c83a7c7c..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/MainFrame.py +++ /dev/null @@ -1,546 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/MainFrame.py -# @brief Implements module/class/test MainFrame -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import collections -import os -import sys -import webbrowser - -import wx -import wx.aui as aui -import wx.html as wxhtml - -from MDANSE import LOGGER, PLATFORM, REGISTRY -from MDANSE.__pkginfo__ import __author__, __commit__, __version__, __beta__ -from MDANSE.Core.Platform import PLATFORM -from MDANSE.Framework.Jobs.Converter import Converter -from MDANSE.GUI.ControllerPanel import ControllerPanel -from MDANSE.GUI.DataController import DATA_CONTROLLER -from MDANSE.GUI.DataTreePanel import DataTreePanel -from MDANSE.GUI.Icons import ICONS -from MDANSE.GUI.Plugins.IPlugin import IPlugin, uninit_aui_managers -from MDANSE.GUI.PluginsTreePanel import PluginsTreePanel -from MDANSE.GUI.WorkingPanel import WorkingPanel - - -def excepthook(error, message, tback): - """ - Called when an exception is raised and uncaught. - - Redirect the exception information to the MDANSE logger at the ERROR level. - - :param typ: the exception class. - :type typ: exception - - @param value: the exception instance. - @type value: exception - - @param tback: the traceback. - @type tback: traceback instance - """ - - import traceback - - from MDANSE.Core.Error import Error - - tback = traceback.extract_tb(tback) - - trace = [] - - if not issubclass(error, Error): - for tb in tback: - trace.append(" -- ".join([str(t) for t in tb])) - - trace.append("\n%s: %s" % (error.__name__, message)) - - trace = "\n".join(trace) - - LOGGER(trace, "error", ["console", "dialog"]) - - -class MainFrame(wx.Frame): - def __init__( - self, - parent, - title="MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments", - ): - wx.Frame.__init__(self, parent, wx.ID_ANY, title, size=(1200, 800)) - - self.build_dialog() - - # Add some handlers to the loggers - consoleHandler = REGISTRY["handler"]["console"]( - self._panels["controller"].pages["logger"] - ) - LOGGER.add_handler("console", consoleHandler, level="info") - LOGGER.add_handler("dialog", REGISTRY["handler"]["dialog"](), level="error") - LOGGER.start() - - # Redirect all output to the console logger - # sys.stdout = consoleHandler - # sys.stderr = consoleHandler - - # sys.excepthook = excepthook - - def build_dialog(self): - self.build_menu() - - self.build_toolbar() - - icon = wx.Icon() - icon.CopyFromBitmap(ICONS["mdanse", 32, 32]) - self.SetIcon(icon) - - # The main aui manager. - self._mgr = aui.AuiManager(self) - - self._panels = {} - self._panels["data"] = DataTreePanel(self) - self._panels["plugins"] = PluginsTreePanel(self) - self._panels["working"] = WorkingPanel(self) - self._panels["controller"] = ControllerPanel(self) - - # Add the panes corresponding to the tree control and the notebook. - paneInfo1 = aui.AuiPaneInfo() - paneInfo2 = aui.AuiPaneInfo() - # Order is first "Data", and then "Plugins". It is switched on Linux and macOS - if PLATFORM.name == "windows": - self._mgr.AddPane( - self._panels["data"], - paneInfo1.Caption("Data") - .Name("data") - .Left() - .CloseButton(True) - .DestroyOnClose(False) - .MinSize((250, -1)), - ) - self._mgr.AddPane( - self._panels["plugins"], - paneInfo2.Caption("Plugins") - .Name("plugins") - .Left() - .CloseButton(True) - .DestroyOnClose(False) - .MinSize((250, -1)), - ) - else: - self._mgr.AddPane( - self._panels["plugins"], - paneInfo2.Caption("Plugins") - .Name("plugins") - .Left() - .CloseButton(True) - .DestroyOnClose(False) - .MinSize((250, -1)), - ) - self._mgr.AddPane( - self._panels["data"], - paneInfo1.Caption("Data") - .Name("data") - .Left() - .CloseButton(True) - .DestroyOnClose(False) - .MinSize((250, -1)), - ) - paneInfo3 = aui.AuiPaneInfo() - self._mgr.AddPane( - self._panels["working"], - paneInfo3.Caption("Working panel") - .Name("working") - .Center() - .CloseButton(False), - ) - paneInfo4 = aui.AuiPaneInfo() - self._mgr.AddPane( - self._panels["controller"], - paneInfo4.Name("controller") - .Name("controller") - .Floatable() - .Right() - .Bottom() - .CloseButton(True) - .DestroyOnClose(False) - .MinSize((-1, 120)), - ) - - self._mgr.Update() - - def build_menu(self): - self._mainMenu = wx.MenuBar() - - fileMenu = wx.Menu() - loadDataItem = fileMenu.Append(wx.ID_ANY, "Load data") - fileMenu.AppendSeparator() - converterMenu = wx.Menu() - self._converters = {} - - converters = [ - job - for job in list(REGISTRY["job"].items()) - if issubclass(job[1], Converter) - ] - converters = sorted(converters) - for name, job in converters: - item = converterMenu.Append(wx.ID_ANY, job.label) - self._converters[job.label] = name - self.Bind(wx.EVT_MENU, self.on_open_converter, item) - - fileMenu.Append(wx.ID_ANY, "Trajectory converters", converterMenu) - fileMenu.AppendSeparator() - quitItem = fileMenu.Append(wx.ID_ANY, "Quit") - - self._mainMenu.Append(fileMenu, "File") - - viewMenu = wx.Menu() - showDataTreeItem = viewMenu.Append(wx.ID_ANY, "Toggle data tree") - showPluginsTreeItem = viewMenu.Append(wx.ID_ANY, "Toggle plugins tree") - showControllerItem = viewMenu.Append(wx.ID_ANY, "Toggle controller") - viewMenu.AppendSeparator() - showToolbarItem = viewMenu.Append(wx.ID_ANY, "Toggle toolbar") - - self._mainMenu.Append(viewMenu, "View") - - helpMenu = wx.Menu() - aboutItem = helpMenu.Append(wx.ID_ANY, "About") - helpMenu.AppendSeparator() - simpleHelpItem = helpMenu.Append(wx.ID_ANY, "Simple help") - theoryHelpItem = helpMenu.Append(wx.ID_ANY, "Theoretical background") - user_guideHelpItem = helpMenu.Append(wx.ID_ANY, "User guide") - helpMenu.AppendSeparator() - bugReportItem = helpMenu.Append(wx.ID_ANY, "Bug report") - self._mainMenu.Append(helpMenu, "Help") - - self.SetMenuBar(self._mainMenu) - - self.Bind(wx.EVT_CLOSE, self.on_quit) - - self.Bind(wx.EVT_MENU, self.on_load_data, loadDataItem) - self.Bind(wx.EVT_MENU, self.on_quit, quitItem) - self.Bind(wx.EVT_MENU, self.on_about, aboutItem) - self.Bind(wx.EVT_MENU, self.on_toggle_data_tree, showDataTreeItem) - self.Bind(wx.EVT_MENU, self.on_toggle_plugins_tree, showPluginsTreeItem) - self.Bind(wx.EVT_MENU, self.on_toggle_controller, showControllerItem) - self.Bind(wx.EVT_MENU, self.on_toggle_toolbar, showToolbarItem) - self.Bind(wx.EVT_MENU, self.on_bug_report, bugReportItem) - self.Bind(wx.EVT_MENU, self.on_simple_help, simpleHelpItem) - self.Bind(wx.EVT_MENU, self.on_theory_help, theoryHelpItem) - self.Bind(wx.EVT_MENU, self.on_user_guide, user_guideHelpItem) - - def build_toolbar(self): - self._toolbar = self.CreateToolBar() - - loadDataButton = self._toolbar.AddTool( - wx.ID_ANY, "Load a trajectory", ICONS["load", 32, 32] - ) - periodicTableButton = self._toolbar.AddTool( - wx.ID_ANY, - "Launch the periodic table viewer", - ICONS["periodic_table", 32, 32], - ) - elementsDatabaseButton = self._toolbar.AddTool( - wx.ID_ANY, "Launch the elements database editor", ICONS["atom", 32, 32] - ) - plotButton = self._toolbar.AddTool( - wx.ID_ANY, "Launch the NetCDF plotter", ICONS["plot", 32, 32] - ) - udButton = self._toolbar.AddTool( - wx.ID_ANY, "Launch the user definitions editor", ICONS["user", 32, 32] - ) - unitsButton = self._toolbar.AddTool( - wx.ID_ANY, "Launch the units editor", ICONS["units", 32, 32] - ) - registryButton = self._toolbar.AddTool( - wx.ID_ANY, "Inspect MDANSE classes framework", ICONS["registry", 32, 32] - ) - templateButton = self._toolbar.AddTool( - wx.ID_ANY, "Save a template for a new analysis", ICONS["template", 32, 32] - ) - apiButton = self._toolbar.AddTool( - wx.ID_ANY, "Open MDANSE API", ICONS["api", 32, 32] - ) - websiteButton = self._toolbar.AddTool( - wx.ID_ANY, "Open MDANSE website", ICONS["web", 32, 32] - ) - aboutButton = self._toolbar.AddTool( - wx.ID_ANY, "About MDANSE", ICONS["about", 32, 32] - ) - bugButton = self._toolbar.AddTool(wx.ID_ANY, "Bug report", ICONS["bug", 32, 32]) - quitButton = self._toolbar.AddTool( - wx.ID_ANY, "Quit MDANSE", ICONS["quit", 32, 32] - ) - - self._toolbar.Realize() - - self.SetToolBar(self._toolbar) - - # The toolbar-related events handlers. - self.Bind(wx.EVT_MENU, self.on_load_data, loadDataButton) - self.Bind(wx.EVT_MENU, self.on_open_periodic_table, periodicTableButton) - self.Bind(wx.EVT_MENU, self.on_open_elements_database, elementsDatabaseButton) - self.Bind(wx.EVT_MENU, self.on_start_plotter, plotButton) - self.Bind(wx.EVT_MENU, self.on_open_user_definitions, udButton) - self.Bind(wx.EVT_MENU, self.on_open_units, unitsButton) - self.Bind(wx.EVT_MENU, self.on_open_classes_registry, registryButton) - self.Bind(wx.EVT_MENU, self.on_save_job_template, templateButton) - self.Bind(wx.EVT_MENU, self.on_about, aboutButton) - self.Bind(wx.EVT_MENU, self.on_quit, quitButton) - self.Bind(wx.EVT_MENU, self.on_open_api, apiButton) - self.Bind(wx.EVT_MENU, self.on_open_mdanse_url, websiteButton) - self.Bind(wx.EVT_MENU, self.on_bug_report, bugButton) - - def load_data(self, typ, filename): - ext = os.path.splitext(filename)[1] - if typ == "automatic": - # if type is set on automatic, find data type - if ext == ".mvi": - data = REGISTRY["input_data"]["molecular_viewer"](filename) - elif ext == ".h5": - data = REGISTRY["input_data"]["hdf_trajectory"](filename) - elif ext == ".nc": - data = REGISTRY["input_data"]["netcdf_data"](filename) - else: - data = REGISTRY["input_data"][typ](filename) - - DATA_CONTROLLER[data.filename] = data - - def on_about(self, event=None): - if __beta__: - beta_string = " (%s)" % __beta__ - else: - beta_string = "" - about_str = """MDANSE version %s (commit %s). - -An interactive program for analyzing Molecular Dynamics simulations. - -Authors: -""" % ( - __version__ + beta_string, - __commit__, - ) - - for author in __author__.split(","): - about_str += "\t- %s\n" % author.strip() - - d = wx.MessageDialog( - self, about_str, "About", style=wx.OK | wx.ICON_INFORMATION - ) - d.ShowModal() - d.Destroy() - - def on_bug_report(self, event=None): - webbrowser.open("mailto:mdanse@ill.fr?subject=MDANSE query") - - def on_simple_help(self, event): - path = os.path.join(PLATFORM.doc_path(), "simple_help.html") - - with open(path, "r") as f: - info = f.read() - frame = wx.Frame( - self, - style=wx.DEFAULT_DIALOG_STYLE - | wx.MINIMIZE_BOX - | wx.MAXIMIZE_BOX - | wx.RESIZE_BORDER, - ) - frame.SetMinSize((800, 600)) - panel = wx.Panel(frame, wx.ID_ANY) - sizer = wx.BoxSizer(wx.VERTICAL) - html = wxhtml.HtmlWindow( - panel, - -1, - size=(300, 150), - style=wx.VSCROLL | wx.HSCROLL | wx.TE_READONLY | wx.BORDER_SIMPLE, - ) - html.SetPage(info) - sizer.Add(html, 1, wx.ALL | wx.EXPAND, 5) - panel.SetSizer(sizer) - frame.Show() - - @staticmethod - def on_theory_help(event): - webbrowser.open( - "file://%s" % os.path.join(PLATFORM.doc_path(), "theory_help.pdf") - ) - - @staticmethod - def on_user_guide(event): - webbrowser.open("https://doi.org/10.5286/raltr.2022003") - - def on_open_classes_registry(self, event): - from MDANSE.GUI.RegistryViewer import RegistryViewer - - f = RegistryViewer(self) - - f.ShowModal() - - f.Destroy() - - def on_save_job_template(self, event): - from MDANSE.GUI.JobTemplateEditor import JobTemplateEditor - - f = JobTemplateEditor(self) - - f.ShowModal() - - f.Destroy() - - def on_open_api(self, event): - mainHTML = os.path.join(PLATFORM.api_path(), "MDANSE.html") - - if os.path.exists(mainHTML): - webbrowser.open("file://%s" % mainHTML) - else: - LOGGER( - "Can not open MDANSE API. Maybe the documentation was not properly installed.", - "error", - ["dialog"], - ) - - def on_load_data(self, event=None): - wildcards = collections.OrderedDict( - [kls._type, "%s (*.%s)|*.%s" % (kls._type, kls.extension, kls.extension)] - for kls in list(REGISTRY["input_data"].values()) - if kls.extension is not None - ) - - dialog = wx.FileDialog( - None, - message="Open data ...", - wildcard="automatic (*.mvi,*.nc,*.h5)|*.mvi;*.nc;*.h5|" - + "|".join(wildcards.values()), - style=wx.FD_OPEN, - ) - - if dialog.ShowModal() == wx.ID_CANCEL: - return "" - - idx = dialog.GetFilterIndex() - # Check if automatic has been chosen - if idx <= 0: - dataType = "automatic" - else: - dataType = list(wildcards.keys())[idx - 1] - - filename = dialog.GetPath() - - if not filename: - return - - self.load_data(dataType, filename) - - LOGGER("Data %r successfully loaded." % filename, "info", ["console"]) - - def on_open_user_definitions(self, event): - from MDANSE.GUI.UserDefinitionViewer import UserDefinitionViewer - - f = UserDefinitionViewer(self) - f.ShowModal() - f.Destroy() - - def on_open_units(self, event): - from MDANSE.GUI.UnitsEditor import UnitsEditor - - f = UnitsEditor(self) - f.ShowModal() - f.Destroy() - - def on_open_converter(self, event): - from MDANSE.GUI.Plugins.JobPlugin import JobFrame - - item = self.GetMenuBar().FindItemById(event.GetId()) - converter = item.GetText() - - f = JobFrame(self, self._converters[converter], None) - f.Show() - - def on_open_periodic_table(self, event): - from MDANSE.GUI.PeriodicTableViewer import PeriodicTableViewer - - f = PeriodicTableViewer(self) - - f.Show() - - def on_open_elements_database(self, event): - from MDANSE.GUI.ElementsDatabaseEditor import ElementsDatabaseEditor - - f = ElementsDatabaseEditor(self) - - f.Show() - - def on_open_mdanse_url(self, event): - webbrowser.open("https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx") - - def _uninit_aui_managers(self): - nPages = self._panels["working"].notebook.GetPageCount() - for i in range(nPages): - page = self._panels["working"].notebook.GetPage(i) - uninit_aui_managers(page._mgr) - - def on_quit(self, event=None): - 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._uninit_aui_managers() - self._mgr.UnInit() - self.Destroy() - - def on_start_plotter(self, event=None): - from MDANSE.GUI.Plugins.PlotterPlugin import PlotterFrame - - f = PlotterFrame(self) - - f.Show() - - def on_toggle_controller(self, event=None): - pane = self._mgr.GetPane("controller") - - self.toggle_window(pane) - - def on_toggle_data_tree(self, event=None): - pane = self._mgr.GetPane("data") - - self.toggle_window(pane) - - def on_toggle_plugins_tree(self, event=None): - pane = self._mgr.GetPane("plugins") - - self.toggle_window(pane) - - def on_toggle_toolbar(self, event=None): - self.toggle_window(self._toolbar) - self.Layout() - - @property - def panels(self): - return self._panels - - def toggle_window(self, window): - if window.IsShown(): - window.Hide() - else: - window.Show() - - self._mgr.Update() - - -if __name__ == "__main__": - from MDANSE.GUI.Apps import MainApplication - - app = MainApplication(None) - app.MainLoop() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/PeriodicTableViewer.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/PeriodicTableViewer.py deleted file mode 100644 index 6ed97d6669..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/PeriodicTableViewer.py +++ /dev/null @@ -1,684 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/PeriodicTableViewer.py -# @brief Implements module/class/test PeriodicTableViewer -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx -import wx.lib.fancytext as wxfancytext - -from MDANSE.Chemistry import ATOMS_DATABASE -from MDANSE.GUI.ElementsDatabaseEditor import ElementsDatabaseEditor - -_LAYOUT = {} -_LAYOUT["H"] = (0, 1) -_LAYOUT["He"] = (0, 18) - -_LAYOUT["Li"] = (1, 1) -_LAYOUT["Be"] = (1, 2) -_LAYOUT["B"] = (1, 13) -_LAYOUT["C"] = (1, 14) -_LAYOUT["N"] = (1, 15) -_LAYOUT["O"] = (1, 16) -_LAYOUT["F"] = (1, 17) -_LAYOUT["Ne"] = (1, 18) - -_LAYOUT["Na"] = (2, 1) -_LAYOUT["Mg"] = (2, 2) -_LAYOUT["Al"] = (2, 13) -_LAYOUT["Si"] = (2, 14) -_LAYOUT["P"] = (2, 15) -_LAYOUT["S"] = (2, 16) -_LAYOUT["Cl"] = (2, 17) -_LAYOUT["Ar"] = (2, 18) - -_LAYOUT["K"] = (3, 1) -_LAYOUT["Ca"] = (3, 2) -_LAYOUT["Sc"] = (3, 3) -_LAYOUT["Ti"] = (3, 4) -_LAYOUT["V"] = (3, 5) -_LAYOUT["Cr"] = (3, 6) -_LAYOUT["Mn"] = (3, 7) -_LAYOUT["Fe"] = (3, 8) -_LAYOUT["Co"] = (3, 9) -_LAYOUT["Ni"] = (3, 10) -_LAYOUT["Cu"] = (3, 11) -_LAYOUT["Zn"] = (3, 12) -_LAYOUT["Ga"] = (3, 13) -_LAYOUT["Ge"] = (3, 14) -_LAYOUT["As"] = (3, 15) -_LAYOUT["Se"] = (3, 16) -_LAYOUT["Br"] = (3, 17) -_LAYOUT["Kr"] = (3, 18) - -_LAYOUT["Rb"] = (4, 1) -_LAYOUT["Sr"] = (4, 2) -_LAYOUT["Y"] = (4, 3) -_LAYOUT["Zr"] = (4, 4) -_LAYOUT["Nb"] = (4, 5) -_LAYOUT["Mo"] = (4, 6) -_LAYOUT["Tc"] = (4, 7) -_LAYOUT["Ru"] = (4, 8) -_LAYOUT["Rh"] = (4, 9) -_LAYOUT["Pd"] = (4, 10) -_LAYOUT["Ag"] = (4, 11) -_LAYOUT["Cd"] = (4, 12) -_LAYOUT["In"] = (4, 13) -_LAYOUT["Sn"] = (4, 14) -_LAYOUT["Sb"] = (4, 15) -_LAYOUT["Te"] = (4, 16) -_LAYOUT["I"] = (4, 17) -_LAYOUT["Xe"] = (4, 18) - -_LAYOUT["Cs"] = (5, 1) -_LAYOUT["Ba"] = (5, 2) -_LAYOUT["Hf"] = (5, 4) -_LAYOUT["Ta"] = (5, 5) -_LAYOUT["W"] = (5, 6) -_LAYOUT["Re"] = (5, 7) -_LAYOUT["Os"] = (5, 8) -_LAYOUT["Ir"] = (5, 9) -_LAYOUT["Pt"] = (5, 10) -_LAYOUT["Au"] = (5, 11) -_LAYOUT["Hg"] = (5, 12) -_LAYOUT["Tl"] = (5, 13) -_LAYOUT["Pb"] = (5, 14) -_LAYOUT["Bi"] = (5, 15) -_LAYOUT["Po"] = (5, 16) -_LAYOUT["At"] = (5, 17) -_LAYOUT["Rn"] = (5, 18) - -_LAYOUT["Fr"] = (6, 1) -_LAYOUT["Ra"] = (6, 2) -_LAYOUT["Rf"] = (6, 4) -_LAYOUT["Db"] = (6, 5) -_LAYOUT["Sg"] = (6, 6) -_LAYOUT["Bh"] = (6, 7) -_LAYOUT["Hs"] = (6, 8) -_LAYOUT["Mt"] = (6, 9) -_LAYOUT["Ds"] = (6, 10) -_LAYOUT["Rg"] = (6, 11) -_LAYOUT["Cn"] = (6, 12) -_LAYOUT["Uut"] = (6, 13) -_LAYOUT["Fl"] = (6, 14) -_LAYOUT["Uup"] = (6, 15) -_LAYOUT["Lv"] = (6, 16) -_LAYOUT["Uus"] = (6, 17) -_LAYOUT["Uuo"] = (6, 18) - -_LAYOUT["La"] = (8, 4) -_LAYOUT["Ce"] = (8, 5) -_LAYOUT["Pr"] = (8, 6) -_LAYOUT["Nd"] = (8, 7) -_LAYOUT["Pm"] = (8, 8) -_LAYOUT["Sm"] = (8, 9) -_LAYOUT["Eu"] = (8, 10) -_LAYOUT["Gd"] = (8, 11) -_LAYOUT["Tb"] = (8, 12) -_LAYOUT["Dy"] = (8, 13) -_LAYOUT["Ho"] = (8, 14) -_LAYOUT["Er"] = (8, 15) -_LAYOUT["Tm"] = (8, 16) -_LAYOUT["Yb"] = (8, 17) -_LAYOUT["Lu"] = (8, 18) - -_LAYOUT["Ac"] = (9, 4) -_LAYOUT["Th"] = (9, 5) -_LAYOUT["Pa"] = (9, 6) -_LAYOUT["U"] = (9, 7) -_LAYOUT["Np"] = (9, 8) -_LAYOUT["Pu"] = (9, 9) -_LAYOUT["Am"] = (9, 10) -_LAYOUT["Cm"] = (9, 11) -_LAYOUT["Bk"] = (9, 12) -_LAYOUT["Cf"] = (9, 13) -_LAYOUT["Es"] = (9, 14) -_LAYOUT["Fm"] = (9, 15) -_LAYOUT["Md"] = (9, 16) -_LAYOUT["No"] = (9, 17) -_LAYOUT["Lr"] = (9, 18) - -_COLS = list(range(1, 19)) -_ROWS = ["i", "ii", "iii", "iv", "v", "vi", "vii"] - -# Dictionary that maps the chemical family with a RGB color. -_FAMILY = { - "default": (128, 128, 128), - "user-defined": (255, 255, 255), - "non metal": (153, 255, 153), - "noble gas": (192, 255, 255), - "alkali metal": (255, 153, 153), - "alkaline earth metal": (255, 222, 173), - "metalloid": (204, 204, 153), - "halogen": (255, 255, 153), - "post-transition metal": (204, 204, 204), - "transition metal": (255, 192, 192), - "lanthanoid": (255, 191, 255), - "actinoid": (255, 153, 294), -} - -# Dictionary that maps the chemical state with a RGB color. -_STATE = { - "default": (128, 128, 128), - "user-defined": (255, 0, 0), - "gas": (255, 0, 0), - "liquid": (0, 0, 255), - "solid": (0, 0, 0), - "unknown": (0, 150, 0), -} - - -class StaticFancyText(wxfancytext.StaticFancyText): - """ - StaticFancyText with SetLabel function. - """ - - def SetLabel(self, label): - """ - Overload of the StaticFancyText.SetLabel method - """ - - bmp = wxfancytext.RenderToBitmap( - label, wx.Brush(self.GetParent().GetBackgroundColour(), wx.SOLID) - ) - - self.SetBitmap(bmp) - - -class ElementInfoFrame(wx.Frame): - """ - This class creates a panel that contains all the information stored in the database about a given element. - """ - - def __init__(self, parent, element, *args, **kwds): - """ - The constructor. - - :Parameters: - #. parent (wx window): the parent window. - #. element (string): the element name. - """ - - # The base class constructor. - wx.Frame.__init__( - self, - parent, - wx.ID_ANY, - title="Information about %s element" % element, - style=wx.DEFAULT_FRAME_STYLE - & ~(wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER), - ) - - # The main panel - mainPanel = wx.Panel(self, wx.ID_ANY) - - # The main panel sizer. - mainSizer = wx.BoxSizer(wx.VERTICAL) - - # A text widget is created to display the information about the selected element. - text = wx.StaticText(mainPanel, wx.ID_ANY, label=ATOMS_DATABASE.info(element)) - - # The background color of the text widget is set. - mainPanel.SetBackgroundColour(wx.Colour(255, 236, 139)) - info = ATOMS_DATABASE[element] - bgColor = _FAMILY[info["family"]] - mainPanel.SetBackgroundColour(bgColor) - - # The font of the text widget is set. - text.SetFont( - wx.Font(10, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL) - ) - - # The text widget is added to the main panel sizer. - mainSizer.Add(text, 1, wx.ALL | wx.EXPAND, 5) - - # An hyperlink widget is created for opening the url about the selected element. - hyperlink = wx.HyperlinkCtrl( - mainPanel, - wx.ID_ANY, - label="More about %s" % ATOMS_DATABASE[element]["element"], - url=ATOMS_DATABASE[element]["url"], - ) - - # The hyperlink widget is added to the main panel sizer. - mainSizer.Add(hyperlink, 0, wx.ALL | wx.EXPAND, 5) - - # The main panel sizer is set and fitted with its contents. - mainPanel.SetSizer(mainSizer) - - # The frame is fitted with its contents. - mainSizer.Fit(self) - - mainPanel.Layout() - - -class ElementShortInfoPanel(wx.Panel): - """ - This class creates a panel that displays a summary of the information stored in the database for a given element. - """ - - def __init__(self, parent, element="H"): - """ - The constructor. - - :Parameters: - #. parent (wx window): the parent window. - #. element (string): the element name. - """ - - # The base class constructor. - wx.Panel.__init__(self, parent=parent, style=wx.BORDER_SUNKEN) - - # This will store the name of the element for which the summary is currently displayed. - self.selected = None - - # The top sizer that will arrange the summary widget as a grid. - self.sizer = wx.GridBagSizer(0, 0) - self.sizer.SetEmptyCellSize((20, 20)) - - # The static texts that will display the informations about a given element. - self.family = wx.StaticText( - self, label="", style=wx.ALIGN_RIGHT | wx.ST_NO_AUTORESIZE | wx.EXPAND - ) - self.family.SetToolTip("Chemical family") - self.family.SetFont( - wx.Font(8, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_ITALIC, wx.FONTWEIGHT_BOLD) - ) - - # The element symbol. - self.symbol = wx.StaticText( - self, label="", style=wx.ALIGN_LEFT | wx.ST_NO_AUTORESIZE - ) - self.symbol.SetToolTip("Symbol") - self.symbol.SetFont( - wx.Font(18, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD) - ) - - # The element atomic number. - self.z = wx.StaticText( - self, label="", style=wx.ALIGN_RIGHT | wx.ST_NO_AUTORESIZE | wx.EXPAND - ) - self.z.SetToolTip("Atomic number") - self.z.SetFont( - wx.Font(8, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD) - ) - - # The element position in the periodic table. - self.position = wx.StaticText( - self, - label="", - size=(40, 15), - style=wx.ALIGN_CENTER_VERTICAL | wx.ST_NO_AUTORESIZE, - ) - self.position.SetToolTip("Group,Period,Block") - self.position.SetFont( - wx.Font(8, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD) - ) - - # The element full name. - self.atom = wx.StaticText( - self, label="", style=wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE - ) - self.atom.SetToolTip("Atom") - self.atom.SetFont( - wx.Font(8, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD) - ) - - # The element electronic configuration. - self.configuration = StaticFancyText( - self, wx.ID_ANY, "", style=wx.EXPAND | wx.ALIGN_LEFT | wx.ST_NO_AUTORESIZE - ) - self.configuration.SetToolTip("Electron configuration") - - # The element atomic weight. - self.atomicWeight = wx.StaticText( - self, label="", style=wx.ALIGN_RIGHT | wx.ST_NO_AUTORESIZE - ) - self.atomicWeight.SetToolTip("Relative atomic mass (uma)") - - # The element electronegativity. - self.electroNegativity = wx.StaticText( - self, label="", style=wx.EXPAND | wx.ALIGN_RIGHT | wx.ST_NO_AUTORESIZE - ) - self.electroNegativity.SetToolTip("Electronegativity") - - # The element electroaffinity. - self.electroAffinity = wx.StaticText( - self, label="", style=wx.ALIGN_RIGHT | wx.ST_NO_AUTORESIZE - ) - self.electroAffinity.SetToolTip("Electroaffinity (eV)") - - # The element ionization energy. - self.ionizationEnergy = wx.StaticText( - self, label="", style=wx.ALIGN_RIGHT | wx.ST_NO_AUTORESIZE - ) - self.ionizationEnergy.SetToolTip("Ionization energy (eV)") - - # The widgets are placed into the gridbag top sizer. - self.sizer.Add(self.family, pos=(0, 1), span=(1, 16), flag=wx.EXPAND) - self.sizer.Add(self.z, pos=(1, 0), span=(1, 3), flag=wx.EXPAND) - self.sizer.Add(self.position, pos=(6, 0), span=(1, 6), flag=wx.EXPAND) - self.sizer.Add(self.symbol, pos=(2, 2), span=(2, 7), flag=wx.EXPAND) - self.sizer.Add(self.configuration, pos=(2, 10), span=(2, 8), flag=wx.EXPAND) - self.sizer.Add(self.atom, pos=(4, 0), span=(1, 7), flag=wx.EXPAND) - self.sizer.Add(self.atomicWeight, pos=(4, 14), span=(1, 3), flag=wx.EXPAND) - self.sizer.Add(self.electroNegativity, pos=(5, 14), span=(1, 3), flag=wx.EXPAND) - self.sizer.Add(self.electroAffinity, pos=(6, 14), span=(1, 3), flag=wx.EXPAND) - self.sizer.Add(self.ionizationEnergy, pos=(7, 14), span=(1, 3), flag=wx.EXPAND) - - # The main panel sizer is set and fitted with its contents. - self.SetSizer(self.sizer) - - # The frame is fitted with its contents. - self.sizer.Fit(self) - - self.Layout() - - # The selected element is set. - self.set_selection(element) - - def set_selection(self, element): - """ - Select an element whose summary will be displayed.. - - :Parameters: - #. element (string): the element name. - """ - - # If the element is already the one displayed, just return. - if self.selected == element: - return - - # The new element becomes the current one. - self.selected = element - - # Prevents any updates from taking place on screen. - self.Freeze() - - # The element database instance. - info = ATOMS_DATABASE[element] - - # Its chemical family. - family = info["family"] - color = _FAMILY.get(family, _FAMILY["default"]) - - # Change the main panel background color according to the element chemical family. - self.SetBackgroundColour((color[0], color[1], color[2])) - - # Updates the different static text according to the new element properties. - self.family.SetLabel("%s " % family) - self.symbol.SetLabel(info["symbol"]) - self.z.SetLabel("%4s" % info["proton"]) - self.position.SetLabel( - "%2s,%s,%s" % (info["group"], info["period"], info["block"]) - ) - self.atom.SetLabel(info["element"]) - self.atomicWeight.SetLabel("%s" % info["atomic_weight"]) - self.electroNegativity.SetLabel("%s" % info["electronegativity"]) - self.electroAffinity.SetLabel("%s" % info["electroaffinity"]) - self.ionizationEnergy.SetLabel("%s" % info["ionization_energy"]) - - label = [] - for orb in info["configuration"].split(): - if not orb.startswith("[") and len(orb) > 2: - orb = orb[:2] + "" + orb[2:] + "" - label.append(orb) - label.append(" ") - self.configuration.SetLabel(" ".join(label)) - - # Reenables the main panel updating after the previous call to Freeze. - self.Thaw() - - -class PeriodicTableViewer(wx.Frame): - """ - This class creates a panel that will display the periodic table. Each element of the periodic table is a button - that when clicked on will list the natural element and the different isotopes found in the database for the - selected element. There is also a special button that when clicked will display the "user-defined elements". - """ - - def __init__(self, parent): - """ - The constructor. - :Parameters: - #. parent (wx window): the parent window. - """ - - wx.Frame.__init__( - self, - parent, - wx.ID_ANY, - title="Periodic table viewer", - style=wx.DEFAULT_FRAME_STYLE - & ~(wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER), - ) - - self._parent = parent - - mainPanel = wx.Panel(self, wx.ID_ANY) - - mainSizer = wx.GridBagSizer(0, 0) - mainSizer.SetEmptyCellSize((20, 20)) - - self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE)) - - for i in _COLS: - wid = wx.TextCtrl( - mainPanel, - wx.ID_ANY, - value=str(i), - size=(40, 40), - style=wx.ALIGN_CENTER_HORIZONTAL - | wx.EXPAND - | wx.TE_READONLY - | wx.NO_BORDER, - ) - wid.SetBackgroundColour((230, 230, 220)) - mainSizer.Add( - wid, - (0, i), - flag=wx.ALL | wx.ALIGN_CENTER | wx.FIXED_MINSIZE | wx.EXPAND, - border=1, - ) - - for i, v in enumerate(_ROWS): - wid = wx.TextCtrl( - mainPanel, - wx.ID_ANY, - value=str(v), - size=(40, 40), - style=wx.ALIGN_CENTER_HORIZONTAL - | wx.EXPAND - | wx.TE_READONLY - | wx.NO_BORDER, - ) - wid.SetBackgroundColour((230, 230, 220)) - mainSizer.Add( - wid, - (i + 1, 0), - flag=wx.ALL | wx.ALIGN_CENTER | wx.FIXED_MINSIZE | wx.EXPAND, - border=1, - ) - - wid = wx.TextCtrl( - mainPanel, - wx.ID_ANY, - value="*", - size=(40, 40), - style=wx.ALIGN_CENTER_HORIZONTAL - | wx.EXPAND - | wx.TE_READONLY - | wx.NO_BORDER, - ) - mainSizer.Add( - wid, - (6, 3), - flag=wx.ALL | wx.ALIGN_CENTER | wx.FIXED_MINSIZE | wx.EXPAND, - border=1, - ) - - wid = wx.TextCtrl( - mainPanel, - wx.ID_ANY, - value="**", - size=(40, 40), - style=wx.ALIGN_CENTER_HORIZONTAL - | wx.EXPAND - | wx.TE_READONLY - | wx.NO_BORDER, - ) - mainSizer.Add( - wid, - (7, 3), - flag=wx.ALL | wx.ALIGN_CENTER | wx.FIXED_MINSIZE | wx.EXPAND, - border=1, - ) - - wid = wx.TextCtrl( - mainPanel, - wx.ID_ANY, - value="*", - size=(40, 40), - style=wx.ALIGN_CENTER_HORIZONTAL - | wx.EXPAND - | wx.TE_READONLY - | wx.NO_BORDER, - ) - mainSizer.Add( - wid, - (9, 3), - flag=wx.ALL | wx.ALIGN_CENTER | wx.FIXED_MINSIZE | wx.EXPAND, - border=1, - ) - - wid = wx.TextCtrl( - mainPanel, - wx.ID_ANY, - value="**", - size=(40, 40), - style=wx.ALIGN_CENTER_HORIZONTAL - | wx.EXPAND - | wx.TE_READONLY - | wx.NO_BORDER, - ) - mainSizer.Add( - wid, - (10, 3), - flag=wx.ALL | wx.ALIGN_CENTER | wx.FIXED_MINSIZE | wx.EXPAND, - border=1, - ) - - # The panel that will contain the short info about a selected element. - self.shortInfo = ElementShortInfoPanel(mainPanel) - mainSizer.Add( - self.shortInfo, - (1, 5), - (3, 7), - flag=wx.ALL | wx.ALIGN_CENTER | wx.FIXED_MINSIZE | wx.EXPAND, - border=1, - ) - - symbs = [] - for el, info in ATOMS_DATABASE.items(): - if info["symbol"] in symbs: - continue - symbs.append(info["symbol"]) - try: - r, c = _LAYOUT[info["symbol"]] - wid = wx.TextCtrl( - mainPanel, - wx.ID_ANY, - value=info["symbol"], - size=(40, 40), - style=wx.ALIGN_CENTER_HORIZONTAL - | wx.EXPAND - | wx.TE_READONLY - | wx.NO_BORDER, - ) - wid.SetToolTip(info["element"]) - bgColor = _FAMILY[info["family"]] - wid.SetBackgroundColour(bgColor) - fgColor = _STATE[info["state"]] - wid.SetForegroundColour(fgColor) - wid.Bind(wx.EVT_LEFT_DOWN, self.on_select_element) - wid.Bind(wx.EVT_ENTER_WINDOW, self.on_display_element_short_info) - mainSizer.Add( - wid, - (r + 1, c), - flag=wx.ALL | wx.ALIGN_CENTER | wx.FIXED_MINSIZE | wx.EXPAND, - border=1, - ) - except KeyError: - continue - - edit = wx.Button(mainPanel, wx.ID_ANY, label="Edit element(s)") - mainSizer.Add(edit, (12, 0), (1, 19), flag=wx.EXPAND, border=20) - - mainPanel.SetSizer(mainSizer) - self.SetSize(mainPanel.GetBestSize()) - - self.Bind(wx.EVT_BUTTON, self.on_open_database, edit) - - def on_open_database(self, event): - f = ElementsDatabaseEditor(self) - f.Show() - - def on_select_element(self, event=None): - # The button of the periodic table that was clicked on. - button = event.GetEventObject() - - element = button.GetValue() - - siz = button.GetSize() - - pos = button.GetPosition() - - # A menu is created. - menu = wx.Menu() - - # The natural element and its different isotopes are appended to the menu. - for iso in ATOMS_DATABASE.get_isotopes(element): - item = menu.Append(wx.ID_ANY, iso) - menu.Bind(wx.EVT_MENU, self.on_display_element_info, item) - - self.PopupMenu(menu, wx.Point(pos.x, pos.y + siz.y)) - - menu.Destroy() - - def display_element_short_info(self, element): - self.shortInfo.set_selection(element) - - def on_display_element_short_info(self, event=None): - element = event.GetEventObject().GetValue() - - self.display_element_short_info(element) - - def on_display_element_info(self, event=None): - # The button of the periodic table that was clicked on. - wid = event.GetEventObject() - - if isinstance(wid, wx.Menu): - # The entry that was selected. - element = wid.FindItemById(event.GetId()).GetText() - else: - element = wid.GetValue() - - # Pops up the information dialog about the selected isotope. - elementFrame = ElementInfoFrame(self, element) - elementFrame.Show() - - -if __name__ == "__main__": - app = wx.App(False) - f = PeriodicTableViewer(None) - f.Show() - app.MainLoop() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/AnimationPlugin.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/AnimationPlugin.py deleted file mode 100644 index d54cfd197c..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/AnimationPlugin.py +++ /dev/null @@ -1,190 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/AnimationPlugin.py -# @brief Implements module/class/test AnimationPlugin -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx -import wx.aui as wxaui - -from MDANSE import REGISTRY -from MDANSE.GUI import PUBLISHER -from MDANSE.GUI.Icons import ICONS -from MDANSE.GUI.Plugins.ComponentPlugin import ComponentPlugin - - -class AnimationPlugin(ComponentPlugin): - label = "Animation" - - ancestor = ["molecular_viewer"] - - def __init__(self, parent, *args, **kwargs): - ComponentPlugin.__init__(self, parent, size=(-1, 50), *args, **kwargs) - - def build_panel(self): - panel = wx.Panel(self, wx.ID_ANY, size=self.GetSize()) - - controlSizer = wx.BoxSizer(wx.HORIZONTAL) - - firstButton = wx.BitmapButton(panel, wx.ID_ANY, ICONS["first", 32, 32]) - self.startStop = wx.BitmapButton(panel, wx.ID_ANY, ICONS["play", 32, 32]) - lastButton = wx.BitmapButton(panel, wx.ID_ANY, ICONS["last", 32, 32]) - self.frameSlider = wx.Slider( - panel, id=wx.ID_ANY, value=0, minValue=0, maxValue=1, style=wx.SL_HORIZONTAL - ) - self.frameSlider.SetRange(0, self._parent.n_frames - 1) - self.frameEntry = wx.TextCtrl( - panel, - id=wx.ID_ANY, - value="0", - size=(60, 20), - style=wx.SL_HORIZONTAL | wx.TE_PROCESS_ENTER, - ) - speedBitmap = wx.StaticBitmap(panel, -1, ICONS["clock", 42, 42]) - self.speedSlider = wx.Slider( - panel, id=wx.ID_ANY, value=0, minValue=0, maxValue=1, style=wx.SL_HORIZONTAL - ) - self.speedSlider.SetRange(0, self._parent.max_laps) - speed = self._parent.max_laps - self._parent.timer_interval - self.speedSlider.SetValue(speed) - self.speedEntry = wx.TextCtrl( - panel, - id=wx.ID_ANY, - value=str(speed), - size=(60, 20), - style=wx.SL_HORIZONTAL | wx.TE_PROCESS_ENTER, - ) - - controlSizer.Add(firstButton, 0, wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 5) - controlSizer.Add(self.startStop, 0, wx.ALIGN_CENTER_VERTICAL) - controlSizer.Add(lastButton, 0, wx.ALIGN_CENTER_VERTICAL) - controlSizer.Add((5, -1), 0, wx.ALIGN_RIGHT) - - controlSizer.Add(self.frameSlider, 3, wx.ALIGN_CENTER_VERTICAL) - controlSizer.Add(self.frameEntry, 0, wx.ALIGN_CENTER_VERTICAL) - controlSizer.Add((5, -1), 0, wx.ALIGN_RIGHT) - - controlSizer.Add(speedBitmap, 0, wx.ALIGN_CENTER_VERTICAL) - controlSizer.Add((5, -1), 0, wx.ALIGN_RIGHT) - - controlSizer.Add(self.speedSlider, 1, wx.ALL | wx.ALIGN_CENTER_VERTICAL) - controlSizer.Add(self.speedEntry, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - - panel.SetSizer(controlSizer) - controlSizer.Fit(panel) - panel.Layout() - - self._mgr.AddPane( - panel, - wxaui.AuiPaneInfo() - .Center() - .Dock() - .CaptionVisible(False) - .CloseButton(False) - .MinSize(self.GetSize()), - ) - - self._mgr.Update() - - self.Bind(wx.EVT_SCROLL, self.on_frame_sliding, self.frameSlider) - self.Bind(wx.EVT_TEXT_ENTER, self.on_set_frame, self.frameEntry) - - self.Bind(wx.EVT_SLIDER, self.on_change_frame_rate, self.speedSlider) - self.Bind(wx.EVT_TEXT_ENTER, self.on_set_speed, self.speedEntry) - - self.Bind(wx.EVT_BUTTON, self.on_start_stop_animation, self.startStop) - self.Bind(wx.EVT_BUTTON, self.on_goto_first_frame, firstButton) - self.Bind(wx.EVT_BUTTON, self.on_goto_last_frame, lastButton) - - PUBLISHER.subscribe(self.msg_update_animation_icon, "msg_animate_trajectory") - PUBLISHER.subscribe(self.msg_set_trajectory, "msg_set_trajectory") - PUBLISHER.subscribe(self.msg_timer, "msg_timer") - - def plug(self): - self._parent._mgr.GetPane(self).LeftDockable(False).RightDockable( - False - ).Dock().Bottom().CloseButton(True) - - self._parent._mgr.Update() - - def on_change_frame_rate(self, event=None): - laps = self.speedSlider.GetValue() - - self._parent.change_frame_rate(laps) - - self.speedEntry.SetValue(str(self.speedSlider.GetValue())) - - def on_frame_sliding(self, event=None): - frame = self.frameSlider.GetValue() - - self._parent.set_frame(frame) - - frame = self._parent.current_frame - - self.frameEntry.SetValue(str(frame)) - self.frameSlider.SetValue(frame) - - def on_goto_first_frame(self, event=None): - self._parent.goto_first_frame() - - self.frameEntry.SetValue(str(0)) - self.frameSlider.SetValue(0) - - def on_goto_last_frame(self, event=None): - self._parent.goto_last_frame() - - self.frameEntry.SetValue(str(self._parent.n_frames - 1)) - self.frameSlider.SetValue(self._parent.n_frames - 1) - - def on_set_speed(self, event=None): - self.speedSlider.SetValue(int(self.speedEntry.GetValue())) - self._parent.change_frame_rate() - - def msg_timer(self, message): - plugin = message - if not plugin.is_parent(self): - return - - frame = plugin.current_frame - - self.frameEntry.SetValue(str(frame)) - self.frameSlider.SetValue(int(frame)) - - def on_set_frame(self, event=None): - frame = int(self.frameEntry.GetValue()) - - self._parent.set_configuration(frame) - - self.frameSlider.SetValue(frame) - - def on_start_stop_animation(self, event=None): - self._parent.start_stop_animation() - - def msg_update_animation_icon(self, message): - plugin = message - if not plugin.is_parent(self): - return - - if plugin.animation_loop: - self.startStop.SetBitmapLabel(ICONS["pause", 32, 32]) - else: - self.startStop.SetBitmapLabel(ICONS["play", 32, 32]) - - def msg_set_trajectory(self, message): - plugin = message - if not plugin.is_parent(self): - return - - self.frameSlider.SetRange(0, self._parent.n_frames - 1) - - -REGISTRY["animation"] = AnimationPlugin diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/AtomSelectionPlugin.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/AtomSelectionPlugin.py deleted file mode 100644 index 533385d12e..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/AtomSelectionPlugin.py +++ /dev/null @@ -1,417 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/AtomSelectionPlugin.py -# @brief Implements module/class/test AtomSelectionPlugin -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import collections -import os - -import wx -import wx.aui as wxaui - -from MDANSE import LOGGER, REGISTRY -from MDANSE.Framework.AtomSelectionParser import ( - AtomSelectionParser, - AtomSelectionParserError, -) -from MDANSE.MolecularDynamics.Trajectory import sorted_atoms - -from MDANSE.GUI import PUBLISHER -from MDANSE.GUI.Plugins.DataPlugin import get_data_plugin -from MDANSE.GUI.Plugins.UserDefinitionPlugin import UserDefinitionPlugin - - -class Query(object): - def __init__(self): - self._list = [] - - self._parser = None - - def get_expression(self): - s = [] - - for v in self._list: - if isinstance(v, list): - keyword, arguments = v - arguments = ",".join([str(val) for val in arguments]) - s.append("%s %s" % (keyword, arguments)) - else: - s.append(v) - - return "".join(s) - - @property - def list(self): - return self._list - - @property - def parser(self): - return self._parser - - def add_operator(self, operator): - if operator == "(": - if self._list: - if self._list[-1] == ")" or isinstance(self._list[-1], list): - return - self._list.append("(") - - elif operator == ")": - if self._list: - if self._list[-1] == ")" or isinstance(self._list[-1], list): - if self._list.count(")") < self._list.count("("): - self._list.append(")") - - elif operator == "not": - if self._list: - if self._list[-1] == ")": - return - self._list.append(" not ") - - elif operator in ["and", "or"]: - if self._list: - if self._list[-1] == ")" or isinstance(self._list[-1], list): - self._list.append(" %s " % operator) - - def add_query(self, query): - if not self._list: - if query is not None: - self._list.append(query) - else: - keyword, values = query - - if isinstance(self._list[-1], list): - if self._list[-1][0] == keyword: - if values: - self._list[-1] = query - else: - del self._list[-1] - else: - self._list.extend([" or ", query]) - - elif isinstance(self._list[-1], str): - if self._list[-1] in [" and ", " or ", "(", " not "]: - self._list.append(query) - - def clear(self): - self._list = [] - - def is_empty(self): - return len(self._list) == 0 - - def parse(self): - if self._parser is None: - return [] - - try: - expression = self.get_expression() - selection = self._parser.parse(expression) - except AtomSelectionParserError: - return ("", []) - else: - return (expression, selection) - - def pop(self): - return self._list.pop() - - def set_parser(self, parser): - self._parser = parser - - -class AtomSelectionPlugin(UserDefinitionPlugin): - label = "Atom selection" - - ancestor = ["molecular_viewer"] - - def __init__(self, parent, *args, **kwargs): - self._query = Query() - - self._selectors = {} - - self._selection = [] - - PUBLISHER.subscribe( - self.msg_select_atoms_from_viewer, "msg_select_atoms_from_viewer" - ) - - UserDefinitionPlugin.__init__(self, parent, size=(600, 600)) - - def build_panel(self): - self._mainPanel = wx.ScrolledWindow(self, wx.ID_ANY) - self._mainPanel.SetScrollbars(20, 20, 50, 50) - - sizer = wx.BoxSizer(wx.VERTICAL) - - settingsPanel = wx.Panel(self._mainPanel, wx.ID_ANY) - - # Build the widgets used to build a selection from selection strings and operators - self._queryPanel = wx.Panel(settingsPanel) - - self.filterTree = wx.TreeCtrl( - self._queryPanel, - 1, - wx.DefaultPosition, - style=wx.TR_HIDE_ROOT | wx.TR_HAS_BUTTONS, - ) - - root = self.filterTree.AddRoot("filters") - filters = self.filterTree.AppendItem(root, "Filter by") - selectors = list(REGISTRY["selector"].values()) - self.__filters = collections.OrderedDict() - for selector in selectors: - if selector.section is not None: - if selector.section in self.__filters: - self.__filters[selector.section].append(selector._type) - else: - self.__filters[selector.section] = [selector._type] - - for section, subsections in sorted(self.__filters.items()): - section_node = self.filterTree.AppendItem(filters, section) - for subsection in sorted(subsections): - self.filterTree.AppendItem(section_node, subsection) - - self.filterTree.Expand(filters) - - self.values = wx.ListBox( - self._queryPanel, wx.ID_ANY, style=wx.LB_MULTIPLE | wx.LB_NEEDED_SB - ) - - leftBraceLinker = wx.Button(self._queryPanel, wx.ID_ANY, label="(") - rightBraceLinker = wx.Button(self._queryPanel, wx.ID_ANY, label=")") - andLinker = wx.Button(self._queryPanel, wx.ID_ANY, label="and") - orLinker = wx.Button(self._queryPanel, wx.ID_ANY, label="or") - notLinker = wx.Button(self._queryPanel, wx.ID_ANY, label="not") - - selectionStringSizer = wx.BoxSizer(wx.VERTICAL) - keywordsValuesSizer = wx.BoxSizer(wx.HORIZONTAL) - keywordsValuesSizer.Add( - self.filterTree, - 1, - wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT | wx.EXPAND, - 2, - ) - keywordsValuesSizer.Add( - self.values, 3, wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT | wx.EXPAND, 2 - ) - linkersSizer = wx.BoxSizer(wx.HORIZONTAL) - linkersSizer.Add(leftBraceLinker, 1, flag=wx.ALL | wx.EXPAND) - linkersSizer.Add(rightBraceLinker, 1, flag=wx.ALL | wx.EXPAND) - linkersSizer.Add(andLinker, 1, flag=wx.ALL | wx.EXPAND) - linkersSizer.Add(orLinker, 1, flag=wx.ALL | wx.EXPAND) - linkersSizer.Add(notLinker, 1, flag=wx.ALL | wx.EXPAND) - selectionStringSizer.Add(keywordsValuesSizer, 1, wx.ALL | wx.EXPAND, 5) - selectionStringSizer.Add(linkersSizer, 0, wx.ALL | wx.EXPAND, 5) - self._queryPanel.SetSizer(selectionStringSizer) - - selectionSizer = wx.BoxSizer(wx.VERTICAL) - selectionSizer.Add(self._queryPanel, 1, wx.ALL | wx.EXPAND, 5) - - settingsPanel.SetSizer(selectionSizer) - - # The widgets related to the selection being performed - selectionExpressionStaticBox = wx.StaticBox( - self._mainPanel, wx.ID_ANY, label="Selection" - ) - selectionExpressionStaticBoxSizer = wx.StaticBoxSizer( - selectionExpressionStaticBox, wx.HORIZONTAL - ) - - self.selectionTextCtrl = wx.TextCtrl( - self._mainPanel, wx.ID_ANY, style=wx.TE_READONLY - ) - clearButton = wx.Button(self._mainPanel, wx.ID_ANY, label="Clear") - - self._selectionExpressionSizer = wx.GridBagSizer(5, 5) - self._selectionExpressionSizer.AddGrowableCol(0) - self._selectionExpressionSizer.Add( - self.selectionTextCtrl, pos=(0, 0), span=(1, 2), flag=wx.ALL | wx.EXPAND - ) - self._selectionExpressionSizer.Add(clearButton, pos=(0, 2), flag=wx.ALL) - selectionExpressionStaticBoxSizer.Add( - self._selectionExpressionSizer, 1, wx.ALL | wx.EXPAND, 5 - ) - - self._selectionSummary = wx.TextCtrl( - self._mainPanel, - wx.ID_ANY, - style=wx.TE_LINEWRAP | wx.TE_MULTILINE | wx.TE_READONLY, - ) - - sizer.Add(settingsPanel, 2, wx.ALL | wx.EXPAND, 5) - sizer.Add(selectionExpressionStaticBoxSizer, 0, wx.ALL | wx.EXPAND, 5) - sizer.Add(self._selectionSummary, 1, wx.ALL | wx.EXPAND, 5) - - self._mainPanel.SetSizer(sizer) - - self._mainSizer = wx.BoxSizer(wx.VERTICAL) - self._mainSizer.Add(self._mainPanel, 1, wx.EXPAND | wx.ALL, 5) - self.SetSizer(self._mainSizer) - - self.Bind( - wx.EVT_TREE_SEL_CHANGED, self.on_display_keyword_values, self.filterTree - ) - self.Bind(wx.EVT_LISTBOX, self.on_insert_keyword_values, self.values) - - self.Bind(wx.EVT_BUTTON, self.on_add_operator, leftBraceLinker) - self.Bind(wx.EVT_BUTTON, self.on_add_operator, rightBraceLinker) - self.Bind(wx.EVT_BUTTON, self.on_add_operator, orLinker) - self.Bind(wx.EVT_BUTTON, self.on_add_operator, andLinker) - self.Bind(wx.EVT_BUTTON, self.on_add_operator, notLinker) - - self.Bind(wx.EVT_BUTTON, self.on_clear, clearButton) - - def plug(self): - self._parent._mgr.GetPane(self).Float().Floatable(True).Dockable( - True - ).CloseButton(True) - - self._parent._mgr.Update() - - self.set_trajectory(self.dataproxy.data) - - if self.parent.selectedAtoms: - self.insert_keyword_values("atom_picked", sorted(self.parent.selectedAtoms)) - - def set_trajectory(self, trajectory): - self._trajectory = trajectory - - self._query.set_parser(AtomSelectionParser(self._trajectory)) - - self._atoms = sorted_atoms(self._trajectory.universe) - - self._target = os.path.basename(self._trajectory.filename) - - def display_selection_summary(self): - self._selectionSummary.Clear() - - nSelectedAtoms = len(self._selection) - - text = [] - text.append("Number of selected atoms: %d\n" % nSelectedAtoms) - - if nSelectedAtoms == 0: - return - - text.append("List of selected atoms:") - for idx in self._selection: - text.append( - "\t%s (Index: %d)" - % (self._atoms[idx].fullName(), self._atoms[idx].index) - ) - - self._selectionSummary.SetValue("\n".join(text)) - - def insert_keyword_values(self, keyword, values): - self._query.add_query([keyword, values]) - - self.set_selection() - - self.selectionTextCtrl.SetValue(self._query.get_expression()) - - self.display_selection_summary() - - def on_add_operator(self, event=None): - operator = event.GetEventObject().GetLabel() - - self._query.add_operator(operator) - - self.selectionTextCtrl.SetValue(self._query.get_expression()) - - self.values.DeselectAll() - - def on_browse_python_script(self, event): - dlg = wx.FileDialog( - self, - "Browse python selection script", - defaultDir=os.getcwd(), - wildcard="Python files (*.py)|*.py", - style=wx.FD_OPEN | wx.FD_MULTIPLE, - ) - - if dlg.ShowModal() == wx.ID_OK: - self.insert_keyword_values("pythonscript", dlg.GetPaths()) - - def on_clear(self, event=None): - self._query.clear() - - self.selectionTextCtrl.Clear() - - self.values.DeselectAll() - - self._selectionSummary.Clear() - - PUBLISHER.sendMessage("msg_clear_selection", message=self) - - def on_display_keyword_values(self, event=None): - if self._trajectory is None: - return - - item = event.GetItem() - - selectionFilter = self.filterTree.GetItemText(item) - - if selectionFilter not in REGISTRY["selector"]: - return - - if selectionFilter not in self._selectors: - self._selectors[selectionFilter] = [ - str(v) - for v in REGISTRY["selector"][selectionFilter](self._trajectory).choices - ] - - self.values.DeselectAll() - - self.values.Set(self._selectors[selectionFilter]) - - def on_insert_keyword_values(self, event): - item = self.filterTree.GetSelection() - - keyword = str(self.filterTree.GetItemText(item)) - - values = [str(self.values.GetString(v)) for v in self.values.GetSelections()] - - self.insert_keyword_values(keyword, values) - - def on_mode_selection(self, event=None): - self.selectedMode = str(event.GetEventObject().GetLabelText()).lower() - - self.keywords.DeselectAll() - self.values.DeselectAll() - - def msg_select_atoms_from_viewer(self, message): - dataPlugin, selection = message - - if dataPlugin != get_data_plugin(self): - return - - self._query.clear() - - self.insert_keyword_values("atom_picked", selection) - - def set_selection(self): - _, self._selection = self._query.parse() - - PUBLISHER.sendMessage("msg_set_selection", message=self) - - @property - def selection(self): - return self._selection - - def validate(self): - if not self._selection: - LOGGER("The current selection is empty", "error", ["dialog"]) - return None - - return {"indexes": self._selection} - - -REGISTRY["atom_selection"] = AtomSelectionPlugin diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/AtomsListPlugin.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/AtomsListPlugin.py deleted file mode 100644 index f92a91690f..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/AtomsListPlugin.py +++ /dev/null @@ -1,266 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/AtomsListPlugin.py -# @brief Implements module/class/test AtomsListPlugin -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import os - -import wx - -from MDANSE import LOGGER, REGISTRY -from MDANSE.GUI.Plugins.UserDefinitionPlugin import UserDefinitionPlugin -from MDANSE.MolecularDynamics.Trajectory import ( - find_atoms_in_molecule, - get_chemical_objects_dict, -) - - -class AtomNameDropTarget(wx.TextDropTarget): - def __init__(self, molTree, atList): - wx.TextDropTarget.__init__(self) - self._molecules = molTree - self._atoms = atList - self._currentMolecule = None - - def OnDropText(self, x, y, data): - listedAtoms = [ - self._atoms.GetItem(idx).GetText() - for idx in range(self._atoms.GetItemCount()) - ] - - if data in listedAtoms: - return - - atTreeItem = self._molecules.GetSelection() - molTreeItem = self._molecules.GetItemParent(atTreeItem) - - molname = self._molecules.GetItemText(molTreeItem) - - if self._atoms.GetItemCount() > 0: - if molname != self._currentMolecule: - LOGGER( - "The dragged atoms does not belong to the same molecule than the current selection.", - "error", - ["dialog"], - ) - return - else: - self._currentMolecule = molname - - self._atoms.Append([data]) - - -class AtomsListPlugin(UserDefinitionPlugin): - label = "Atoms list" - - ancestor = ["molecular_viewer"] - - def __init__(self, parent, *args, **kwargs): - self._parent = parent - - self._nAtoms = 1 - - self._selectedAtoms = [] - - self._selection = [] - - UserDefinitionPlugin.__init__(self, parent, size=(600, 600)) - - def build_panel(self): - self._mainPanel = wx.ScrolledWindow(self, wx.ID_ANY, size=self.GetSize()) - self._mainPanel.SetScrollbars(20, 20, 50, 50) - - sizer = wx.BoxSizer(wx.VERTICAL) - - self._nAtomsSelectionSizer = wx.BoxSizer(wx.HORIZONTAL) - - label = wx.StaticText(self._mainPanel, wx.ID_ANY, label="Number of atoms") - - self._nAtomsSpinCtrl = wx.SpinCtrl( - self._mainPanel, wx.ID_ANY, style=wx.SP_ARROW_KEYS | wx.SP_WRAP - ) - self._nAtomsSpinCtrl.SetRange(1, 100) - self._nAtomsSpinCtrl.SetValue(self._nAtoms) - - self._nAtomsSelectionSizer.Add(label, 0, wx.ALL | wx.ALIGN_CENTRE_VERTICAL, 5) - self._nAtomsSelectionSizer.Add(self._nAtomsSpinCtrl, 1, wx.ALL | wx.EXPAND, 5) - - gbSizer = wx.GridBagSizer(5, 5) - - label1 = wx.StaticText(self._mainPanel, wx.ID_ANY, label="Molecules") - label2 = wx.StaticText(self._mainPanel, wx.ID_ANY, label="Selected atoms") - - gbSizer.Add(label1, (0, 0), flag=wx.EXPAND) - gbSizer.Add(label2, (0, 1), flag=wx.EXPAND) - - self._molecules = wx.TreeCtrl( - self._mainPanel, wx.ID_ANY, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT - ) - - self._atoms = wx.ListCtrl(self._mainPanel, wx.ID_ANY) - - self._dt = AtomNameDropTarget(self._molecules, self._atoms) - self._atoms.SetDropTarget(self._dt) - - gbSizer.Add(self._molecules, (1, 0), flag=wx.EXPAND) - gbSizer.Add(self._atoms, (1, 1), flag=wx.EXPAND) - - gbSizer.AddGrowableRow(1) - gbSizer.AddGrowableCol(0) - gbSizer.AddGrowableCol(1) - - self._resultsTextCtrl = wx.TextCtrl( - self._mainPanel, wx.ID_ANY, style=wx.TE_READONLY | wx.TE_MULTILINE - ) - - sizer.Add(self._nAtomsSelectionSizer, 0, wx.EXPAND | wx.ALL, 5) - sizer.Add(gbSizer, 1, wx.EXPAND | wx.ALL, 5) - sizer.Add(self._resultsTextCtrl, 1, wx.EXPAND | wx.ALL, 5) - - self._mainPanel.SetSizer(sizer) - - self._mainSizer = wx.BoxSizer(wx.VERTICAL) - self._mainSizer.Add(self._mainPanel, 1, wx.EXPAND | wx.ALL, 5) - self.SetSizer(self._mainSizer) - - self.Bind(wx.EVT_SPINCTRL, self.on_define_list_size, self._nAtomsSpinCtrl) - self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.on_add_atom, self._molecules) - self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.on_add_atom) - self.Bind(wx.EVT_LIST_KEY_DOWN, self.on_keypress_atom, self._atoms) - - 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 enable_natoms_selection(self, state): - self._nAtomsSpinCtrl.Enable(state) - - def set_natoms(self, nAtoms): - self._nAtoms = nAtoms - - self._nAtomsSpinCtrl.SetValue(nAtoms) - - def set_trajectory(self, trajectory): - self._trajectory = trajectory - - self._target = os.path.basename(self._trajectory.filename) - - self._molecularContents = get_chemical_objects_dict(self._trajectory.universe) - - root = self._molecules.AddRoot("") - - for mname in sorted(self._molecularContents.keys()): - molnode = self._molecules.AppendItem(root, mname) - atomsList = self._molecularContents[mname][0].atomList() - atomNames = sorted(set([at.name for at in atomsList])) - for aname in atomNames: - self._molecules.AppendItem(molnode, aname) - - def on_define_list_size(self, event): - self._nAtoms = event.GetInt() - - self._atoms.ClearAll() - - self._resultsTextCtrl.Clear() - - def on_keypress_atom(self, event): - keycode = event.GetKeyCode() - if keycode == wx.WXK_DELETE: - item = self._atoms.GetFirstSelected() - selectedItems = [] - while item != -1: - selectedItems.append(item) - item = self._atoms.GetNextSelected(item) - - if not selectedItems: - return - - selectedItems.reverse() - for it in selectedItems: - self._atoms.DeleteItem(it) - - self._selection = [] - self._resultsTextCtrl.Clear() - - # This is the ASCII value for Ctrl+A key - elif keycode == 1: - for i in range(self._atoms.GetItemCount()): - item = self._atoms.GetItem(i) - self._atoms.SetItemState( - item.GetId(), wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED - ) - - def on_add_atom(self, event): - item = event.GetItem() - - parentItem = self._molecules.GetItemParent(item) - if parentItem == self._molecules.GetRootItem(): - return - - if self._atoms.GetItemCount() >= self._nAtoms: - return - - text = self._molecules.GetItemText(item) - tdo = wx.TextDataObject(text) - tds = wx.DropSource(self._molecules) - tds.SetData(tdo) - - # Case of a drag and drop event - if event.GetEventType() == wx.wxEVT_COMMAND_TREE_BEGIN_DRAG: - tds.DoDragDrop(wx.Drag_CopyOnly) - # Case of a double click event - else: - self._dt.OnDropText(-1, -1, text) - - if self._atoms.GetItemCount() == self._nAtoms: - self._resultsTextCtrl.Clear() - self._selection = [] - atTreeItem = self._molecules.GetSelection() - molTreeItem = self._molecules.GetItemParent(atTreeItem) - molecule = self._molecules.GetItemText(molTreeItem) - self._selectedAtoms = [ - self._atoms.GetItem(idx).GetText() - for idx in range(self._atoms.GetItemCount()) - ] - self._selection = find_atoms_in_molecule( - self._trajectory.universe, molecule, self._selectedAtoms, True - ) - - self._resultsTextCtrl.AppendText( - "Number of selected %d-tuplets: %d\n" - % (self._nAtoms, len(self._selection)) - ) - for idxs in self._selection: - line = " ; ".join( - [ - "Atom %5d : %s" % (v, self._selectedAtoms[i]) - for i, v in enumerate(idxs) - ] - ) - self._resultsTextCtrl.AppendText(line) - self._resultsTextCtrl.AppendText("\n") - - def validate(self): - if not self._selection: - LOGGER("The current selection is empty", "error", ["dialog"]) - return None - - return {"indexes": self._selection, "natoms": self._nAtoms} - - -REGISTRY["atoms_list"] = AtomsListPlugin diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/ComponentPlugin.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/ComponentPlugin.py deleted file mode 100644 index 5ad0b65c5a..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/ComponentPlugin.py +++ /dev/null @@ -1,30 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/ComponentPlugin.py -# @brief Implements module/class/test ComponentPlugin -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -from MDANSE.GUI.Plugins.IPlugin import IPlugin - - -class ComponentPlugin(IPlugin): - @property - def datakey(self): - return self.parent.datakey - - @property - def dataproxy(self): - return self.parent.dataproxy - - @property - def dataplugin(self): - return self.parent.dataplugin diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/DataInfoPlugin.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/DataInfoPlugin.py deleted file mode 100644 index 379359a28f..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/DataInfoPlugin.py +++ /dev/null @@ -1,68 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/DataInfoPlugin.py -# @brief Implements module/class/test DataInfoPlugin -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx -import wx.aui as aui - -from MDANSE import REGISTRY -from MDANSE.GUI.Plugins.ComponentPlugin import ComponentPlugin - - -class DataInfoPlugin(ComponentPlugin): - label = "Data info" - - ancestor = list(REGISTRY["input_data"].keys()) - - def __init__(self, parent, *args, **kwargs): - ComponentPlugin.__init__(self, parent, size=(-1, 50), *args, **kwargs) - - def build_panel(self): - panel = wx.Panel(self, wx.ID_ANY, size=self.GetSize()) - - sizer = wx.BoxSizer(wx.HORIZONTAL) - - self._info = wx.TextCtrl( - panel, wx.ID_ANY, style=wx.TE_MULTILINE | wx.TE_READONLY - ) - - sizer.Add(self._info, 1, wx.ALL | wx.EXPAND, 5) - - panel.SetSizer(sizer) - sizer.Fit(panel) - panel.Layout() - - self._mgr.AddPane( - panel, - aui.AuiPaneInfo() - .Center() - .Dock() - .CaptionVisible(False) - .CloseButton(False) - .MinSize(self.GetSize()), - ) - - self._mgr.Update() - - def on_close(self, event): - self.parent.mgr.ClosePane(self.parent.mgr.GetPane(self)) - - def plug(self): - self._info.SetValue(self.dataproxy.info()) - - self._parent._mgr.GetPane(self).Float().CloseButton(True).BestSize((600, 600)) - self._parent._mgr.Update() - - -REGISTRY["data_info"] = DataInfoPlugin diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/DataPlugin.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/DataPlugin.py deleted file mode 100644 index 135d56fcc7..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/DataPlugin.py +++ /dev/null @@ -1,63 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/DataPlugin.py -# @brief Implements module/class/test DataPlugin -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx - -from MDANSE.GUI.DataController import DATA_CONTROLLER -from MDANSE.GUI.Plugins.IPlugin import IPlugin - - -def get_data_plugin(window): - if isinstance(window, DataPlugin): - return window - - else: - try: - return get_data_plugin(window.Parent) - except AttributeError: - return None - - -class DataPlugin(IPlugin): - ancestor = [] - - def __init__(self, parent, datakey, **kwargs): - IPlugin.__init__(self, parent, wx.ID_ANY, **kwargs) - - self._datakey = datakey - - self._dataProxy = DATA_CONTROLLER[self._datakey] - - def build_panel(self): - pass - - def plug(self, standalone=False): - pass - - @property - def datakey(self): - return self._datakey - - @datakey.setter - def datakey(self, key): - self._datakey = key - - @property - def dataproxy(self): - return self._dataProxy - - @property - def dataplugin(self): - return self diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/DensitySuperpositionPlugin.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/DensitySuperpositionPlugin.py deleted file mode 100644 index e3da7b45c7..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/DensitySuperpositionPlugin.py +++ /dev/null @@ -1,452 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/DensitySuperpositionPlugin.py -# @brief Implements module/class/test DensitySuperpositionPlugin -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx -import wx.aui as aui - -import vtk - -import numpy as np - -import netCDF4 - -from MDANSE import REGISTRY -from MDANSE.Core.Error import Error -from MDANSE.GUI.Plugins.ComponentPlugin import ComponentPlugin - - -class DensitySuperpositionError(Error): - pass - - -class DensitySuperpositionPlugin(ComponentPlugin): - label = "Density superposition" - - ancestor = ["molecular_viewer"] - - def __init__(self, parent, *args, **kwargs): - self.currentFilename = None - - ComponentPlugin.__init__(self, parent, size=parent.GetSize(), *args, **kwargs) - - def build_panel(self): - self._mainPanel = wx.Panel(self, wx.ID_ANY, size=self.GetSize()) - - mainSizer = wx.BoxSizer(wx.VERTICAL) - - sb1 = wx.StaticBox(self._mainPanel, wx.ID_ANY, label="Select file") - sourcesSizer = wx.StaticBoxSizer(sb1, wx.HORIZONTAL) - - self._filelist = wx.Choice(self._mainPanel, wx.ID_ANY) - self._browse = wx.Button(self._mainPanel, wx.ID_ANY, label="Browse") - - sourcesSizer.Add(self._filelist, 1, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 0) - sourcesSizer.Add(self._browse, 0, wx.ALIGN_CENTER_VERTICAL, 0) - - # Add to main sizer - mainSizer.Add(sourcesSizer, 0, wx.ALL | wx.EXPAND, 5) - - sb1 = wx.StaticBox(self._mainPanel, wx.ID_ANY, label="Contour Level") - isovSizer = wx.StaticBoxSizer(sb1, wx.HORIZONTAL) - self.isov_scale = 100.0 - self.isov_slider = wx.Slider(self._mainPanel, wx.ID_ANY, style=wx.SL_HORIZONTAL) - self.isov_slider.Disable() - - isovSizer.Add(self.isov_slider, 1, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 0) - - self.dim_label = wx.StaticText(self._mainPanel, label="Shape") - self.dim = wx.TextCtrl( - self._mainPanel, wx.ID_ANY, style=wx.SL_HORIZONTAL | wx.TE_READONLY - ) - - self.rendlist_label = wx.StaticText(self._mainPanel, label="Rendering mode") - self.rendlist = wx.ComboBox( - self._mainPanel, - id=wx.ID_ANY, - choices=["surface", "wireframe", "points"], - style=wx.CB_READONLY, - ) - self.rendlist.SetValue("surface") - - self.opacity_label = wx.StaticText(self._mainPanel, label="Opacity level [0-1]") - self.opacity = wx.TextCtrl( - self._mainPanel, wx.ID_ANY, style=wx.SL_HORIZONTAL | wx.TE_PROCESS_ENTER - ) - self.opacity.SetValue(str(0.5)) - - sb2 = wx.StaticBox(self._mainPanel, wx.ID_ANY, label="Parameters") - paramsbsizer = wx.StaticBoxSizer(sb2, wx.HORIZONTAL) - - gbSizer = wx.GridBagSizer(5, 5) - - gbSizer.Add(self.dim_label, (0, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer.Add(self.dim, (0, 1), flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND) - gbSizer.Add(self.rendlist_label, (1, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer.Add(self.rendlist, (1, 1), flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND) - gbSizer.Add(self.opacity_label, (2, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer.Add(self.opacity, (2, 1), flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND) - - gbSizer.Add( - isovSizer, (3, 0), span=(3, 4), flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND - ) - - paramsbsizer.Add(gbSizer, 1, wx.ALL | wx.EXPAND, 5) - - # Add to main sizer - mainSizer.Add(paramsbsizer, 1, wx.ALL | wx.EXPAND, 5) - - actionsSizer = wx.BoxSizer(wx.HORIZONTAL) - - clearButton = wx.Button(self._mainPanel, wx.ID_ANY, label="Clear") - superButton = wx.Button(self._mainPanel, wx.ID_ANY, label="Draw") - - actionsSizer.Add(clearButton, 0, wx.ALL, 5) - actionsSizer.Add(superButton, 0, wx.ALL, 5) - - # Add to main sizer - mainSizer.Add(actionsSizer, 1, wx.ALL | wx.ALIGN_RIGHT, 5) - - self._mainPanel.SetSizer(mainSizer) - mainSizer.Fit(self._mainPanel) - self._mainPanel.Layout() - - self.Bind(wx.EVT_CHOICE, self.on_select_file, self._filelist) - self.Bind(wx.EVT_BUTTON, self.on_browse, self._browse) - self.Bind(wx.EVT_BUTTON, self.on_clear, clearButton) - self.Bind(wx.EVT_BUTTON, self.on_superpose, superButton) - self.Bind(wx.EVT_SCROLL, self.on_change_isov, self.isov_slider) - self.Bind(wx.EVT_COMBOBOX, self.on_change_surf_rend_mode, self.rendlist) - self.Bind(wx.EVT_TEXT_ENTER, self.on_set_opacity, self.opacity) - - @property - def dataDict(self): - return self._dataDict - - @property - def renderer(self): - return self.parent._renderer - - @property - def iren(self): - return self.parent._iren - - @property - def camera(self): - return self.parent.camera - - @property - def molecule(self): - return self.parent.molecule - - @property - def surface(self): - return self.parent._surface - - @surface.setter - def surface(self, value): - self.parent._surface = value - - @property - def iso(self): - return self.parent._iso - - @iso.setter - def iso(self, value): - self.parent._iso = value - - @property - def cell_bounds_coords(self): - return self.parent.cell_bounds_coords - - def unique(self, key, dic): - skey = key - i = 0 - while key in list(dic.keys()): - key = skey + "_%d" % i - i += 1 - return key - - def on_keyboard_input(self, obj, event): - key = self.iren.GetKeyCode() - s = self.get_spacing() - if key in ["x"]: - self.xyz = [1, 0, 0] - elif key in ["y"]: - self.xyz = [0, 1, 0] - elif key in ["z"]: - self.xyz = [0, 0, 1] - elif key in ["+"]: - self.surface.AddPosition( - self.xyz[0] * s[0] / 2.0, - self.xyz[1] * s[1] / 2.0, - self.xyz[2] * s[2] / 2.0, - ) - elif key in ["-"]: - self.surface.AddPosition( - -self.xyz[0] * s[0] / 2.0, - -self.xyz[1] * s[1] / 2.0, - -self.xyz[2] * s[2] / 2.0, - ) - self.iren.Render() - - def on_browse(self, event): - filters = "NC file (*.nc)|*.nc|All files (*.*)|*.*" - dialog = wx.FileDialog( - None, message="Open file...", wildcard=filters, style=wx.MULTIPLE - ) - if dialog.ShowModal() == wx.ID_CANCEL: - return - - pathlist = dialog.GetPaths() - - for i in range(len(pathlist)): - filename = pathlist[i] - if filename in self._filelist.GetStrings(): - continue - self._filelist.Append(filename) - self._filelist.Select(self._filelist.GetCount() - 1) - self.select_file(filename) - - def select_file(self, filename): - self.currentFilename = filename - f = netCDF4.Dataset(filename, "r") - variables = f.variables - - if "molecular_trace" not in variables: - raise DensitySuperpositionError( - "Trace file format not compatible with Plugin" - ) - - self.dim.SetValue(str(variables["molecular_trace"][:].shape)) - f.close() - - def on_select_file(self, event): - if event.GetString() == self.currentFilename: - return - self.select_file(event.GetString()) - - def get_file(self): - return self._filelist.GetStringSelection() - - def get_variable(self): - return self.selectedVar - - def get_spacing(self): - spacing = float(self.spacing.GetValue()) - return np.array([spacing, spacing, spacing]) - - def on_clear(self, event=None): - if self.surface is None: - return - - self.surface.VisibilityOff() - self.surface.ReleaseGraphicsResources(self.iren.GetRenderWindow()) - self.renderer.RemoveActor(self.surface) - self.parent.del_surface() - self.iren.Render() - - def on_superpose(self, event): - self.on_clear() - rendtype = self.rendlist.GetValue() - opacity = float(self.opacity.GetValue()) - filename = self.get_file() - - f = netCDF4.Dataset(filename, "r") - variables = f.variables - - data = variables["molecular_trace"][:] - origin = variables["origin"][:] - spacing = variables["spacing"][:] - - f.close() - - mi, ma = self.draw_isosurface(data, rendtype, opacity, origin, spacing) - self.isov_slider.SetRange(mi, ma) - self.isov_slider.Enable() - - def close(self): - self.on_clear() - - def plug(self): - self.parent.mgr.GetPane(self).Float().CloseButton(True).BestSize((360, 300)) - self.parent.mgr.Update() - - def array_to_3d_imagedata(self, data, spacing): - if data.ndim != 3: - raise DensitySuperpositionError("Data dimension should be 3") - nx = data.shape[0] - ny = data.shape[1] - nz = data.shape[2] - image = vtk.vtkImageData() - image.SetDimensions(nx, ny, nz) - dx, dy, dz = spacing - image.SetSpacing(dx, dy, dz) - image.SetExtent(0, nx - 1, 0, ny - 1, 0, nz - 1) - if vtk.vtkVersion.GetVTKMajorVersion() < 6: - image.SetScalarTypeToDouble() - image.SetNumberOfScalarComponents(1) - else: - image.AllocateScalars(vtk.VTK_DOUBLE, 1) - - for i in range(nx): - for j in range(ny): - for k in range(nz): - image.SetScalarComponentFromDouble(i, j, k, 0, data[i, j, k]) - - return image - - def draw_isosurface(self, data, rendtype, opacity, origin, spacing): - self.image = self.array_to_3d_imagedata(data, spacing) - isovalue = data.mean() - mi, ma = data.min(), data.max() - - self.iso = vtk.vtkMarchingContourFilter() - self.iso.UseScalarTreeOn() - self.iso.ComputeNormalsOn() - if vtk.vtkVersion.GetVTKMajorVersion() < 6: - self.iso.SetInput(self.image) - else: - self.iso.SetInputData(self.image) - self.iso.SetValue(0, isovalue) - - self.depthSort = vtk.vtkDepthSortPolyData() - self.depthSort.SetInputConnection(self.iso.GetOutputPort()) - self.depthSort.SetDirectionToBackToFront() - self.depthSort.SetVector(1, 1, 1) - self.depthSort.SetCamera(self.camera) - self.depthSort.SortScalarsOn() - self.depthSort.Update() - - mapper = vtk.vtkPolyDataMapper() - mapper.SetInputConnection(self.depthSort.GetOutputPort()) - mapper.ScalarVisibilityOff() - mapper.Update() - - self.surface = vtk.vtkActor() - self.surface.SetMapper(mapper) - self.surface.GetProperty().SetColor((0, 0.5, 0.75)) - self.surface.GetProperty().SetOpacity(opacity) - self.surface.PickableOff() - - if rendtype == "wireframe": - self.surface.GetProperty().SetRepresentationToWireframe() - elif rendtype == "surface": - self.surface.GetProperty().SetRepresentationToSurface() - elif rendtype == "points": - self.surface.GetProperty().SetRepresentationToPoints() - self.surface.GetProperty().SetPointSize(5) - else: - self.surface.GetProperty().SetRepresentationToWireframe() - self.surface.GetProperty().SetInterpolationToGouraud() - self.surface.GetProperty().SetSpecular(0.4) - self.surface.GetProperty().SetSpecularPower(10) - - self.renderer.AddActor(self.surface) - - self.surface.SetPosition(origin[0], origin[1], origin[2]) - - self.iren.Render() - - return mi, ma - - def cpt_isosurf(self, event=None): - try: - isov = float(self.isov.GetValue()) - except: - raise DensitySuperpositionError( - "Contour level has wrong format : %s" % self.isov.GetValue() - ) - self.iso.SetValue(0, isov) - self.iso.Update() - self.iren.Render() - - def on_change_isov(self, event=None): - if self.iso is None: - return - isov = float(self.isov_slider.GetValue()) / self.isov_scale - self.iso.SetValue(0, isov) - self.iso.Update() - self.iren.Render() - - def on_set_opacity(self, event=None): - if self.surface is None: - return - opct = float(self.opacity.GetValue()) - self.surface.GetProperty().SetOpacity(opct) - self.iren.Render() - - def on_change_surf_rend_mode(self, event=None): - if self.surface is None: - return - rendtype = self.rendlist.GetValue() - if rendtype == "wireframe": - self.surface.GetProperty().SetRepresentationToWireframe() - elif rendtype == "surface": - self.surface.GetProperty().SetRepresentationToSurface() - elif rendtype == "points": - self.surface.GetProperty().SetRepresentationToPoints() - self.surface.GetProperty().SetPointSize(3) - self.iren.Render() - - -class FakeIren(object): - def AddObserver(self, *args, **kwargs): - pass - - -class TestFrame(wx.Frame): - def __init__(self, parent, title="Density Superposition"): - wx.Frame.__init__( - self, - parent, - wx.ID_ANY, - title, - style=wx.DEFAULT_DIALOG_STYLE - | wx.MINIMIZE_BOX - | wx.MAXIMIZE_BOX - | wx.RESIZE_BORDER, - ) - - self._renderer = None - self._iren = FakeIren() - self.camera = None - self.molecule = None - - self._mgr = aui.AuiManager(self) - - self.__build_dialog() - - def __build_dialog(self): - self.SetSize((360, 300)) - self.plugin = DensitySuperpositionPlugin(self) - self._mgr.AddPane( - self.plugin, - aui.AuiPaneInfo() - .DestroyOnClose() - .Dock() - .CaptionVisible(True) - .CloseButton(True) - .BestSize(self.GetSize()), - ) - self._mgr.Update() - - -REGISTRY["density_superposition"] = DensitySuperpositionPlugin - -if __name__ == "__main__": - app = wx.App(False) - f = TestFrame(None) - f.Show() - app.MainLoop() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/IPlugin.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/IPlugin.py deleted file mode 100644 index ad636b2f34..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/IPlugin.py +++ /dev/null @@ -1,190 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/IPlugin.py -# @brief Implements module/class/test IPlugin -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import abc -import pickle - -import wx -import wx.aui as aui - -from MDANSE import REGISTRY - -from MDANSE.GUI import PUBLISHER - - -def plugin_parent(window): - if window == window.TopLevelParent: - return None - - if isinstance(window, IPlugin): - return window - - else: - return plugin_parent(window.Parent) - - -def uninit_aui_managers(mgr): - panes = mgr.GetAllPanes() - for pane in panes: - window = pane.window - if isinstance(window, IPlugin): - window.close() - uninit_aui_managers(window._mgr) - mgr.UnInit() - - -class PluginDropTarget(wx.DropTarget): - def __init__(self, targetPanel): - wx.DropTarget.__init__(self) - self._targetPanel = targetPanel - - self._data = wx.CustomDataObject("Plugin") - self.SetDataObject(self._data) - - @property - def target_panel(self): - return self._targetPanel - - def OnDrop(self, x, y): - return True - - def OnDragOver(self, x, y, d): - return wx.DragCopy - - def OnData(self, x, y, d): - if self.GetData(): - pluginName = pickle.loads(self._data.GetData()) - self._targetPanel.drop(pluginName) - - return d - - -class IPlugin(wx.Panel): - _registry = "plugin" - - ancestor = [] - - def __init__(self, parent, *args, **kwargs): - wx.Panel.__init__(self, parent, *args, **kwargs) - - self._parent = parent - - self._currentWindow = self - - self.SetDropTarget(PluginDropTarget(self)) - - self.build_dialog() - - self._mgr.Bind(wx.EVT_CHILD_FOCUS, self.on_changing_pane) - - self._mgr.Bind(aui.EVT_AUI_PANE_CLOSE, self.on_close_pane) - - @abc.abstractmethod - def build_panel(self): - pass - - @abc.abstractmethod - def plug(self, standalone=False): - pass - - @property - def mgr(self): - return self._mgr - - @property - def parent(self): - return self._parent - - def is_parent(self, window): - if window == self: - return True - - if window is None: - return False - - return self.is_parent(window.Parent) - - @property - 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: - event.Veto() - return - - window = event.GetPane().window - - # Call the 'close' method the plugin to be closed - window.close() - - uninit_aui_managers(self._mgr) - self._mgr.DetachPane(window) - self._mgr.Update() - window.Destroy() - - self.SetFocus() - - self._currentWindow = self - - PUBLISHER.sendMessage("msg_set_plugins_tree", message=self) - - def build_dialog(self): - self.Freeze() - - self._mgr = aui.AuiManager(self) - - self.build_panel() - - self._mgr.Update() - - self.Thaw() - - def drop(self, pluginName): - # If no plugin match the name of the dropped plugin, do nothing. - plugin = REGISTRY["plugin"].get(pluginName, None) - if plugin is None: - return - - plugin = plugin(self) - - self._mgr.AddPane( - plugin, aui.AuiPaneInfo().Caption(getattr(plugin, "label", pluginName)) - ) - - self._mgr.Update() - - plugin.plug() - - plugin.SetFocus() - - def on_changing_pane(self, event): - window = plugin_parent(event.GetWindow()) - - if window is None: - return - - self._currentWindow = window - - PUBLISHER.sendMessage("msg_set_plugins_tree", message=window) diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/JobPlugin.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/JobPlugin.py deleted file mode 100644 index 839df23f3c..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/JobPlugin.py +++ /dev/null @@ -1,236 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/JobPlugin.py -# @brief Implements module/class/test JobPlugin -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import os -import subprocess -import sys -import tempfile -import time - -import wx -import wx.aui as aui - -from MDANSE import PLATFORM, REGISTRY -from MDANSE.Framework.InputData.EmptyData import EmptyData - -from MDANSE.GUI import PUBLISHER -from MDANSE.GUI.DataController import DATA_CONTROLLER -from MDANSE.GUI.Plugins.ComponentPlugin import ComponentPlugin -from MDANSE.GUI.ComboWidgets.ConfigurationPanel import ConfigurationPanel -from MDANSE.GUI.ComboWidgets.JobHelpFrame import JobHelpFrame - - -class JobPlugin(ComponentPlugin): - def __init__(self, parent, standalone=False, *args, **kwargs): - self._job = REGISTRY["job"][self._type]() - - self._standlone = standalone - - ComponentPlugin.__init__(self, parent, size=wx.Size(800, 600), *args, **kwargs) - - def build_panel(self): - self._main = wx.ScrolledWindow(self, wx.ID_ANY, size=self.GetSize()) - self._main.SetScrollbars( - pixelsPerUnitX=20, pixelsPerUnitY=20, noUnitsX=500, noUnitsY=500 - ) - - mainSizer = wx.BoxSizer(wx.VERTICAL) - - self._parametersPanel = ConfigurationPanel(self._main, self._job, self._type) - - sb = wx.StaticBox(self._main, wx.ID_ANY) - sbSizer = wx.StaticBoxSizer(sb, wx.HORIZONTAL) - - helpButton = wx.Button(self._main, label="Help") - saveButton = wx.Button(self._main, label="Save") - runButton = wx.Button(self._main, label="Run") - - sbSizer.Add(helpButton, 0, wx.ALL | wx.EXPAND, 5) - sbSizer.Add((-1, -1), 1, wx.ALL | wx.EXPAND, 5) - sbSizer.Add(saveButton, 0, wx.ALL | wx.EXPAND, 5) - sbSizer.Add(runButton, 0, wx.ALL | wx.EXPAND, 5) - - mainSizer.Add(self._parametersPanel, 1, wx.ALL | wx.EXPAND, 0) - mainSizer.Add(sbSizer, 0, wx.ALL | wx.EXPAND, 5) - - self._main.SetSizer(mainSizer) - mainSizer.Layout() - self._main.Fit() - - self._mgr.AddPane( - self._main, - aui.AuiPaneInfo() - .Center() - .Floatable(False) - .Dock() - .CaptionVisible(False) - .CloseButton(False), - ) - - self._mgr.Update() - - self.Bind(wx.EVT_BUTTON, self.on_help, helpButton) - self.Bind(wx.EVT_BUTTON, self.on_save, saveButton) - self.Bind(wx.EVT_BUTTON, self.on_run, runButton) - - def on_help(self, event): - d = JobHelpFrame(self, self._job) - - d.Show() - - def on_run(self, event=None): - if not self._parametersPanel.validate(): - return - - parameters = self._parametersPanel.get_value() - - name = self._job.define_unique_name() - - handle, filename = tempfile.mkstemp(prefix="MDANSE_%s.py" % name, text=True) - os.close(handle) - - self._job.save(filename, parameters) - - if PLATFORM.name == "windows": - startupinfo = subprocess.STARTUPINFO() - startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW - startupinfo.wShowWindow = subprocess.SW_HIDE - else: - startupinfo = None - - try: - p = subprocess.Popen( - [sys.executable, filename], - startupinfo=startupinfo, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ) - except subprocess.CalledProcessError as e: - message = e.output - else: - message = None - - PUBLISHER.sendMessage("msg_start_job", message=message) - - if message is None and not self._standlone: - d = wx.MessageDialog( - None, - "Your analysis is performing. Do you want to close ?", - "Question", - wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, - ) - if d.ShowModal() == wx.ID_YES: - self.on_close(None) - - if self._standlone: - p.wait() - - def on_save(self, event=None): - if not self._parametersPanel.validate(): - return - - parameters = self._parametersPanel.get_value() - - d = wx.FileDialog( - self, - "Save MDANSE python script", - style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT, - wildcard="Python files (*.py)|*.py", - ) - if d.ShowModal() == wx.ID_CANCEL: - return - - path = d.GetPath().strip() - - if not path: - return - - if os.path.splitext(path)[1] != ".py": - path += ".py" - - self._job.save(path, parameters) - - def plug(self): - self._parent._mgr.GetPane(self).Float().Center().Floatable(True).Dockable( - True - ).CloseButton(True) - - self._parent._mgr.Update() - - PUBLISHER.sendMessage("msg_set_data", message=self) - - def on_close(self, event): - try: - self.parent.mgr.ClosePane(self.parent.mgr.GetPane(self)) - except AttributeError: - # If the job is a converter, the parent has no mgr attribute - self.parent.Close() - - -class JobDialog(wx.Dialog): - def __init__(self, parent, jobType, datakey=None): - wx.Dialog.__init__( - self, - parent, - wx.ID_ANY, - style=wx.DEFAULT_DIALOG_STYLE - | wx.MINIMIZE_BOX - | wx.MAXIMIZE_BOX - | wx.RESIZE_BORDER, - ) - - self._jobType = jobType - - job = REGISTRY["job"][self._jobType] - - self.SetTitle(job.label) - - data = REGISTRY["input_data"][job.ancestor[0]](datakey, True) - - self.datakey = data.name - - if not isinstance(data, EmptyData): - DATA_CONTROLLER[data.name] = data - - self._plugin = REGISTRY["plugin"][self._jobType](self, standalone=True) - - self.SetSize(self._plugin.GetSize()) - - self.Bind(wx.EVT_CLOSE, self.on_close, self) - - PUBLISHER.sendMessage("msg_set_data", message=self._plugin) - - def on_close(self, event): - self._plugin._mgr.UnInit() - - self.EndModal(wx.CANCEL) - - self.Destroy() - - -if __name__ == "__main__": - filename = os.path.join( - os.path.dirname(PLATFORM.package_directory()), - "Data", - "Trajectories", - "HDF", - "waterbox.h5", - ) - - app = wx.App(False) - f = JobFrame(None, "dacf", filename) - f.Show() - app.MainLoop() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/MolecularViewerPlugin.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/MolecularViewerPlugin.py deleted file mode 100644 index 6beb6922aa..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/MolecularViewerPlugin.py +++ /dev/null @@ -1,1175 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/MolecularViewerPlugin.py -# @brief Implements module/class/test MolecularViewerPlugin -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import os -import platform - -import numpy as np - -import vtk -from vtk.wx.wxVTKRenderWindowInteractor import wxVTKRenderWindowInteractor - -import wx -import wx.aui as aui - -from MDANSE import LOGGER, REGISTRY -from MDANSE.Chemistry import ATOMS_DATABASE -from MDANSE.Core.Error import Error -from MDANSE.Framework.UserDefinitionStore import UD_STORE -from MDANSE.MolecularDynamics.Configuration import ( - PeriodicRealConfiguration, - RealConfiguration, -) -from MDANSE.MolecularDynamics.Trajectory import sorted_atoms, Trajectory - -from MDANSE.GUI import PUBLISHER -from MDANSE.GUI.Plugins.DataPlugin import get_data_plugin -from MDANSE.GUI.Plugins.ComponentPlugin import ComponentPlugin - -# The colour for a selected atom (R,G,B,Alpha). -RGB_COLOURS = {} -RGB_COLOURS["selection"] = (0, (1.00, 0.20, 1.00)) -RGB_COLOURS["default"] = (1, (1.00, 0.90, 0.90)) -RGB_COLOURS["axis1"] = (2, (0.95, 0.00, 0.20)) -RGB_COLOURS["axis2"] = (3, (0.00, 0.20, 0.95)) -RGB_COLOURS["basis1"] = (4, (0.95, 0.00, 0.20)) -RGB_COLOURS["basis2"] = (5, (0.30, 0.95, 0.00)) -RGB_COLOURS["basis3"] = (6, (0.00, 0.20, 0.95)) - - -class MolecularViewerError(Error): - pass - - -class MyEventTimer(wx.Timer): - def __init__(self, iren): - wx.Timer.__init__(self) - self._iren = iren - - def Notify(self): - self._iren._Iren.TimerEvent() - - -class MyRenderWindowInteractor(wxVTKRenderWindowInteractor): - def CreateTimer(self, obj, evt): - self._timer = MyEventTimer(self) - self._timer.Start(obj.GetTimerEventDuration(), True) - - -class MvEvent(int): - def __init__(self, v): - self = v - - def GetId(self): - return self - - -class SelectionBox(vtk.vtkBoxWidget): - def __init__(self, viewer, selection_color): - self.viewer = viewer - self.selection_color = selection_color - outline = vtk.vtkOutlineFilter() - if vtk.vtkVersion.GetVTKMajorVersion() < 6: - outline.SetInput(self.viewer._polydata) - else: - outline.SetInputData(self.viewer._polydata) - - outlineMapper = vtk.vtkPolyDataMapper() - outlineMapper.SetInputConnection(outline.GetOutputPort()) - self.box = vtk.vtkLODActor() - self.box.SetMapper(outlineMapper) - self.box.GetProperty().SetColor(1, 1, 1) - self.box.PickableOff() - - self.SetProp3D(self.box) - self.planes = vtk.vtkPlanes() - self.SetInteractor(viewer.iren) - if vtk.vtkVersion.GetVTKMajorVersion() < 6: - self.SetInput(self.viewer._polydata) - else: - self.SetInputData(self.viewer._polydata) - - self.SetPlaceFactor(1) - self.PlaceWidget() - self.InsideOutOn() - self.SetRotationEnabled(0) - self.GetPlanes(self.planes) - self.AddObserver("EndInteractionEvent", self.on_select_atoms) - - def is_enabled(self): - return self.GetEnabled() - - def show(self): - self.SetEnabled(1) - - def hide(self): - self.SetEnabled(0) - - def on_off(self): - if self.GetEnabled(): - self.SetEnabled(0) - else: - self.SetEnabled(1) - - def on_select_atoms(self, obj=None, evt=None): - polybox = vtk.vtkPolyData() - self.GetPolyData(polybox) - (xmin, xmax, ymin, ymax, zmin, zmax) = polybox.GetBounds() - selection = [] - for i in range(self.viewer.n_atoms): - x, y, z = self.viewer._polydata.GetPoint(i) - if ( - x >= xmin - and x <= xmax - and y >= ymin - and y <= ymax - and z >= zmin - and z <= zmax - ): - selection.append(i) - - self.viewer.pick_atoms(selection, True) - - -class MolecularViewerPlugin(ComponentPlugin): - """ - This class sets up a molecular viewer using vtk functionnalities. - """ - - label = "Molecular Viewer" - - ancestor = ["hdf_trajectory"] - - category = ("Viewer",) - - # 0 line / 1 sphere / 2 tube / 3 sphere + tube / 4 sphere + line - _rendmod = 4 - - def __init__(self, parent, *args, **kwargs): - ComponentPlugin.__init__(self, parent, *args, **kwargs) - - self.enable_picking(True) - - def build_panel(self): - self._iren = MyRenderWindowInteractor(self, wx.ID_ANY, size=self.GetSize()) - self._iren.SetPosition((0, 0)) - - # define interaction style - self._iren.GetInteractorStyle().SetCurrentStyleToTrackballCamera() # change interaction style - - self._iren.Enable(1) - - # create renderer - self._renderer = vtk.vtkRenderer() - self._iren.GetRenderWindow().AddRenderer(self._renderer) - - # cam stuff - self.camera = vtk.vtkCamera() # create camera - self._renderer.SetActiveCamera(self.camera) # associate camera to renderer - self.camera.SetFocalPoint(0, 0, 0) - self.camera.SetPosition(0, 0, 20) - - self.__pickerObserverId = None - self.picker = vtk.vtkCellPicker() - self.picker.SetTolerance(0.005) - - self._iren.AddObserver("TimerEvent", self.on_timer) - self._iren.RemoveObservers("CharEvent") - self._iren.AddObserver("CharEvent", self.on_keyboard_input) - self._iren.AddObserver("LeftButtonPressEvent", self.emulate_focus) - - self._iren.Bind(wx.EVT_CONTEXT_MENU, self.on_show_popup_menu) - - PUBLISHER.subscribe(self.msg_set_selection, "msg_set_selection") - PUBLISHER.subscribe(self.msg_switch_viewers_state, "msg_switch_viewers_state") - PUBLISHER.subscribe(self.msg_clear_selection, "msg_clear_selection") - - self._mgr.AddPane( - self._iren, - aui.AuiPaneInfo().Dock().Center().CaptionVisible(False).CloseButton(False), - ) - - self._mgr.Update() - - self._first = True - self._timerCounter = 0 - self._timerInterval = 5 - self._animationLoop = False - self._trajectoryLoaded = False - self._currentFrame = 0 - self._maxLaps = 100 - self.display_bbox = False - self.bbox = None - - self._surface = None - self._iso = None - - # Atoms picked from mouse or selection box. - self.__pickedAtoms = set() - - self.SetFocusIgnoringChildren() - - def del_surface(self): - del self._surface - self._surface = None - - def msg_set_selection(self, message): - plugin = message - if not self.is_parent(plugin): - return - - self.show_selection(plugin.selection) - - def on_show_selection_box(self, message): - window, show = message.data - - if get_data_plugin(self) != get_data_plugin(window): - return - - self.show_selection_box(show) - - def on_enable_picking(self, message): - window, state = message.data - - if get_data_plugin(self) != get_data_plugin(window): - return - - self.enable_picking(state) - - def plug(self): - self._parent._mgr.GetPane(self).Dock().Floatable(False).Center().CloseButton( - True - ) - - self._parent._mgr.Update() - - self._trajectory = self.dataproxy.data - - self.set_trajectory(self._trajectory) - - def emulate_focus(self, obj=None, event=None): - self.SetFocusIgnoringChildren() - - def close(self): - # Ensure unsubscription - self.__unsubscribe() - # Clear the viewer - self.clear_universe() - - self._iren.GetRenderWindow().Finalize() - - def __del__(self): - # Ensure unsubscription - self.__unsubscribe() - - def __unsubscribe(self): - PUBLISHER.unsubscribe(self.msg_set_selection, "msg_set_selection") - PUBLISHER.unsubscribe(self.msg_switch_viewers_state, "msg_switch_viewers_state") - PUBLISHER.unsubscribe(self.msg_clear_selection, "msg_clear_selection") - - def set_trajectory(self, trajectory, selection=None, frame=0): - if not isinstance(trajectory, Trajectory): - return - - # The trajectory argument is copied. - if self._trajectoryLoaded: - self.clear_universe() - - self._nFrames = len(trajectory) - - self._atoms = sorted_atoms(trajectory.chemical_system.atom_list()) - - # The number of atoms of the universe stored by the trajectory. - self._nAtoms = trajectory.chemical_system.number_of_atoms() - - # Hack for reducing objects resolution when the system is big - self._resolution = int(np.sqrt(300000.0 / self._nAtoms)) - self._resolution = 10 if self._resolution > 10 else self._resolution - self._resolution = 4 if self._resolution < 4 else self._resolution - - # The array that will store the color and alpha scale for all the atoms. - self._atomsColours, self._lut = self.build_ColorTransferFunction() - self.atomsColours = np.copy(self._atomsColours) - - # The array that will store the scale for all the atoms. - self._atomsScales = np.array( - [ATOMS_DATABASE[at.symbol]["vdw_radius"] for at in self._atoms] - ).astype(np.float32) - - scalars = ndarray_to_vtkarray( - self.atomsColours, self._atomsScales, self._nAtoms - ) - - bonds = vtk.vtkCellArray() - for at in self._atoms: - idx1 = at.index - for bat in at.bonds: - idx2 = bat.index - line = vtk.vtkLine() - line.GetPointIds().SetId(0, idx1) - line.GetPointIds().SetId(1, idx2) - bonds.InsertNextCell(line) - - self._polydata = vtk.vtkPolyData() - self._polydata.GetPointData().SetScalars(scalars) - self._polydata.SetLines(bonds) - - self.clear_universe() - - self._trajectory = trajectory - - self.set_configuration(frame) - - self.enable_info_picking() - - self.__selectionBox = SelectionBox(self, RGB_COLOURS["selection"][0]) - - self._trajectoryLoaded = True - - PUBLISHER.sendMessage("msg_set_trajectory", message=self) - - def color_string_to_RGB(self, s): - if not s.strip(): - s = "1;1;1" - - return np.array(s.split(";")).astype(np.float32) / 255.0 - - def build_ColorTransferFunction(self): - lut = vtk.vtkColorTransferFunction() - - for idx, color in list(RGB_COLOURS.values()): - lut.AddRGBPoint(idx, *color) - - colours = [] - unic_colours = {} - - color_string_list = [ - self.color_string_to_RGB(ATOMS_DATABASE[at.symbol]["color"]) - for at in self._atoms - ] - col_ids = len(RGB_COLOURS) - - for col in color_string_list: - tup_col = tuple(col) - if not (tup_col in list(unic_colours.keys())): - unic_colours[tup_col] = col_ids - lut.AddRGBPoint(col_ids, *tup_col) - colours.append(col_ids) - col_ids += 1 - else: - colours.append(unic_colours[tup_col]) - - return colours, lut - - def enable_picking(self, state): - if state: - self.__pickerObserverId = self._iren.AddObserver( - "LeftButtonPressEvent", self.on_pick - ) - else: - if self.__pickerObserverId is None: - return - - self._iren.RemoveObserver(self.__pickerObserverId) - self.__pickerObserverId = None - - def enable_info_picking(self): - self._iren.AddObserver("LeftButtonPressEvent", self.on_info_pick) - - def on_show_popup_menu(self, event): - popupMenu = wx.Menu() - - renderingMenu = wx.Menu() - item = renderingMenu.Append(wx.ID_ANY, "Line") - self.Bind(wx.EVT_MENU, lambda event: self.set_rendering_mode(0), item) - - item = renderingMenu.Append(wx.ID_ANY, "Stick") - self.Bind(wx.EVT_MENU, lambda event: self.set_rendering_mode(2), item) - - item = renderingMenu.Append(wx.ID_ANY, "Ball") - self.Bind(wx.EVT_MENU, lambda event: self.set_rendering_mode(1), item) - - item = renderingMenu.Append(wx.ID_ANY, "Ball and line") - self.Bind(wx.EVT_MENU, lambda event: self.set_rendering_mode(4), item) - - item = renderingMenu.Append(wx.ID_ANY, "Ball and stick") - self.Bind(wx.EVT_MENU, lambda event: self.set_rendering_mode(3), item) - - popupMenu.AppendMenu(wx.ID_ANY, "Rendering", renderingMenu) - - popupMenu.AppendSeparator() - selectionBox = popupMenu.Append( - wx.ID_ANY, "Show/hide selection box", kind=wx.ITEM_CHECK - ) - saveSelection = popupMenu.Append(wx.ID_ANY, "Save selection") - clearSelection = popupMenu.Append(wx.ID_ANY, "Clear selection") - - popupMenu.AppendSeparator() - - parallelProjection = popupMenu.Append( - wx.ID_ANY, "Parallel projection", kind=wx.ITEM_CHECK - ) - - popupMenu.Bind(wx.EVT_MENU, self.on_toggle_selection_box, selectionBox) - popupMenu.Bind(wx.EVT_MENU, self.on_clear_selection, clearSelection) - popupMenu.Bind(wx.EVT_MENU, self.on_save_selection, saveSelection) - popupMenu.Bind(wx.EVT_MENU, self.parallel_proj_onoff, parallelProjection) - popupMenu.Check(parallelProjection.GetId(), self.camera.GetParallelProjection()) - - boundingBox = popupMenu.Append( - wx.ID_ANY, "Show/hide bounding box", kind=wx.ITEM_CHECK - ) - - popupMenu.Bind(wx.EVT_MENU, self.bbox_onoff, boundingBox) - popupMenu.Check(boundingBox.GetId(), self.display_bbox) - popupMenu.Check(selectionBox.GetId(), False) - - self.PopupMenu(popupMenu) - - # Give to vtkinteractor the event that Wx has stoled - self.iren.RightButtonReleaseEvent() - - @property - def animation_loop(self): - return self._animationLoop - - @property - def surface(self): - return self._surface - - @property - def iso(self): - return self._iso - - @property - def current_frame(self): - return self._currentFrame - - @property - def iren(self): - return self._iren - - @property - def max_laps(self): - return self._maxLaps - - @property - def n_frames(self): - return self._nFrames - - @property - def n_atoms(self): - return self._nAtoms - - @property - def selection_box(self): - return self.__selectionBox - - @property - def timer_interval(self): - return self._timerInterval - - @property - def trajectory(self): - return self._trajectory - - @property - def trajectory_loaded(self): - return self._trajectoryLoaded - - @property - def picked_atoms(self): - return self.__pickedAtoms - - @property - def selectedAtoms(self): - return self.__pickedAtoms - - def change_frame_rate(self, laps): - if not self._trajectoryLoaded: - return - - self._timerInterval = (self._maxLaps - laps) * 10 + 1 - if self._animationLoop: - self._iren.CreateRepeatingTimer(self._timerInterval) - - def create_timer(self): - self._iren.Initialize() - timerId = self._iren.CreateRepeatingTimer(self._timerInterval) - self._iren.Start() - - return timerId - - def set_frame(self, frame): - if not self._trajectoryLoaded: - return - - self.stop_animation() - - self._timerCounter = frame - - self.set_configuration(frame) - - def on_clear_labels(self, event=None): - pass - - def on_export(self, event=None): - pass - - def on_hide_labels(self, event=None): - pass - - def on_select_all(self, event=None): - pass - - def on_show_all_atoms(self, event=None): - pass - - def on_show_labels(self, event=None): - pass - - def on_show_unselected_atoms(self, event=None): - pass - - def on_show_selected_atoms(self, event=None): - pass - - def on_undo_exclude(self, event=None): - pass - - def on_undo_include(self, event=None): - pass - - def bbox_onoff(self, event=None): - if self.bbox is None: - return - if self.display_bbox: - self.bbox.VisibilityOff() - self.display_bbox = False - else: - self.bbox.VisibilityOn() - self.display_bbox = True - # rendering - self._iren.Render() - - def parallel_proj_onoff(self, event=None): - if self.camera.GetParallelProjection(): - self.camera.ParallelProjectionOff() - else: - self.camera.ParallelProjectionOn() - # rendering - self._iren.Render() - - def on_toggle_selection_box(self, event): - if self._trajectoryLoaded: - self.__selectionBox.on_off() - - def on_keyboard_input(self, obj=None, event=None): - if not self._trajectoryLoaded: - return - - key = self._iren.GetKeyCode() - - if key in ["1", "2", "3", "4", "5"]: - mode = int(self._iren.GetKeyCode()) - 1 - self.set_rendering_mode(mode) - - elif key == " ": - self.start_stop_animation() - - def on_timer(self, obj=None, event=None): - if self._iren._timer.IsRunning(): - return - - self.set_configuration(self._timerCounter) - self._timerCounter += 1 - - PUBLISHER.sendMessage("msg_timer", message=self) - - def set_rendering_mode(self, mode): - if not self._trajectoryLoaded: - return - - if self._rendmod != mode: - self._rendmod = mode - self.set_configuration(self._currentFrame) - - def goto_first_frame(self): - if not self._trajectoryLoaded: - return - - self.stop_animation() - - self._timerCounter = 0 - self.set_configuration(0) - - def goto_last_frame(self): - if not self._trajectoryLoaded: - return - - self.stop_animation() - last = self._nFrames - 1 - self._timerCounter = last - self.set_configuration(last) - - def show_selection_box(self, show): - if self._trajectoryLoaded: - self.__selectionBox.SetEnabled(show) - - def set_timer_interval(self, timerInterval): - self._timerInterval = timerInterval - - def on_pick(self, obj, event=None): - if not self._trajectoryLoaded: - return - - pos = obj.GetEventPosition() - self.picker.AddPickList(self.picking_domain) - self.picker.PickFromListOn() - self.picker.Pick(pos[0], pos[1], 0, self._renderer) - pid = self.picker.GetPointId() - if pid > 0: - idx = self.get_atom_index(pid) - self.pick_atoms([idx], new=(not obj.GetShiftKey())) - - def on_info_pick(self, obj, evt=None): - if not self._trajectoryLoaded: - return - - pos = obj.GetEventPosition() - - self.picker.AddPickList(self.picking_domain) - self.picker.PickFromListOn() - self.picker.Pick(pos[0], pos[1], 0, self._renderer) - pid = self.picker.GetPointId() - if pid > 0: - idx = self.get_atom_index(pid) - xyz = self._trajectory.chemical_system.configuration["coordinates"][idx, :] - info = "%s (id:%s) at %s" % ( - self._atoms[idx].full_name(), - self._atoms[idx].index, - "%.3f %.3f %.3f" % tuple(xyz), - ) - LOGGER(info, "info") - self.picker.InitializePickList() - - def pick_atoms(self, atomsList, new=False): - if new: - self.__pickedAtoms = set(atomsList) - else: - self.__pickedAtoms.symmetric_difference_update(atomsList) - - self.show_selection(list(self.__pickedAtoms)) - - PUBLISHER.sendMessage( - "msg_select_atoms_from_viewer", - message=(self.dataplugin, list(self.__pickedAtoms)), - ) - - def box_atoms(self, atomsList): - self.__pickedAtoms = set(atomsList) - - self.show_selection(list(self.__pickedAtoms)) - - def show_selected_atoms(self, atomsList): - self.show_selection(atomsList) - - def on_clear_selection(self, event=None): - if not self._trajectoryLoaded: - return - - self.atomsColours = np.copy(self._atomsColours) - - for i in range(self._nAtoms): - self._polydata.GetPointData().GetArray("scalars").SetTuple3( - i, self._atomsScales[i], self._atomsColours[i], i - ) - - self._polydata.Modified() - - self._iren.Render() - - def on_save_selection(self, event=None): - if not self._trajectoryLoaded: - return - - if not self.__pickedAtoms: - return - - d = wx.TextEntryDialog(self, "Enter selection name", "New selection") - - # If the new element dialog is closed by clicking on OK. - if d.ShowModal() == wx.ID_CANCEL: - return - - # Get rid of wxpython unicode string formatting - name = str(d.GetValue()) - - if not name: - return - - target = os.path.basename(self._trajectory.filename) - - if UD_STORE.has_definition(target, "atom_selection", name): - LOGGER( - "There is already a user-definition with that name.", - "error", - ["console"], - ) - return - - UD_STORE.set_definition( - target, "atom_selection", name, {"indexes": sorted(self.__pickedAtoms)} - ) - - UD_STORE.save() - - PUBLISHER.sendMessage("msg_set_ud", message=None) - - LOGGER("User definition %r successfully set." % name, "info", ["console"]) - - def show_selection(self, selection): - if not self._trajectoryLoaded: - return - - if not isinstance(selection, dict): - selection = {"selection": selection} - - self.atomsColours = np.copy(self._atomsColours) - - for k, v in list(selection.items()): - self.atomsColours[v] = RGB_COLOURS[k][0] - - for idx in range(self._nAtoms): - self._polydata.GetPointData().GetArray("scalars").SetTuple3( - idx, self._atomsScales[idx], self.atomsColours[idx], idx - ) - - self._polydata.Modified() - - self._iren.Render() - - def start_animation(self, event=None): - if self._trajectoryLoaded: - self._timerId = self.create_timer() - self._iren.TimerEventResetsTimerOn() - self._animationLoop = True - - def stop_animation(self, event=None): - if self._trajectoryLoaded: - self._iren.TimerEventResetsTimerOff() - self._animationLoop = False - - def start_stop_animation(self, event=None, check=True): - if not self._trajectoryLoaded: - return - - if self._first: - self._first = False - - if not self._animationLoop: - self.start_animation() - else: - self.stop_animation() - - if check: - PUBLISHER.sendMessage("msg_switch_viewers_state", message=self) - - PUBLISHER.sendMessage("msg_animate_trajectory", message=self) - - def msg_switch_viewers_state(self, message): - if not self._animationLoop: - return - - viewer = message - if viewer == self: - return - - self.start_stop_animation(check=False) - - def get_atom_index(self, pid): - if self._rendmod in [1, 3, 4]: - _, _, idx = ( - self.glyph.GetOutput().GetPointData().GetArray("scalars").GetTuple3(pid) - ) - elif self._rendmod in [2]: - _, _, idx = ( - self.tubes.GetOutput().GetPointData().GetArray("scalars").GetTuple3(pid) - ) - else: - _, _, idx = self._polydata.GetPointData().GetArray("scalars").GetTuple3(pid) - - return int(idx) - - def get_atom_props(self, pid): - if self._rendmod in [1, 3, 4]: - radius, color, idx = ( - self.glyph.GetOutput().GetPointData().GetArray("scalars").GetTuple3(pid) - ) - elif self._rendmod in [2]: - radius, color, idx = ( - self.tubes.GetOutput().GetPointData().GetArray("scalars").GetTuple3(pid) - ) - else: - radius, color, idx = ( - self._polydata.GetPointData().GetArray("scalars").GetTuple3(pid) - ) - - return radius, color, int(idx) - - def this_atom_is_selected(self, pid): - _, _, pid = self.get_atom_props(pid) - return self.atomsColours[pid] == RGB_COLOURS["selection"][0] - - def pick_atom(self, pid): - if self.this_atom_is_selected(pid): - self.unpick_atom(pid) - else: - radius, _, pid = self.get_atom_props(pid) - self.atomsColours[pid] = RGB_COLOURS["selection"][0] - self._polydata.GetPointData().GetArray("scalars").SetTuple3( - pid, radius, RGB_COLOURS["selection"][0], pid - ) - self._polydata.Modified() - - def unpick_atom(self, pid): - radius, _, pid = self.get_atom_props(pid) - self.atomsColours[pid] = self._atomsColours[pid] - self._polydata.GetPointData().GetArray("scalars").SetTuple3( - pid, radius, self._atomsColours[pid], pid - ) - self._polydata.Modified() - - def get_renwin(self): - return self._iren.GetRenderWindow() - - def build_real_bbox(self, molecule): - Xmin, Xmax, Ymin, Ymax, Zmin, Zmax = molecule.GetBounds() - bbox_points = vtk.vtkPoints() - - bbox_points.InsertNextPoint(Xmin, Ymin, Zmin) - bbox_points.InsertNextPoint(Xmax, Ymax, Zmax) - - BBox_poly = vtk.vtkPolyData() - BBox_poly.SetPoints(bbox_points) - - outline = vtk.vtkOutlineFilter() - if vtk.vtkVersion.GetVTKMajorVersion() < 6: - outline.SetInput(BBox_poly) - else: - outline.SetInputData(BBox_poly) - - outline_mapper = vtk.vtkPolyDataMapper() - outline_mapper.SetInputConnection(outline.GetOutputPort()) - - outline_actor = vtk.vtkLODActor() - outline_actor.SetMapper(outline_mapper) - outline_actor.GetProperty().SetColor(1, 0, 0) - outline_actor.GetProperty().SetLineWidth(3) - - self._renderer.AddActor(outline_actor) - self._iren.Render() - - def build_bbox(self, basis_vector): - cell = np.array(basis_vector).astype(np.float32) - Xmax, Ymax, Zmax = np.array( - [cell[0, 0], cell[1, 1], cell[2, 2]], dtype=np.float32 - ) - bbox_points = vtk.vtkPoints() - - self.cell_bounds_coords = np.array( - [-Xmax / 2.0, Xmax / 2.0, -Ymax / 2.0, Ymax / 2.0, -Zmax / 2.0, Zmax / 2.0] - ) - - bbox_points.InsertNextPoint(-Xmax / 2.0, -Ymax / 2.0, -Zmax / 2.0) - bbox_points.InsertNextPoint(Xmax / 2.0, Ymax / 2.0, Zmax / 2.0) - - BBox_poly = vtk.vtkPolyData() - BBox_poly.SetPoints(bbox_points) - - outline = vtk.vtkOutlineFilter() - if vtk.vtkVersion.GetVTKMajorVersion() < 6: - outline.SetInput(BBox_poly) - else: - outline.SetInputData(BBox_poly) - - outline_mapper = vtk.vtkPolyDataMapper() - outline_mapper.SetInputConnection(outline.GetOutputPort()) - - outline_actor = vtk.vtkLODActor() - outline_actor.SetMapper(outline_mapper) - outline_actor.GetProperty().SetColor(1, 1, 1) - outline_actor.GetProperty().SetLineWidth(3) - - return outline_actor - - def build_scene(self): - """ - build a vtkPolyData object for a given frame of the trajectory - """ - - rendmod = self._rendmod - - actorList = [] - lineActor = None - ballActor = None - tubeActor = None - - if rendmod in [0, 4]: - line_mapper = vtk.vtkPolyDataMapper() - if vtk.vtkVersion.GetVTKMajorVersion() < 6: - line_mapper.SetInput(self._polydata) - else: - line_mapper.SetInputData(self._polydata) - - line_mapper.SetLookupTable(self._lut) - line_mapper.ScalarVisibilityOn() - line_mapper.ColorByArrayComponent("scalars", 1) - lineActor = vtk.vtkLODActor() - lineActor.GetProperty().SetLineWidth(3) - lineActor.SetMapper(line_mapper) - actorList.append(lineActor) - - if rendmod in [1, 3, 4]: - sphere = vtk.vtkSphereSource() - sphere.SetCenter(0, 0, 0) - sphere.SetRadius(0.2) - sphere.SetThetaResolution(self._resolution) - sphere.SetPhiResolution(self._resolution) - glyph = vtk.vtkGlyph3D() - if vtk.vtkVersion.GetVTKMajorVersion() < 6: - glyph.SetInput(self._polydata) - else: - glyph.SetInputData(self._polydata) - - glyph.SetScaleModeToScaleByScalar() - glyph.SetColorModeToColorByScalar() - glyph.SetScaleFactor(1) - glyph.SetSourceConnection(sphere.GetOutputPort()) - glyph.SetIndexModeToScalar() - sphere_mapper = vtk.vtkPolyDataMapper() - sphere_mapper.SetLookupTable(self._lut) - sphere_mapper.SetScalarRange(self._polydata.GetScalarRange()) - sphere_mapper.SetInputConnection(glyph.GetOutputPort()) - sphere_mapper.ScalarVisibilityOn() - sphere_mapper.ColorByArrayComponent("scalars", 1) - ballActor = vtk.vtkLODActor() - ballActor.SetMapper(sphere_mapper) - ballActor.GetProperty().SetAmbient(0.2) - ballActor.GetProperty().SetDiffuse(0.5) - ballActor.GetProperty().SetSpecular(0.3) - ballActor.SetNumberOfCloudPoints(30000) - actorList.append(ballActor) - self.glyph = glyph - - if rendmod in [2, 3]: - tubes = vtk.vtkTubeFilter() - if vtk.vtkVersion.GetVTKMajorVersion() < 6: - tubes.SetInput(self._polydata) - else: - tubes.SetInputData(self._polydata) - - tubes.SetNumberOfSides(6) - if rendmod == 2: - tubes.CappingOn() - tubes.SetRadius(0.015) - else: - tubes.SetCapping(0) - tubes.SetRadius(0.01) - tubes.SetNumberOfSides(self._resolution) - tube_mapper = vtk.vtkPolyDataMapper() - tube_mapper.SetLookupTable(self._lut) - tube_mapper.SetInputConnection(tubes.GetOutputPort()) - tube_mapper.ScalarVisibilityOn() - tube_mapper.ColorByArrayComponent("scalars", 1) - tubeActor = vtk.vtkLODActor() - tubeActor.SetMapper(tube_mapper) - tubeActor.GetProperty().SetAmbient(0.2) - tubeActor.GetProperty().SetDiffuse(0.5) - tubeActor.GetProperty().SetSpecular(0.3) - actorList.append(tubeActor) - self.tubes = tubes - - self.picking_domain = [lineActor, ballActor, tubeActor, ballActor, ballActor][ - rendmod - ] - - basis_vector = self._trajectory[0].get("unit_cell", None) - if not basis_vector is None: - self.bbox = self.build_bbox(basis_vector) - if not self.display_bbox: - self.bbox.VisibilityOff() - actorList.append(self.bbox) - - assembly = vtk.vtkAssembly() - for actor in actorList: - assembly.AddPart(actor) - - return assembly - - def msg_clear_selection(self, message): - plugin = message - if not self.is_parent(plugin): - return - - self.on_clear_selection() - - def clear_universe(self): - if not hasattr(self, "_actors"): - return - - self._actors.VisibilityOff() - self._actors.ReleaseGraphicsResources(self.get_renwin()) - self._renderer.RemoveActor(self._actors) - - del self._actors - - def show_universe(self): - """ - Update the renderer - """ - # deleting old frame - self.clear_universe() - - # creating new polydata - self._actors = self.build_scene() - - # adding polydata to renderer - self._renderer.AddActor(self._actors) - - # rendering - self._iren.Render() - - def set_configuration(self, frame): - """ - Sets a new configuration. - - @param frame: the configuration number - @type frame: integer - """ - - self._currentFrame = frame % len(self._trajectory) - coords = self._trajectory[self._currentFrame]["coordinates"] - unitCell = self._trajectory.unit_cell(self._currentFrame) - - if unitCell is None: - conf = RealConfiguration(self.trajectory.chemical_system, coords) - else: - conf = PeriodicRealConfiguration( - self.trajectory.chemical_system, coords, unitCell - ) - - conf = conf.continuous_configuration() - - self._trajectory.chemical_system.configuration = conf - - coords = conf.variables["coordinates"] - - points = vtk.vtkPoints() - points.SetNumberOfPoints(self._nAtoms) - for i in range(self._nAtoms): - x, y, z = coords[i] - points.SetPoint(i, x, y, z) - - self._polydata.SetPoints(points) - - # Reset the view. - self.show_universe() - - -def ndarray_to_vtkpoints(array): - """Create vtkPoints from double array""" - points = vtk.vtkPoints() - points.SetNumberOfPoints(array.shape[0]) - vtkids = {} - for i in range(array.shape[0]): - point = array[i] - vtkid = points.SetPoint(i, point[0], point[1], point[2]) - vtkids[vtkid] = i - return points, vtkids - - -def ndarray_to_vtkarray(colors, radius, nbat): - # define the colours - color_scalars = vtk.vtkFloatArray() - color_scalars.SetNumberOfValues(colors.shape[0]) - for i, c in enumerate(colors): - color_scalars.SetValue(i, c) - color_scalars.SetName("colors") - - # some radii - radius_scalars = vtk.vtkFloatArray() - radius_scalars.SetNumberOfValues(radius.shape[0]) - for i, r in enumerate(radius): - radius_scalars.SetValue(i, r) - radius_scalars.SetName("radius") - - # the original index - index_scalars = vtk.vtkIntArray() - index_scalars.SetNumberOfValues(nbat) - for i in range(nbat): - index_scalars.SetValue(i, i) - index_scalars.SetName("index") - - scalars = vtk.vtkFloatArray() - scalars.SetNumberOfComponents(3) - scalars.SetNumberOfTuples(radius_scalars.GetNumberOfTuples()) - scalars.CopyComponent(0, radius_scalars, 0) - scalars.CopyComponent(1, color_scalars, 0) - scalars.CopyComponent(2, index_scalars, 0) - scalars.SetName("scalars") - return scalars - - -def ndarray_to_vtkcellarray(array): - bonds = vtk.vtkCellArray() - for data in array: - line = vtk.vtkLine() - line.GetPointIds().SetId(0, int(data[0])) - line.GetPointIds().SetId(1, int(data[1])) - bonds.InsertNextCell(line) - - return bonds - - -def get_trajectory_filename(): - filters = "HDF file (*.h5)|*.h5|All files (*.*)|*.*" - - dialog = wx.FileDialog( - None, message="Open Trajectory file...", wildcard=filters, style=wx.FD_OPEN - ) - - if dialog.ShowModal() == wx.ID_CANCEL: - return "" - - return dialog.GetPath() - - -def build_axes(): - axes = vtk.vtkAxesActor() # create axes actor - axes.SetTotalLength(10, 10, 10) - axes.SetNormalizedShaftLength(1, 1, 1) - axes.SetNormalizedTipLength(0, 0, 0) - axes.AxisLabelsOff() - axes.GetXAxisTipProperty().SetColor(0, 0, 1) - axes.GetXAxisShaftProperty().SetColor(0, 0, 1) - axes.GetYAxisTipProperty().SetColor(1, 1, 1) - axes.GetYAxisShaftProperty().SetColor(1, 1, 1) - axes.GetZAxisTipProperty().SetColor(1, 0, 0) - axes.GetZAxisShaftProperty().SetColor(1, 0, 0) - return axes - - -REGISTRY["molecular_viewer"] = MolecularViewerPlugin diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/MviViewerPlugin.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/MviViewerPlugin.py deleted file mode 100644 index f660959cd1..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/MviViewerPlugin.py +++ /dev/null @@ -1,373 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/MviViewerPlugin.py -# @brief Implements module/class/test MviViewerPlugin -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import numpy as np - -import vtk -from vtk.wx.wxVTKRenderWindowInteractor import wxVTKRenderWindowInteractor - -import wx -import wx.aui as aui - -from MDANSE import REGISTRY -from MDANSE.Core.Error import Error -from MDANSE.GUI.Plugins.ComponentPlugin import ComponentPlugin - -UC_COMP = "COMPONENT:" -MC_COMP = "MCDISPLAY: component" -MC_COMP_SHORT = "COMP: " -MC_LINE = "MCDISPLAY: multiline" -MC_CIRCLE = "MCDISPLAY: circle" -MC_ENTER = "ENTER:" -MC_LEAVE = "LEAVE:" -MC_STATE = "STATE:" -MC_SCATTER = "SCATTER:" -MC_ABSORB = "ABSORB:" -MC_MAGNIFY = "MCDISPLAY: magnify" -MC_START = "MCDISPLAY: start" -MC_END = "MCDISPLAY: end" -MC_STOP = "INSTRUMENT END:" - -POINTS_IN_CIRCLE = 128 - - -class MviViewerPluginError(Error): - pass - - -class MviViewerPlugin(ComponentPlugin): - """ - This class sets up the Mcstas virtual instrument viewer using vtk functionnalities. - """ - - label = "McStas Virtual Instrument Viewer" - - ancestor = ["mvi_trace"] - - category = ("Viewer",) - - def __init__(self, parent, *args, **kwargs): - ComponentPlugin.__init__(self, parent, *args, **kwargs) - - def build_panel(self): - self._iren = wxVTKRenderWindowInteractor(self, wx.ID_ANY, size=self.GetSize()) - self._iren.SetPosition((0, 0)) - - # define interaction style - self._iren.GetInteractorStyle().SetCurrentStyleToTrackballCamera() # change interaction style - - self._iren.Enable(1) - - # create renderer - self._renderer = vtk.vtkRenderer() - self._iren.GetRenderWindow().AddRenderer(self._renderer) - - # cam stuff - self.camera = vtk.vtkCamera() # create camera - self._renderer.SetActiveCamera(self.camera) # associate camera to renderer - - self._iren.AddObserver("LeftButtonPressEvent", self.emulate_focus) - - self._mgr.AddPane( - self._iren, - aui.AuiPaneInfo().Dock().Center().CaptionVisible(False).CloseButton(False), - ) - - self._mgr.Update() - - def plug(self): - self._parent._mgr.GetPane(self).Dock().Floatable(False).Center().CloseButton( - True - ) - - self._parent._mgr.Update() - - self.parse_trace(self.dataproxy._filename) - - def emulate_focus(self, obj, event): - self.SetFocusIgnoringChildren() - - def close(self): - pass - - def parse_trace(self, fname): - """ - Parse McStas trace output from stdin and write results to file objects csv_comps and csv_lines - """ - - color = 0 - - # map from component name to (position, rotation matrix) - comps = {} - - # active (position, rotation matrix) - comp = ( - np.array([0, 0, 0]), - np.array([1, 0, 0, 0, 1, 0, 0, 0, 1]).reshape(3, 3), - ) - - # previous neutron position - prev = None - skip = False - # we are drawing a neutron - active = False - xstate = [] - ystate = [] - zstate = [] - - circlePoints = vtk.vtkPoints() - circleLines = vtk.vtkCellArray() - circle_pid = 0 - - multiPoints = vtk.vtkPoints() - multiLines = vtk.vtkCellArray() - multi_pid = 0 - - neutronPoints = vtk.vtkPoints() - neutronLines = vtk.vtkCellArray() - neutron_pid = 0 - - f = open(fname, "r") - lines = f.readlines() - - for i, line in enumerate(lines): - if not line: - break - line = line.strip() - # register components - if line.startswith(UC_COMP): - # grab info line - info = lines[i + 1] - assert info[:4] == "POS:" - nums = [x.strip() for x in info[4:].split(",")] - # extract fields - name = line[len(UC_COMP) :].strip(' "\n') - pos = np.array([float(x) for x in nums[:3]]) - # read flat 3x3 rotation matrix - rot = np.array([float(x) for x in nums[3 : 3 + 9]]).reshape(3, 3) - comps[name] = (pos, rot) - - # switch perspective - elif line.startswith(MC_COMP): - color += 1 - comp = comps[line[len(MC_COMP) + 1 :]] - - elif line.startswith(MC_COMP_SHORT): - name = line[len(MC_COMP_SHORT) + 1 :].strip('"') - comp = comps[name] - skip = True - - # process multiline - elif line.startswith(MC_LINE): - points = self.parse_multiline(line[len(MC_LINE) :].strip("()")) - points.pop(0) - coords = self.rotate_points(points, comp) - beg = multi_pid - for p in coords: - multiPoints.InsertNextPoint(p) - multi_pid += 1 - end = multi_pid - for idx in range(beg, end - 1): - vline = vtk.vtkLine() - vline.GetPointIds().SetId(0, idx) - vline.GetPointIds().SetId(1, idx + 1) - multiLines.InsertNextCell(vline) - - # process circle - elif line.startswith(MC_CIRCLE): - xyz = "xyz" - items = line[len(MC_CIRCLE) :].strip("()").split(",") - # plane - pla = [xyz.find(a) for a in items[0].strip("''")] - # center and radius - pos = [float(x) for x in items[1:4]] - rad = float(items[4]) - coords = self.draw_circle(pla, pos, rad, comp) - beg = circle_pid - for p in coords: - circlePoints.InsertNextPoint(p) - circle_pid += 1 - end = circle_pid - for idx in range(beg, end - 1): - vline = vtk.vtkLine() - vline.GetPointIds().SetId(0, idx) - vline.GetPointIds().SetId(1, idx + 1) - circleLines.InsertNextCell(vline) - - # activate neutron when it enters - elif line.startswith(MC_ENTER): - prev = None - skip = True - active = True - color = 0 - xstate = [] - ystate = [] - zstate = [] - # deactivate neutron when it leaves - elif line.startswith(MC_LEAVE): - coords = np.column_stack([xstate, ystate, zstate]) - beg = neutron_pid - for p in coords: - neutronPoints.InsertNextPoint(p) - neutron_pid += 1 - end = neutron_pid - for idx in range(beg, end - 1): - vline = vtk.vtkLine() - vline.GetPointIds().SetId(0, idx) - vline.GetPointIds().SetId(1, idx + 1) - neutronLines.InsertNextCell(vline) - active = False - prev = None - - elif line.startswith(MC_ABSORB): - pass - - # register state and scatter - elif line.startswith(MC_STATE) or line.startswith(MC_SCATTER): - if not active: - continue - - if skip: - skip = False - continue - - xyz = [float(x) for x in line[line.find(":") + 1 :].split(",")[:3]] - xyz = self.rotate(xyz, comp) - if prev is not None: - xstate.append(xyz[0]) - ystate.append(xyz[1]) - zstate.append(xyz[2]) - prev = xyz - xstate.append(prev[0]) - ystate.append(prev[1]) - zstate.append(prev[2]) - - circlePolydata = vtk.vtkPolyData() - circlePolydata.SetPoints(circlePoints) - circlePolydata.SetLines(circleLines) - - circle_mapper = vtk.vtkPolyDataMapper() - circle_mapper.SetInput(circlePolydata) - circle_actor = vtk.vtkActor() - circle_actor.SetMapper(circle_mapper) - circle_actor.GetProperty().SetAmbient(0.2) - circle_actor.GetProperty().SetDiffuse(0.5) - circle_actor.GetProperty().SetSpecular(0.3) - circle_actor.GetProperty().SetColor(0, 0.7, 0.7) - circle_actor.GetProperty().SetLineWidth(3) - - multiPolydata = vtk.vtkPolyData() - multiPolydata.SetPoints(multiPoints) - multiPolydata.SetLines(multiLines) - - multi_mapper = vtk.vtkPolyDataMapper() - multi_mapper.SetInput(multiPolydata) - multi_actor = vtk.vtkActor() - multi_actor.SetMapper(multi_mapper) - multi_actor.GetProperty().SetAmbient(0.2) - multi_actor.GetProperty().SetDiffuse(0.5) - multi_actor.GetProperty().SetSpecular(0.3) - multi_actor.GetProperty().SetColor(1, 0, 0.5) - multi_actor.GetProperty().SetLineWidth(3) - - neutronPolydata = vtk.vtkPolyData() - neutronPolydata.SetPoints(neutronPoints) - neutronPolydata.SetLines(neutronLines) - - neutron_mapper = vtk.vtkPolyDataMapper() - neutron_mapper.SetInput(neutronPolydata) - neutron_actor = vtk.vtkActor() - neutron_actor.SetMapper(neutron_mapper) - neutron_actor.GetProperty().SetAmbient(0.2) - neutron_actor.GetProperty().SetDiffuse(0.5) - neutron_actor.GetProperty().SetSpecular(0.3) - neutron_actor.GetProperty().SetColor(1, 1, 1) - neutron_actor.GetProperty().SetLineWidth(2) - - self._renderer.AddActor(circle_actor) - self._renderer.AddActor(multi_actor) - self._renderer.AddActor(neutron_actor) - self._renderer.SetBackground(0, 0, 0) - - self._iren.Render() - - def parse_multiline(self, line): - """ - Parse a multiline with size as first elements and n points as rest - """ - - elems = [float(x) for x in line.split(",")] - count = int(elems.pop(0)) - points = [] - while count > 0: - points.append(elems[0:3]) - elems = elems[3:] - count -= 1 - - points.append(points[0]) - return points - - def rotate(self, point, origin, rotm): - """ - Rotate and move v according to origin and rotation matrix - """ - return np.dot(point, rotm) + origin - - def rotate_points(self, points, origin, rotm): - """ - Rotate and move v according to origin and rotation matrix - """ - count = 0 - rpoints = [] - x = [] - y = [] - z = [] - while count < len(points): - p = points[count] - rpoints.append(self.rotate(p, (origin, rotm))) - p = rpoints[count] - x.append(p[0]) - y.append(p[1]) - z.append(p[2]) - count += 1 - x.append(x[0]) - y.append(y[0]) - z.append(z[0]) - return np.column_stack([x, y, z]) - - def draw_circle(self, plane, pos, radius, comp): - """ - Draw a circle in plane, at pos and with r radius, rotated by comp - """ - x = [] - y = [] - z = [] - for i in range(0, POINTS_IN_CIRCLE): - walk = 2 * np.pi * i / POINTS_IN_CIRCLE - xyz = np.array(pos) - xyz[plane[0]] += np.cos(walk) * radius - xyz[plane[1]] += np.sin(walk) * radius - # rotate - xyz = self.rotate(xyz, comp) - x.append(xyz[0]) - y.append(xyz[1]) - z.append(xyz[2]) - x.append(x[0]) - y.append(y[0]) - z.append(z[0]) - return np.column_stack([x, y, z]) - - -REGISTRY["mvi_viewer"] = MviViewerPlugin diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/PartialChargesPlugin.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/PartialChargesPlugin.py deleted file mode 100644 index 194a2b4332..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/PartialChargesPlugin.py +++ /dev/null @@ -1,129 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/PartialChargesPlugin.py -# @brief Implements module/class/test PartialChargesPlugin -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import collections -import os - -import wx -import wx.grid as wxgrid - -from MDANSE import LOGGER, REGISTRY -from MDANSE.Chemistry.ChemicalEntity import ( - Atom, - AtomCluster, - Molecule, - NucleotideChain, - PeptideChain, - Protein, -) -from MDANSE.GUI.Plugins.UserDefinitionPlugin import UserDefinitionPlugin - - -class PartialChargesPlugin(UserDefinitionPlugin): - label = "Partial charges" - - ancestor = ["hdf_trajectory"] - - def __init__(self, parent, *args, **kwargs): - self._parent = parent - - self._selectedAtoms = [] - - UserDefinitionPlugin.__init__(self, parent, size=(600, 600)) - - 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) - - def plug(self): - self.parent.mgr.GetPane(self).Float().Dockable(False).CloseButton(True) - - self.parent.mgr.Update() - - self.set_trajectory(self.dataproxy.data) - - self._mgr.Update() - - def set_trajectory(self, trajectory): - self._trajectory = trajectory - - self._target = os.path.basename(self._trajectory.filename) - - self._contents = collections.OrderedDict() - for at in self._trajectory.chemical_system.atom_list(): - self._contents[at.full_name()] = 0.0 - - self._grid.CreateGrid(0, 2) - - self._grid.SetRowLabelSize(1) - - self._grid.SetColFormatNumber(1) - - roAttr = wxgrid.GridCellAttr() - roAttr.SetReadOnly(True) - roAttr.SetBackgroundColour(wx.Colour(220, 220, 220)) - self._grid.SetColAttr(0, roAttr) - - floatAttr = wxgrid.GridCellAttr() - floatAttr.SetRenderer(wxgrid.GridCellFloatRenderer()) - floatAttr.SetEditor(wxgrid.GridCellFloatEditor()) - self._grid.SetColAttr(1, floatAttr) - - self._grid.SetColLabelValue(0, "name") - self._grid.SetColLabelValue(1, "charge") - - for i, (k, v) in enumerate(self._contents.items()): - self._grid.AppendRows(1) - self._grid.SetCellValue(i, 0, k) - self._grid.SetCellValue(i, 1, str(v)) - - self._grid.Bind(wx.EVT_SIZE, self.OnSize) - - def OnSize(self, event): - width, _ = self._grid.GetClientSizeTuple() - w = 4 * width / 5 - if w > 0: - self._grid.SetColSize(0, w) - self._grid.SetColSize(1, width - w - 5) - - self._grid.ForceRefresh() - - def validate(self): - charges = {} - for i in range(self._grid.GetNumberRows()): - name = tuple(self._grid.GetCellValue(i, 0).split(".")) - charge = self._grid.GetCellValue(i, 1) - - val = self._contents.get(name, None) - if val is None: - continue - for idx in val[1]: - charges[idx] = float(charge) - - if not charges: - LOGGER("No partial charges defined.", "error", ["dialog"]) - return None - - return {"charges": charges} - - -REGISTRY["partial_charges"] = PartialChargesPlugin diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/Plotter1D.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/Plotter1D.py deleted file mode 100644 index 1215ae9c3a..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/Plotter1D.py +++ /dev/null @@ -1,596 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/Plotter1D.py -# @brief Implements module/class/test Plotter1D -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -from distutils.version import LooseVersion -import os - -import numpy as np - -import matplotlib -from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg, NavigationToolbar2WxAgg -from matplotlib.figure import Figure -from matplotlib.colors import LogNorm, Normalize - -import wx - -from MDANSE.Core.Error import Error -from MDANSE.Framework.Units import UnitError, measure - -from MDANSE.GUI.Plugins.PlotterSettings import ( - LinesSettingsDialog, - GeneralSettingsDialog, - AxesSettingsDialog, -) -from MDANSE.GUI.Plugins.PlotterTicker import ScaledFormatter, ScaledLocator - -NORMALIZER = {"log": LogNorm(), "auto": Normalize()} - - -class Plotter1DError(Error): - pass - - -class Plotter1D(wx.Panel): - type = "line" - - def __init__(self, parent, data=None): - wx.Panel.__init__(self, parent, wx.ID_ANY) - - self.setting = None - - ### Initialize variables ### - self.parent = parent - self.figure = Figure(figsize=(5, 4), dpi=None) - - if LooseVersion(matplotlib.__version__) < LooseVersion("2.0.0"): - self.axes = self.figure.add_axes( - (10, 10, 10, 10), frameon=True, axis_bgcolor="b" - ) - else: - self.axes = self.figure.add_axes( - (10, 10, 10, 10), frameon=True, facecolor="b" - ) - self.canvas = FigureCanvasWxAgg(self, wx.ID_ANY, self.figure) - self.toolbar = NavigationToolbar2WxAgg(self.canvas) - self.plots = {} - self.selectedLine = None - - self.annotation = wx.StaticText( - self, label="x : , y : ", style=wx.ALIGN_CENTER_VERTICAL - ) - - ### Initialize figure parameters ### - self.title = "" - self.titleStyle = 0 - self.titleWeight = 0 - self.titleWidth = 4 # large - - self.xlabel = "" - self.xlabelStyle = 0 - self.xlabelWeight = 0 - self.xlabelWidth = 3 # medium - - self.ylabel = "" - self.ylabelStyle = 0 - self.ylabelWeight = 0 - self.ylabelWidth = 3 # medium - - self.gridStyle = "None" - self.gridWidth = 1 - self.gridColor = (1, 0, 0) - - self.Xscale = "linear" - self.Yscale = "linear" - - self.xMinorTicks = False - self.yMinorTicks = False - - self.Xposition = "none" - self.Yposition = "none" - - self.Xlabel = "" - self.Ylabel = "" - - self.Xaxis_label = "" - self.Yaxis_label = "" - - self.Xunit = None - self.Yunit = None - - self.Xinit_unit = None - self.Yinit_unit = None - - self.Xaxis = np.array([]) - self.Yaxis = np.array([]) - - self.Xticks = [] - self.Yticks = [] - - self.Xmax = 0 - self.Ymax = 0 - self.Xmin = 0 - self.Ymin = 0 - - self.offset = 0.0 - self.verticalCut = None - - self.show_legend = True - self.legend_location = "best" - self.legend_frameon = True - self.legend_shadow = True - self.legend_fancybox = False - - # add sliders - self.offset_label = wx.StaticText( - self, label="Offset Value", style=wx.ALIGN_CENTER_VERTICAL - ) - self.yAxisSliderOffset = wx.Slider( - self, wx.ID_ANY, size=(60, 27), style=wx.SL_HORIZONTAL - ) - self.offset_multiplier_label = wx.StaticText( - self, label="Modulation", style=wx.ALIGN_CENTER_VERTICAL - ) - self.yAxisOffset = wx.TextCtrl( - self, wx.ID_ANY, size=(60, 27), style=wx.TE_PROCESS_ENTER - ) - self.yAxisOffset.SetValue("0.0") - self.autoFitAxesButton = wx.Button(self, label="Fit axes range", size=(120, 27)) - - hsizer = wx.BoxSizer() - hsizer.Add(self.toolbar, 0, flag=wx.ALL | wx.EXPAND) - hsizer.AddSpacer(25) - hsizer.Add(self.annotation, 0, flag=wx.ALIGN_CENTER_VERTICAL) - - hsizer2 = wx.BoxSizer() - hsizer2.AddSpacer(5) - hsizer2.Add(self.offset_label, 0, flag=wx.ALIGN_CENTER_VERTICAL) - hsizer2.AddSpacer(5) - hsizer2.Add(self.yAxisOffset, 0, flag=wx.ALIGN_CENTER_VERTICAL) - hsizer2.AddSpacer(5) - hsizer2.Add(self.offset_multiplier_label, 0, flag=wx.ALIGN_CENTER_VERTICAL) - hsizer2.AddSpacer(5) - hsizer2.Add( - self.yAxisSliderOffset, - 1, - flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, - ) - hsizer2.AddSpacer(5) - hsizer2.Add(self.autoFitAxesButton, 0, flag=wx.ALIGN_CENTER_VERTICAL) - - ### sizer ### - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.sizer.Add(self.canvas, 1, flag=wx.EXPAND) - self.sizer.Add(hsizer, 0, flag=wx.EXPAND) - self.sizer.Add(hsizer2, 0, flag=wx.EXPAND) - self.SetSizer(self.sizer) - - ### set bindings ### - self.Bind(wx.EVT_CLOSE, self.on_close_figure) - self.Bind(wx.EVT_TEXT_ENTER, self.on_offset, id=self.yAxisOffset.GetId()) - self.Bind(wx.EVT_SCROLL, self.on_offset, id=self.yAxisSliderOffset.GetId()) - self.Bind(wx.EVT_BUTTON, self.on_auto_fit, id=self.autoFitAxesButton.GetId()) - # self.Bind(wx.EVT_CHECKBOX, self.slice, id = self.slice_checkbox.GetId()) - - self.binds_mpl_events() - - #### sizer automatically fitting window size #### - self.toolbar.Realize() - self.SetSizeHints(600, 500, 1000, 1000) # SetSizeHints(minW, minH, maxW, maxH) - self.sizer.Fit(self) - self.Show(True) - - @property - def dataproxy(self): - return self.parent.dataproxy - - @property - def fmt_Xunit(self): - if not self.Xunit: - return "" - else: - return " (" + self.Xunit + ")" - - @property - def fmt_Yunit(self): - if not self.Yunit: - return "" - else: - return " (" + self.Yunit + ")" - - def binds_mpl_events(self): - self.menu_event_id = self.canvas.mpl_connect( - "button_press_event", self.on_click - ) - self.pick_event_id = self.canvas.mpl_connect("pick_event", self.on_pick_line) - self.key_event_id = self.canvas.mpl_connect("key_press_event", self.on_key) - self.on_motion_id = self.canvas.mpl_connect( - "motion_notify_event", self.on_motion - ) - - def on_click(self, event=None): - if event.button != 3: - return - - popupMenu = wx.Menu() - - general = popupMenu.Append(wx.ID_ANY, "General settings") - popupMenu.Bind(wx.EVT_MENU, self.general_setting_dialog, general) - - axes = popupMenu.Append(wx.ID_ANY, "Axes settings") - popupMenu.Bind(wx.EVT_MENU, self.axes_setting_dialog, axes) - - lines = popupMenu.Append(wx.ID_ANY, "Lines settings") - popupMenu.Bind(wx.EVT_MENU, self.lines_setting_dialog, lines) - - popupMenu.AppendSeparator() - - clear = popupMenu.Append(wx.ID_ANY, "Clear") - popupMenu.Bind(wx.EVT_MENU, self.clear, clear) - - popupMenu.AppendSeparator() - - export = popupMenu.Append(wx.ID_ANY, "Export data") - popupMenu.Bind(wx.EVT_MENU, self.export_data, export) - - self.canvas.ReleaseMouse() - wx.CallAfter(self.PopupMenu, popupMenu) - - def on_motion(self, event): - if event.inaxes: - x = event.xdata - y = event.ydata - self.annotation.SetLabel("x : %g, y : %g" % (x, y)) - else: - self.annotation.SetLabel("") - - def clear(self, event=None): - d = wx.MessageDialog( - None, - "Do you really want clean the plot window ?", - "Question", - wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, - ) - if d.ShowModal() == wx.ID_YES: - pass - else: - return - self.plots = {} - self.figure.gca().clear() - self.figure.canvas.draw() - - def on_offset(self, event=None): - try: - offsetValue = float(self.yAxisOffset.GetValue()) - except: - offsetValue = 0.0 - offsetPercent = float(self.yAxisSliderOffset.GetValue()) / 100.0 - AddFactor = float(offsetValue * offsetPercent) - float(self.offset) - self.offset = float(offsetValue * offsetPercent) - - self.add_offset(AddFactor) - - def export_data(self, event=None): - first = True - - for v in list(self.plots.values()): - line, label, varname = v - if first: - try: - axis = self.dataproxy[varname]["axis"][0] - data = [self.dataproxy[axis]["data"] * self.Xunit_conversion_factor] - labels = ["%s (%s)" % (axis, self.Xunit)] - except: - data = [np.arange(self.dataproxy[varname]["data"].shape[0])] - labels = ["default_axis (au)"] - first = False - - try: - line.get_xydata() - data.append(line.get_ydata() * self.Yunit_conversion_factor) - labels.append("%s (%s)" % (label, self.Yunit)) - except: - raise Plotter1DError( - "encounter issue for variable %r while exporting data" % varname - ) - header = "# " - if labels: - for label in labels: - header += "%s, " % label - header = header[:-2] + os.linesep - output_fname = self.get_output_filename() - if output_fname: - with open(output_fname, "w") as f: - f.write(header) - np.savetxt(f, np.column_stack(data), fmt="%12.4e", delimiter=" ") - f.close() - - def get_output_filename(self): - path = "" - dlg = wx.FileDialog(self, "Save As", "", "", "All Files|*.*", wx.SAVE) - if dlg.ShowModal() == wx.ID_OK: - path = dlg.GetPath() - dlg.Destroy() - return path - - def add_offset(self, offset): - lines = self.figure.gca().lines - # remove vertical line if existing - if self.verticalCut is not None: - lines.remove(self.verticalCut) - self.verticalCut = None - - for idx in range(len(lines)): - line = lines[idx] - - y = line.get_ydata() - line.set_ydata((idx + 1) * offset + y) - - # set activeFigure to this figure - self.figure.canvas.draw() - - def on_auto_fit(self, event=None): - lines = self.figure.gca().lines - if not lines: - return - xMin = 1.0e10 - xMax = 0 - yMin = 1.0e10 - yMax = 0 - for line in lines: - xMin = min(xMin, min(line.get_xdata())) - xMax = max(xMax, max(line.get_xdata())) - yMin = min(yMin, min(line.get_ydata())) - yMax = max(yMax, max(line.get_ydata())) - - self.Xmin = xMin - self.Xmax = xMax - self.Ymin = yMin - self.Ymax = yMax + 0.05 * (yMax - yMin) - - self.figure.gca().axis([self.Xmin, self.Xmax, self.Ymin, self.Ymax]) - self.figure.canvas.draw() - - def on_key(self, event=None): - if event.key == "delete": - if self.selectedLine is None: - return - - if self.delete_line(self.selectedLine): - self.selectedLine = None - self.canvas.draw() - - def delete_line(self, line): - self.add_offset(-self.offset) - for k, v in list(self.plots.items()): - if v[0] is line: - d = wx.MessageDialog( - None, - "Do you really want delete this line ?", - "Question", - wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, - ) - if d.ShowModal() == wx.ID_NO: - return False - self.plots.pop(k) - - if not list(self.plots.values()): - self.figure.gca().set_prop_cycle(None) - - # remove line - line.remove() - self.add_offset(self.offset) - self.update_legend() - self.canvas.draw() - - return True - - # self.add_offset(-self.offset) - - # for k, v in self.plots.items(): - # if v[0] is line: - # self.plots.pop(k) - - # line.remove() - # self.add_offset(self.offset) - # self.canvas.draw() - - def on_close_figure(self, event=None): - # remove any selection made in any figure - if self.parent.selectedPlot is not None: - self.parent.selectedPlot = None - - # destroy window - self.Destroy() - self = None - - def scale_xAxis(self): - scaleStr = self.Xscale - if scaleStr == "linear": - self.figure.gca().set_xscale("linear") - elif scaleStr == "symlog": - self.figure.gca().set_xscale("symlog") - elif scaleStr == "ln": - self.figure.gca().set_xscale("log", basex=np.exp(1)) - elif scaleStr == "log 10": - self.figure.gca().set_xscale("log", basex=10) - elif scaleStr == "log 2": - self.figure.gca().set_xscale("log", basex=2) - self.on_auto_fit() - self.figure.canvas.draw() - - def scale_yAxis(self): - scaleStr = self.Yscale - if scaleStr == "linear": - self.figure.gca().set_yscale("linear") - elif scaleStr == "symlog": - self.figure.gca().set_yscale("symlog") - elif scaleStr == "ln": - self.figure.gca().set_yscale("log", basey=np.exp(1)) - elif scaleStr == "log 10": - self.figure.gca().set_yscale("log", basey=10) - elif scaleStr == "log 2": - self.figure.gca().set_yscale("log", basey=2) - self.on_auto_fit() - self.figure.canvas.draw() - - def on_pick_line(self, event=None): - # set alpha of previous selection to 1 - if self.selectedLine is not None: - self.selectedLine.set_alpha(1.0) - self.selectedLine.figure.canvas.draw() - # unselect previous selection - if event.artist == self.selectedLine: - self.selectedLine = None - return - # set new selection and alpha - self.selectedLine = event.artist - self.selectedLine.set_alpha(0.4) - self.selectedLine.figure.canvas.draw() - - def update_legend(self): - if not list(self.plots.values()): - self.figure.gca().legend().remove() - return - - if not self.show_legend: - return - - legend = [[], []] - for v in list(self.plots.values()): - legend[0].append(v[0]) - legend[1].append(v[1]) - self.figure.gca().legend( - tuple(legend[0]), - tuple(legend[1]), - loc=self.legend_location, - frameon=self.legend_frameon, - shadow=self.legend_shadow, - fancybox=self.legend_fancybox, - ) - - def plot(self, data, varname): - if data is None: - return - - try: - [float(d) for d in data] - except ValueError: - raise Plotter1DError( - "Data containing non-numeric values cannot be plotted." - ) - - self.set_axis_property(varname, data) - self.subplot = self.figure.add_subplot(111) - name = self.unique(varname, self.plots) - self.plots[name] = [ - self.subplot.plot(self.Xaxis, data, picker=3)[0], - name, - varname, - ] - self.set_ticks() - self.Xlabel = self.Xaxis_label - self.Ylabel = self.Yaxis_label - self.figure.gca().set_xlabel(self.Xlabel + self.fmt_Xunit) - self.figure.gca().set_ylabel(self.Ylabel + self.fmt_Yunit) - self.on_auto_fit() - self.update_legend() - self.canvas.draw() - - def set_axis_property(self, varname, data): - oldXunit = self.Xinit_unit - oldYunit = self.Yinit_unit - self.Yaxis_label = varname - self.Yaxis = self.dataproxy[varname]["data"] - try: - self.Xaxis_label = self.dataproxy[varname]["axis"][0] - self.Xunit = self.Xinit_unit = self.dataproxy[self.Xaxis_label]["units"] - self.Xaxis = self.dataproxy[self.Xaxis_label]["data"] - except: - self.Xunit = self.Xinit_unit = "au" - self.Xaxis = np.arange(data.shape[0]) - try: - self.Yunit = self.Yinit_unit = self.dataproxy[varname]["units"] - except: - self.Yunit = self.Yinit_unit = "au" - - if oldXunit is not None: - if oldXunit != self.Xinit_unit: - raise Plotter1DError( - "the x axis unit (%s) of data-set %r is inconsistent with the unit (%s) of the precedent data " - "plotted " % (self.Xinit_unit, varname, oldXunit) - ) - if oldYunit is not None: - if oldYunit != self.Yinit_unit: - raise Plotter1DError( - "the y axis unit (%s) of data-set %r is inconsistent with the unit (%s) of the precedent data " - "plotted " % (self.Yinit_unit, varname, oldYunit) - ) - - def compute_conversion_factor(self): - try: - m = measure(1.0, self.Xinit_unit, equivalent=True) - self.Xunit_conversion_factor = m.toval(self.Xunit) - except UnitError: - self.Xunit_conversion_factor = 1.0 - - try: - m = measure(1.0, self.Yinit_unit, equivalent=True) - self.Yunit_conversion_factor = m.toval(self.Yunit) - except UnitError: - self.Yunit_conversion_factor = 1.0 - - def set_ticks(self): - self.compute_conversion_factor() - - self.figure.gca().xaxis.set_major_locator( - ScaledLocator(dx=self.Xunit_conversion_factor) - ) - self.figure.gca().xaxis.set_major_formatter( - ScaledFormatter(dx=self.Xunit_conversion_factor) - ) - - self.figure.gca().yaxis.set_major_locator( - ScaledLocator(dx=self.Yunit_conversion_factor) - ) - self.figure.gca().yaxis.set_major_formatter( - ScaledFormatter(dx=self.Yunit_conversion_factor) - ) - - @staticmethod - def unique(key, dic): - skey = key - i = 0 - while key in dic: - key = skey + "_%d" % i - i += 1 - return key - - def general_setting_dialog(self, event=None): - d = GeneralSettingsDialog(self) - d.SetFocus() - d.ShowModal() - d.Destroy() - - def axes_setting_dialog(self, event=None): - d = AxesSettingsDialog(self) - d.SetFocus() - d.ShowModal() - d.Destroy() - - def lines_setting_dialog(self, event=None): - d = LinesSettingsDialog(self) - d.SetFocus() - d.ShowModal() - d.Destroy() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/Plotter2D.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/Plotter2D.py deleted file mode 100644 index 4e0f50c67f..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/Plotter2D.py +++ /dev/null @@ -1,696 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/Plotter2D.py -# @brief Implements module/class/test Plotter2D -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import collections -from distutils.version import LooseVersion - -import numpy as np - -import matplotlib -from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg, NavigationToolbar2WxAgg -from matplotlib.figure import Figure -from matplotlib.colors import LogNorm, Normalize - -import wx - -from MDANSE.Core.Error import Error -from MDANSE.Framework.Units import UnitError, measure - -from MDANSE.GUI.Plugins.PlotterSettings import ImageSettingsDialog -from MDANSE.GUI.Plugins.PlotterTicker import ScaledFormatter, ScaledLocator - -NORMALIZER = {"log": LogNorm(), "auto": Normalize()} - - -class CrossSlicer(object): - def __init__( - self, parent, canvas, dialog, hplot, vplot, fig, color_index, hlegend, vlegend - ): - self.related_plot = parent - self.canvas = canvas - self.dialog = dialog - self.hplot = hplot - self.vplot = vplot - self.fig = fig - self.color_index = color_index - self.hlegend = hlegend - self.vlegend = vlegend - - -class Plotter2DError(Error): - pass - - -class Plotter2D(wx.Panel): - type = "image" - - def __init__(self, parent, data=None): - wx.Panel.__init__(self, parent, wx.ID_ANY) - - self.setting = None - - ### Initialize variables ### - self.parent = parent - self.figure = Figure(figsize=(5, 4), dpi=None) - if LooseVersion(matplotlib.__version__) < LooseVersion("2.0.0"): - self.axes = self.figure.add_axes( - (10, 10, 10, 10), frameon=True, axis_bgcolor="b" - ) - else: - self.axes = self.figure.add_axes( - (10, 10, 10, 10), frameon=True, facecolor="b" - ) - self.canvas = FigureCanvasWxAgg(self, wx.ID_ANY, self.figure) - self.toolbar = NavigationToolbar2WxAgg(self.canvas) - self.ax = None - self.color_bar = None - self.slice_checkbox = wx.CheckBox(self, id=wx.ID_ANY, label="Slicing mode") - - self.annotation = wx.StaticText( - self, label="x : , y : , data[x,y] :", style=wx.ALIGN_CENTER_VERTICAL - ) - - hsizer = wx.BoxSizer() - hsizer.Add(self.toolbar, 0, flag=wx.ALL | wx.EXPAND) - hsizer.Add( - self.slice_checkbox, 0, flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL - ) - - ### sizer ### - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.sizer.Add(self.canvas, 1, flag=wx.EXPAND) - self.sizer.Add(hsizer, 0, flag=wx.EXPAND) - self.SetSizer(self.sizer) - - ### set bindings ### - self.Bind(wx.EVT_CHECKBOX, self.slice, id=self.slice_checkbox.GetId()) - - # Slice attributes - self.unique = False - self.slice_event_id = None - - self.slice_coords = [] - self.slice_widget = [] - - self.cross_slice_canvas = None - self.cross_slice_dialog = None - self.h_cross_slice_plot = None - self.v_cross_slice_plot = None - self.cross_slice_fig = None - self.cross_slice_color_index = -1 - self.h_cross_slice_legend = [] - self.v_cross_slice_legend = [] - self.color_list = collections.OrderedDict( - [ - ["blue", "b"], - ["green", "g"], - ["red", "r"], - ["cyan", "c"], - ["magenta", "m"], - ["yellow", "y"], - ["black", "k"], - ] - ) - - self.Xmin = 0 - self.Ymin = 0 - self.Xmax = 0 - self.Ymax = 0 - - self.Xunit = None - self.Yunit = None - - self.Xinit_unit = None - self.Yinit_unit = None - - self.Xaxis = [] - self.Yaxis = [] - - self.Xaxis_label = "" - self.Yaxis_label = "" - - self.Xticks = [] - self.Yticks = [] - - self.Xlabel = "" - self.Ylabel = "" - - self.aspect = "equal" - self.interpolation = "nearest" - self.normType = "none" - - hsizer = wx.BoxSizer() - hsizer.Add(self.toolbar, 0, flag=wx.ALL | wx.EXPAND) - hsizer.Add( - self.slice_checkbox, 0, flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL - ) - hsizer.AddSpacer(25) - hsizer.Add(self.annotation, 0, flag=wx.ALIGN_CENTER_VERTICAL) - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.sizer.Add(self.canvas, 1, flag=wx.EXPAND) - self.sizer.Add(hsizer, 0, flag=wx.EXPAND) - self.SetSizer(self.sizer) - - ### set bindings ### - self.Bind(wx.EVT_CHECKBOX, self.slice, id=self.slice_checkbox.GetId()) - self.menu_event_id = self.canvas.mpl_connect( - "button_press_event", self.on_click - ) - self.on_motion_id = self.canvas.mpl_connect( - "motion_notify_event", self.on_motion - ) - #### sizer automatically fitting window size #### - self.toolbar.Realize() - self.SetSizeHints(600, 500, 1000, 1000) # SetSizeHints(minW, minH, maxW, maxH) - self.sizer.Fit(self) - self.Show(True) - - @property - def dataproxy(self): - return self.parent.dataproxy - - @property - def fmt_Xunit(self): - if not self.Xunit: - return "" - else: - return " (" + self.Xunit + ")" - - @property - def fmt_Yunit(self): - if not self.Yunit: - return "" - else: - return " (" + self.Yunit + ")" - - def on_click(self, event=None): - if event.button != 3: - return - - popupMenu = wx.Menu() - - settings = popupMenu.Append(wx.ID_ANY, "Settings") - popupMenu.Bind(wx.EVT_MENU, self.image_setting_dialog, settings) - - popupMenu.AppendSeparator() - - export = popupMenu.Append(wx.ID_ANY, "Export data") - popupMenu.Bind(wx.EVT_MENU, self.export_data, export) - - self.canvas.ReleaseMouse() - wx.CallAfter(self.PopupMenu, popupMenu) - - def on_motion(self, event): - if event.inaxes: - x = event.xdata - y = event.ydata - if self.Xmin <= x and x <= self.Xmax and self.Ymin <= y and y <= self.Ymax: - try: - dx = (self.Xmax - self.Xmin) / float(self.data.shape[1]) - dy = (self.Ymax - self.Ymin) / float(self.data.shape[0]) - X = np.floor((x - self.Xmin) / dx) - Y = np.floor((y - self.Ymin) / dy) - i = self.data[Y, X] - self.annotation.SetLabel( - "x : %g (%g), y : %g (%g), data[x,y] : %g" - % ( - X, - x * self.Xunit_conversion_factor, - Y, - y * self.Yunit_conversion_factor, - i, - ) - ) - except: - self.annotation.SetLabel("") # rarely useful except outside figure - - else: - self.annotation.SetLabel("") - - def export_data(self, event=None): - header = ( - "# Data : %s\n# First row : %s (%s)\n# First column : %s (%s)\n" - % (self.varname, self.Xlabel, self.Xunit, self.Ylabel, self.Yunit) - ) - output_fname = self.get_output_filename() - - x = np.concatenate(([0], self.Xaxis)) * self.Xunit_conversion_factor - data = np.vstack( - ( - x, - np.hstack( - ( - self.Yaxis[:, np.newaxis] * self.Yunit_conversion_factor, - self.data, - ) - ), - ) - ) - if output_fname: - with open(output_fname, "w") as f: - f.write(header) - np.savetxt(f, data, fmt="%12.4e", delimiter=" ") - f.close() - - def get_output_filename(self): - path = "" - dlg = wx.FileDialog(self, "Save As", "", "", "All Files|*.*", wx.SAVE) - if dlg.ShowModal() == wx.ID_OK: - path = dlg.GetPath() - dlg.Destroy() - return path - - def slice(self, event): - if not event.IsChecked(): - self.canvas.mpl_disconnect(self.slice_event_id) - self.slice_event_id = None - self.menu_event_id = self.canvas.mpl_connect( - "button_press_event", self.on_click - ) - self.canvas.SetCursor(wx.StockCursor(wx.CURSOR_ARROW)) - for w in self.slice_widget: - w.remove() - self.slice_widget = [] - - self.cross_slice_fig = None - self.segment_slice_fig = None - - self.segment_slice_color_index = 0 - self.cross_slice_color_index = -1 - self.v_cross_slice_plot = None - self.h_cross_slice_plot = None - self.segment_slice_legend = [] - self.h_cross_slice_legend = [] - self.v_cross_slice_legend = [] - if self.cross_slice_dialog: - self.cross_slice_dialog.Close() - self.canvas.draw() - return - self.canvas.mpl_disconnect(self.menu_event_id) - self.menu_event_id = None - self.slice_event_id = self.canvas.mpl_connect( - "button_press_event", self.build_slice_widget - ) - self.canvas.SetCursor(wx.CROSS_CURSOR) - self.canvas.draw() - - def build_slice_widget(self, event): - if not event.inaxes: - return - - elif event.button == 1: # CROSS SLICING CASE - x, y = event.xdata, event.ydata - dx = (self.Xmax - self.Xmin) / float(self.data.shape[1]) - dy = (self.Ymax - self.Ymin) / float(self.data.shape[0]) - X = np.floor((x - self.Xmin) / dx) - Y = np.floor((y - self.Ymin) / dy) - vslice, hslice = self.extract_cross_slice(X, Y) - - if not self.parent.unique_slicer is None: - self.cross_slice_dialog = self.parent.unique_slicer.dialog - self.cross_slice_canvas = self.parent.unique_slicer.canvas - self.h_cross_slice_plot = self.parent.unique_slicer.hplot - self.v_cross_slice_plot = self.parent.unique_slicer.vplot - self.cross_slice_fig = self.parent.unique_slicer.fig - self.cross_slice_color_index = self.parent.unique_slicer.color_index - self.parent.unique_slicer.color_index += 1 - self.h_cross_slice_legend = self.parent.unique_slicer.hlegend - self.v_cross_slice_legend = self.parent.unique_slicer.vlegend - - elif self.cross_slice_fig is None or not self.cross_slice_fig: - self.cross_slice_fig = Figure() - self.v_cross_slice_plot = self.cross_slice_fig.add_subplot(211) - self.h_cross_slice_plot = self.cross_slice_fig.add_subplot(212) - - if self.cross_slice_dialog is None or not self.cross_slice_dialog: - self.cross_slice_dialog = wx.Frame(self, title="Cross slicing") - self.cross_slice_canvas = FigureCanvasWxAgg( - self.cross_slice_dialog, wx.ID_ANY, self.cross_slice_fig - ) - self.cross_slice_toolbar = NavigationToolbar2WxAgg( - self.cross_slice_canvas - ) - - self.unique_target_checkbox = wx.CheckBox( - self.cross_slice_dialog, id=wx.ID_ANY, label="Single target plot" - ) - self.Bind( - wx.EVT_CHECKBOX, - self.made_unique_target, - id=self.unique_target_checkbox.GetId(), - ) - self.unique_target_checkbox.SetValue(self.unique) - - self.auto_scale_button = wx.Button( - self.cross_slice_dialog, id=wx.ID_ANY, label="Auto-Scale" - ) - self.Bind( - wx.EVT_BUTTON, self.auto_scale_cross_plot, self.auto_scale_button - ) - - sizer = wx.BoxSizer(wx.VERTICAL) - sizer.Add(self.cross_slice_canvas, 1, flag=wx.EXPAND) - hsizer = wx.BoxSizer() - hsizer.Add(self.cross_slice_toolbar, 0, flag=wx.EXPAND) - hsizer.AddSpacer(10) - hsizer.Add( - self.auto_scale_button, - 0, - flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, - ) - hsizer.AddSpacer(10) - hsizer.Add( - self.unique_target_checkbox, - 0, - flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, - ) - - sizer.Add(hsizer, 0, flag=wx.EXPAND) - - self.cross_slice_dialog.SetSizer(sizer) - sizer.Fit(self.cross_slice_dialog) - - self.cross_slice_color_index += 1 - - self.slice_widget.append( - self.subplot.axvline( - x=x, - linewidth=3, - color="%s" % self.get_circular_color(self.cross_slice_color_index), - ) - ) - self.slice_widget.append( - self.subplot.axhline( - y=y, - linewidth=3, - color="%s" % self.get_circular_color(self.cross_slice_color_index), - ) - ) - - v_tmp_plot = self.v_cross_slice_plot.plot( - self.Xaxis * self.Xunit_conversion_factor, - vslice, - color="%s" % self.get_circular_color(self.cross_slice_color_index), - ) - h_tmp_plot = self.h_cross_slice_plot.plot( - self.Yaxis * self.Yunit_conversion_factor, - hslice, - color="%s" % self.get_circular_color(self.cross_slice_color_index), - ) - - self.v_cross_slice_legend.append( - [v_tmp_plot[0], "%s = %8.3f" % (self.Ylabel, y)] - ) - self.h_cross_slice_legend.append( - [h_tmp_plot[0], "%s = %8.3f" % (self.Xlabel, x)] - ) - - self.v_cross_slice_plot.set_xlabel(self.Xlabel + self.fmt_Xunit) - self.h_cross_slice_plot.set_xlabel(self.Ylabel + self.fmt_Yunit) - - self.v_cross_slice_plot.legend( - tuple([e[0] for e in self.v_cross_slice_legend]), - tuple([e[1] for e in self.v_cross_slice_legend]), - loc="best", - frameon=True, - shadow=True, - ) - self.h_cross_slice_plot.legend( - tuple([e[0] for e in self.h_cross_slice_legend]), - tuple([e[1] for e in self.h_cross_slice_legend]), - loc="best", - frameon=True, - shadow=True, - ) - - if self.aspect == "auto": - self.subplot.set_aspect("auto", "datalim") - - self.canvas.draw() - self.cross_slice_dialog.Show() - self.cross_slice_canvas.draw() - - def made_unique_target(self, event): - self.parent.unique_slicer = CrossSlicer( - self, - self.cross_slice_canvas, - self.cross_slice_dialog, - self.h_cross_slice_plot, - self.v_cross_slice_plot, - self.cross_slice_fig, - self.cross_slice_color_index, - self.h_cross_slice_legend, - self.v_cross_slice_legend, - ) - if self.unique: - self.cross_slice_canvas = None - self.cross_slice_fig = None - self.h_cross_slice_plot = None - self.v_cross_slice_plot = None - self.cross_slice_color_index = 0 - self.h_cross_slice_legend = [] - self.v_cross_slice_legend = [] - for w in self.slice_widget: - w.remove() - self.slice_widget = [] - self.canvas.draw() - self.parent.unique_slicer = None - self.cross_slice_dialog.Close() - - self.unique = not self.unique - - def auto_scale_cross_plot(self, event): - norm = Normalize() - - for hl in self.h_cross_slice_plot.get_lines(): - d = hl.get_ydata() - norm.autoscale(d) - hl.set_ydata(norm(d)) - - for vl in self.v_cross_slice_plot.get_lines(): - d = vl.get_ydata() - norm.autoscale(d) - vl.set_ydata(norm(d)) - - self.v_cross_slice_plot.relim() - self.h_cross_slice_plot.relim() - self.v_cross_slice_plot.autoscale_view(True, True, True) - self.h_cross_slice_plot.autoscale_view(True, True, True) - - self.cross_slice_canvas.draw() - - def get_circular_color(self, idx): - circ_idx = idx % len(self.color_list) - return list(self.color_list.values())[circ_idx] - - def extract_cross_slice(self, x, y): - x = int(x) - y = int(y) - hslice = self.data.T[x, :] - vslice = self.data.T[:, y] - return vslice, hslice - - def set_lim(self): - self.Xmin, self.Xmax = self.Xaxis[0], self.Xaxis[-1] - if self.Xmin == self.Xmax: - self.Xmin -= 1.0e-9 - self.Xmax += 1.0e-9 - - self.Ymin, self.Ymax = self.Yaxis[0], self.Yaxis[-1] - if self.Ymin == self.Ymax: - self.Ymin -= 1.0e-9 - self.Ymax += 1.0e-9 - - def reset_axis(self): - self.figure.gca().axis([self.Xmin, self.Xmax, self.Ymin, self.Ymax]) - self.canvas.draw() - - def plot( - self, - data, - varname, - Xaxis=None, - Xunit=None, - Yaxis=None, - Yunit=None, - transposition=True, - ): - if data is None: - return - - if (Xaxis is None) or (Xunit is None) or (Yaxis is None) or (Yunit is None): - self.set_axis_property(varname, data) - else: - self.Xaxis = Xaxis - self.Xunit = Xunit - self.Yaxis = Yaxis - self.Yunit = Yunit - - if transposition: - self.data = data.T - else: - self.data = data - - self.varname = varname - - self.subplot = self.figure.add_subplot(111) - - self.ax = self.subplot.imshow( - self.data, interpolation=self.interpolation, origin="lower" - ) - - self.subplot.set_aspect("auto") - self.aspect = "auto" - - self.Xlabel = self.Xaxis_label - self.Ylabel = self.Yaxis_label - self.figure.gca().set_xlabel(self.Xlabel + self.fmt_Xunit) - self.figure.gca().set_ylabel(self.Ylabel + self.fmt_Yunit) - - self.set_lim() - self.set_ticks() - self.reset_axis() - - self.color_bar = self.figure.colorbar(self.ax) - - self.canvas.draw() - - def replot(self, oldinstance): - self.data = oldinstance.data - self.Xaxis = oldinstance.Xaxis - self.Xunit = oldinstance.Xunit - self.Yaxis = oldinstance.Yaxis - self.Yunit = oldinstance.Yunit - self.varname = oldinstance.varname - self.Xaxis_label = oldinstance.Xaxis_label - self.Yaxis_label = oldinstance.Yaxis_label - self.normType = oldinstance.normType - self.aspect = oldinstance.aspect - self.subplot = self.figure.add_subplot(111) - - self.ax = self.subplot.imshow( - self.data, interpolation=self.interpolation, origin="lower" - ) - - self.subplot.set_aspect(self.aspect) - - self.Xlabel = self.Xaxis_label - self.Ylabel = self.Yaxis_label - self.figure.gca().set_xlabel(self.Xlabel + self.fmt_Xunit) - self.figure.gca().set_ylabel(self.Ylabel + self.fmt_Yunit) - - self.set_ticks() - self.reset_axis() - - self.color_bar = self.figure.colorbar(self.ax) - - self.scale(onReplot=True) - - self.canvas.draw() - - def scale(self, onReplot=False): - if self.normType not in NORMALIZER: - self.color_bar.set_clim(self.data.min(), self.data.max()) - self.ax.set_norm(None) - return - - norm = NORMALIZER[self.normType] - norm.autoscale(self.data) - - try: - self.ax.set_norm(norm) - except ValueError: - raise Plotter2DError( - "Could not set normalization : difference between minimum and maximum values is to small" - ) - - if onReplot: - normd = norm(self.data) - self.color_bar.set_clim(normd.min(), normd.max()) - - def compute_conversion_factor(self): - try: - m = measure(1.0, self.Xinit_unit, equivalent=True) - self.Xunit_conversion_factor = m.toval(self.Xunit) - except UnitError: - self.Xunit_conversion_factor = 1.0 - - try: - m = measure(1.0, self.Yinit_unit, equivalent=True) - self.Yunit_conversion_factor = m.toval(self.Yunit) - except UnitError: - self.Yunit_conversion_factor = 1.0 - - def set_ticks(self): - self.compute_conversion_factor() - - self.figure.gca().xaxis.set_major_locator( - ScaledLocator(dx=self.Xunit_conversion_factor) - ) - xAxisFormatter = ScaledFormatter(dx=self.Xunit_conversion_factor) - self.figure.gca().xaxis.set_major_formatter(xAxisFormatter) - - self.figure.gca().yaxis.set_major_locator( - ScaledLocator(dx=self.Yunit_conversion_factor) - ) - yAxisFormatter = ScaledFormatter(dx=self.Yunit_conversion_factor) - self.figure.gca().yaxis.set_major_formatter(yAxisFormatter) - - self.ax.set_extent([self.Xmin, self.Xmax, self.Ymin, self.Ymax]) - - def set_axis_property(self, varname, data): - oldXunit = self.Xinit_unit - oldYunit = self.Yinit_unit - - try: - self.Xaxis_label = self.dataproxy[varname]["axis"][0] - self.Xunit = self.Xinit_unit = self.dataproxy[self.Xaxis_label]["units"] - self.Xaxis = self.dataproxy[self.Xaxis_label]["data"] - if self.Xaxis.shape[0] != data.shape[0]: - raise - except: - self.Xaxis_label = "x" - self.Xunit = self.Xinit_unit = "au" - self.Xaxis = np.arange(data.shape[0]) - - try: - self.Yaxis_label = self.dataproxy[varname]["axis"][1] - self.Yunit = self.Yinit_unit = self.dataproxy[self.Yaxis_label]["units"] - self.Yaxis = self.dataproxy[self.Yaxis_label]["data"] - if self.Yaxis.shape[0] != data.shape[1]: - raise - except: - self.Yaxis_label = "y" - self.Yunit = self.Yinit_unit = "au" - self.Yaxis = np.arange(data.shape[1]) - - if not oldXunit is None: - if oldXunit != self.Xinit_unit: - raise Plotter2DError( - "the x axis unit (%s) of data-set %r is inconsistent with the unit (%s) of the precedent data plotted " - % (self.Xinit_unit, varname, oldXunit) - ) - if not oldYunit is None: - if oldYunit != self.Yinit_unit: - raise Plotter2DError( - "the y axis unit (%s) of data-set %r is inconsistent with the unit (%s) of the precedent data plotted " - % (self.Yinit_unit, varname, oldYunit) - ) - - def image_setting_dialog(self, event=None): - d = ImageSettingsDialog(self) - d.SetFocus() - d.ShowModal() - d.Destroy() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/Plotter3D.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/Plotter3D.py deleted file mode 100644 index 719de57cb4..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/Plotter3D.py +++ /dev/null @@ -1,1053 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/Plotter3D.py -# @brief Implements module/class/test Plotter3D -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import os - -import wx -import wx.aui as wxaui - -import numpy as np - -import vtk -from vtk.util.numpy_support import numpy as np_to_vtk -from vtk.wx.wxVTKRenderWindowInteractor import wxVTKRenderWindowInteractor - -from MDANSE.Core.Error import Error - -DTYPES_TO_VTK = { - "uint8": vtk.VTK_UNSIGNED_CHAR, - "uint16": vtk.VTK_UNSIGNED_SHORT, - "int8": vtk.VTK_CHAR, - "int16": vtk.VTK_SHORT, - "int32": vtk.VTK_INT, - "uint32": vtk.VTK_UNSIGNED_INT, - "float32": vtk.VTK_FLOAT, - "float64": vtk.VTK_DOUBLE, -} - - -class Plotter3DError(Error): - pass - - -class Plotter3D(wx.Panel): - type = "3d" - - def __init__(self, parent, *args, **kwargs): - """ - The constructor. - """ - wx.Panel.__init__(self, parent, *args, **kwargs) - - self.parent = parent - - self._mgr = wxaui.AuiManager(self) - - self.build_panel() - - def build_panel(self): - self.viewer = wx.Panel(self) - - self.iren = wxVTKRenderWindowInteractor( - self.viewer, -1, size=(500, 500), flag=wx.EXPAND - ) - self.iren.SetPosition((0, 0)) - # define interaction style - self.iren.GetInteractorStyle().SetCurrentStyleToTrackballCamera() - self.iren.Enable(1) - - # create renderer - self.renderer = vtk.vtkRenderer() - self.renderer.SetBackground(1, 1, 1) - self.iren.GetRenderWindow().AddRenderer(self.renderer) - - # create camera - self.camera = vtk.vtkCamera() - # associate camera to renderer - self.renderer.SetActiveCamera(self.camera) - self.camera.SetFocalPoint(0, 0, 0) - self.camera.SetPosition(0, 0, 0) - - self.data = None - self.image = None - self.axes = None - self.actor_list = [] - self.plot_type = "" - - Sizer = wx.BoxSizer(wx.VERTICAL) - Sizer.Add(self.iren, 1, wx.EXPAND, 0) - - self.viewer.SetSizer(Sizer) - Sizer.Fit(self.viewer) - self.viewer.Layout() - - self._mgr.AddPane( - self.viewer, - wxaui.AuiPaneInfo() - .Center() - .Dock() - .DestroyOnClose(False) - .CloseButton(False) - .CaptionVisible(False) - .MinSize(self.iren.GetSize()), - ) - self._mgr.Update() - - def array_to_2d_imagedata(self): - if self.data.ndim != 2: - raise Plotter3DError("Data dimension should be 2") - - nx = self.data.shape[0] - ny = self.data.shape[1] - nz = 1 - - image = vtk.vtkImageData() - image.SetDimensions(nx, ny, 1) - image.SetExtent(0, nx - 1, 0, ny - 1, 0, nz - 1) - - dtype = DTYPES_TO_VTK[self.data.dtype.name] - - if vtk.vtkVersion.GetVTKMajorVersion() < 6: - image.SetScalarType(dtype) - image.SetNumberOfScalarComponents(1) - else: - image.AllocateScalars(dtype, 1) - - image.SetSpacing(1.0, 1.0, 0.0) - - vtk_array = numpy_to_vtk( - num_array=self.data.ravel(), deep=True, array_type=dtype - ) - image.GetPointData().SetScalars(vtk_array) - - return image - - def array_to_3d_imagedata(self): - if self.data.ndim != 3: - raise Plotter3DError("Data dimension should be 3") - - nx = self.data.shape[0] - ny = self.data.shape[1] - nz = self.data.shape[2] - image = vtk.vtkImageData() - image.SetDimensions(nx, ny, nz) - image.SetExtent(0, nx - 1, 0, ny - 1, 0, nz - 1) - - dtype = DTYPES_TO_VTK[self.data.dtype.name] - - if vtk.vtkVersion.GetVTKMajorVersion() < 6: - image.SetScalarType(dtype) - image.SetNumberOfScalarComponents(1) - else: - image.AllocateScalars(dtype, 1) - - vtk_array = numpy_to_vtk( - num_array=self.data.ravel(), deep=True, array_type=dtype - ) - image.GetPointData().SetScalars(vtk_array) - - return image - - def scalarfield(self, data): - self.data = data - self.settings = wx.Panel(self) - - self.plot_type = self.type = "scalarfield" - - self.image = self.array_to_3d_imagedata() - - imageCast = vtk.vtkImageCast() - if vtk.vtkVersion.GetVTKMajorVersion() < 6: - imageCast.SetInput(self.image) - else: - imageCast.SetInputData(self.image) - - imageCast.SetOutputScalarTypeToUnsignedShort() - - # Create transfer mapping scalar value to opacity - opacityTransferFunction = vtk.vtkPiecewiseFunction() - opacityTransferFunction.AddPoint(self.data.min(), 0) - opacityTransferFunction.AddPoint(self.data.max(), 1) - - # Create transfer mapping scalar value to color - colorTransferFunction = vtk.vtkColorTransferFunction() - colorTransferFunction.SetColorSpaceToRGB() - colorTransferFunction.AddRGBPoint(self.data.min(), 0, 0, 1) - colorTransferFunction.AddRGBPoint(self.data.max(), 1, 0, 0) - scalarBar = vtk.vtkScalarBarActor() - # Must add this to avoid vtkTextActor error - scalarBar.SetTitle("") - scalarBar.SetWidth(0.1) - scalarBar.SetHeight(0.9) - scalarBar.SetLookupTable(colorTransferFunction) - - self.outline = vtk.vtkOutlineFilter() - self.outline.SetInputConnection(imageCast.GetOutputPort()) - self.outline.Update() - - outlineMapper = vtk.vtkPolyDataMapper() - if vtk.vtkVersion.GetVTKMajorVersion() < 6: - outlineMapper.SetInputConnection(self.outline.GetOutputPort()) - else: - outlineMapper.SetInputData(self.outline.GetOutputDataObject(0)) - - box = vtk.vtkActor() - box.SetMapper(outlineMapper) - box.GetProperty().SetColor(0, 0, 0) - - # The property describes how the data will look - volumeProperty = vtk.vtkVolumeProperty() - volumeProperty.SetColor(colorTransferFunction) - volumeProperty.SetScalarOpacity(opacityTransferFunction) - volumeProperty.ShadeOn() - volumeProperty.SetInterpolationTypeToLinear() - - # The mapper / ray cast function know how to render the data - compositeFunction = vtk.vtkVolumeRayCastCompositeFunction() - volumeMapper = vtk.vtkVolumeRayCastMapper() - volumeMapper.SetVolumeRayCastFunction(compositeFunction) - volumeMapper.SetInputConnection(imageCast.GetOutputPort()) - - # The volume holds the mapper and the property and - # can be used to position/orient the volume - volume = vtk.vtkVolume() - volume.SetMapper(volumeMapper) - volume.SetProperty(volumeProperty) - - self.renderer.AddVolume(volume) - self.renderer.AddActor2D(scalarBar) - self.renderer.AddActor(box) - self.build_axes() - self.actor_list.append(volume) - self.actor_list.append(scalarBar) - self.actor_list.append(box) - - self.center_on_actor(volume, out=True) - self.iren.Render() - - control_sizer = wx.BoxSizer() - content1 = wx.StaticText( - self.settings, -1, "X :", style=wx.ALIGN_CENTER_VERTICAL - ) - self.x_slider = wx.Slider( - self.settings, - id=wx.ID_ANY, - value=100, - minValue=0, - maxValue=200, - style=wx.SL_AUTOTICKS | wx.SL_HORIZONTAL | wx.SL_LABELS, - ) - self.x_slider.Bind(wx.EVT_SCROLL, self.x_spacing_onmove) - content2 = wx.StaticText( - self.settings, -1, "Y :", style=wx.ALIGN_CENTER_VERTICAL - ) - self.y_slider = wx.Slider( - self.settings, - id=wx.ID_ANY, - value=100, - minValue=0, - maxValue=200, - style=wx.SL_AUTOTICKS | wx.SL_HORIZONTAL | wx.SL_LABELS, - ) - self.y_slider.Bind(wx.EVT_SCROLL, self.y_spacing_onmove) - content3 = wx.StaticText( - self.settings, -1, "Z :", style=wx.ALIGN_CENTER_VERTICAL - ) - self.z_slider = wx.Slider( - self.settings, - id=wx.ID_ANY, - value=100, - minValue=0, - maxValue=200, - style=wx.SL_AUTOTICKS | wx.SL_HORIZONTAL | wx.SL_LABELS, - ) - self.z_slider.Bind(wx.EVT_SCROLL, self.z_spacing_onmove) - - # build sizer - control_sizer.Add((20, -1), proportion=0, flag=wx.EXPAND | wx.ALIGN_RIGHT) - control_sizer.Add(content1, proportion=0, flag=wx.ALIGN_BOTTOM) - control_sizer.Add(self.x_slider, proportion=1, flag=wx.EXPAND) - control_sizer.Add((20, -1), proportion=0, flag=wx.EXPAND | wx.ALIGN_RIGHT) - control_sizer.Add(content2, proportion=0, flag=wx.ALIGN_BOTTOM) - control_sizer.Add(self.y_slider, proportion=1, flag=wx.EXPAND) - control_sizer.Add((20, -1), proportion=0, flag=wx.EXPAND | wx.ALIGN_RIGHT) - control_sizer.Add(content3, proportion=0, flag=wx.ALIGN_BOTTOM) - control_sizer.Add(self.z_slider, proportion=1, flag=wx.EXPAND) - - self.save_fig = wx.Button(self.settings, wx.ID_ANY, label="Save current view") - self.save_fig.Bind(wx.EVT_BUTTON, self.Screen_shot) - - Sizer = wx.BoxSizer(wx.VERTICAL) - - Sizer.Add(control_sizer, 0, wx.EXPAND, 0) - Sizer.Add(self.save_fig, 0, wx.EXPAND, 0) - - self.settings.SetSizer(Sizer) - Sizer.Fit(self.settings) - self.settings.Layout() - - self._mgr.AddPane( - self.settings, - wxaui.AuiPaneInfo() - .Center() - .Dock() - .Bottom() - .CloseButton(False) - .CaptionVisible(False), - ) - self._mgr.Update() - - def elevation(self, data): - self.data = data - - self.settings = wx.Panel(self) - - self.plot_type = self.type = "elevation" - - self.image = self.array_to_2d_imagedata() - - geometry = vtk.vtkImageDataGeometryFilter() - if vtk.vtkVersion.GetVTKMajorVersion() < 6: - geometry.SetInput(self.image) - else: - geometry.SetInputData(self.image) - - self.warp = vtk.vtkWarpScalar() - self.warp.SetInputConnection(geometry.GetOutputPort()) - self.warp.SetScaleFactor(1) - self.warp.UseNormalOn() - self.warp.SetNormal(0, 0, 1) - self.warp.Update() - - lut = vtk.vtkLookupTable() - lut.SetTableRange(self.image.GetScalarRange()) - lut.SetNumberOfColors(256) - lut.SetHueRange(0.7, 0) - lut.Build() - - merge = vtk.vtkMergeFilter() - if vtk.vtkVersion.GetVTKMajorVersion() < 6: - merge.SetGeometry(self.warp.GetOutput()) - merge.SetScalars(self.image) - else: - merge.SetGeometryInputData(self.warp.GetOutput()) - merge.SetScalarsData(self.image) - merge.Update() - - self.outline = vtk.vtkOutlineFilter() - self.outline.SetInputConnection(merge.GetOutputPort()) - self.outline.Update() - - outlineMapper = vtk.vtkPolyDataMapper() - if vtk.vtkVersion.GetVTKMajorVersion() < 6: - outlineMapper.SetInputConnection(self.outline.GetOutputPort()) - else: - outlineMapper.SetInputData(self.outline.GetOutputDataObject(0)) - - box = vtk.vtkActor() - box.SetMapper(outlineMapper) - box.GetProperty().SetColor(0, 0, 0) - - self.renderer.AddActor(box) - self.actor_list.append(box) - - mapper = vtk.vtkPolyDataMapper() - mapper.SetLookupTable(lut) - mapper.SetScalarRange(self.image.GetScalarRange()) - mapper.SetInputConnection(merge.GetOutputPort()) - - actor = vtk.vtkActor() - actor.SetMapper(mapper) - self.renderer.AddActor(actor) - self.actor_list.append(actor) - - scalarBar = vtk.vtkScalarBarActor() - scalarBar.SetTitle("") - scalarBar.SetWidth(0.1) - scalarBar.SetHeight(0.9) - scalarBar.SetLookupTable(lut) - self.renderer.AddActor2D(scalarBar) - self.actor_list.append(scalarBar) - - self.build_axes(noZaxis=True) - - self.center_on_actor(actor) - self.iren.Render() - self.warp.SetScaleFactor(0) - self.warp.Update() - self.outline.Update() - - self.renderer.ResetCameraClippingRange() - self.iren.Render() - - sb0 = wx.StaticBox(self.settings, wx.ID_ANY, label="Scaling Panel") - Sizer0 = wx.StaticBoxSizer(sb0, wx.HORIZONTAL) - - content1 = wx.StaticText(self.settings, -1, "X") - - self.x_Offset = wx.TextCtrl( - self.settings, wx.ID_ANY, size=(45, 27), style=wx.TE_PROCESS_ENTER - ) - self.Bind(wx.EVT_TEXT_ENTER, self.x_spacing_onmove, self.x_Offset) - self.x_Offset.SetValue("1.0") - - self.x_slider = wx.Slider( - self.settings, - id=wx.ID_ANY, - value=100, - minValue=0, - maxValue=200, - style=wx.SL_AUTOTICKS | wx.SL_HORIZONTAL | wx.SL_LABELS, - ) - self.x_slider.Bind(wx.EVT_SCROLL, self.x_spacing_onmove) - content2 = wx.StaticText(self.settings, -1, "Y") - - self.y_Offset = wx.TextCtrl( - self.settings, wx.ID_ANY, size=(45, 27), style=wx.TE_PROCESS_ENTER - ) - self.Bind(wx.EVT_TEXT_ENTER, self.y_spacing_onmove, self.y_Offset) - self.y_Offset.SetValue("1.0") - - self.y_slider = wx.Slider( - self.settings, - id=wx.ID_ANY, - value=100, - minValue=0, - maxValue=200, - style=wx.SL_AUTOTICKS | wx.SL_HORIZONTAL | wx.SL_LABELS, - ) - self.y_slider.Bind(wx.EVT_SCROLL, self.y_spacing_onmove) - - sb1 = wx.StaticBox(self.settings, wx.ID_ANY, label="Elevation Panel") - Sizer1 = wx.StaticBoxSizer(sb1, wx.HORIZONTAL) - - content3 = wx.StaticText(self.settings, -1, "Warp") - - self.z_Offset = wx.TextCtrl( - self.settings, wx.ID_ANY, size=(45, 27), style=wx.TE_PROCESS_ENTER - ) - self.Bind(wx.EVT_TEXT_ENTER, self.z_spacing_onmove, self.z_Offset) - self.z_Offset.SetValue("1.0") - - self.z_slider = wx.Slider( - self.settings, - id=wx.ID_ANY, - value=0, - minValue=0, - maxValue=100, - style=wx.SL_HORIZONTAL, - ) - self.z_slider.Bind(wx.EVT_SCROLL, self.z_spacing_onmove) - - # build sizer - Sizer0.Add(content1, proportion=0, flag=wx.ALIGN_BOTTOM) - Sizer0.Add(self.x_Offset, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL) - Sizer0.Add( - self.x_slider, proportion=1, flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND - ) - Sizer0.Add((20, -1), proportion=0, flag=wx.ALIGN_CENTER_VERTICAL) - Sizer0.Add(content2, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL) - Sizer0.Add(self.y_Offset, proportion=0, flag=wx.ALIGN_BOTTOM) - Sizer0.Add( - self.y_slider, proportion=1, flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND - ) - - Sizer1.Add(content3, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL) - Sizer1.Add(self.z_Offset, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL) - Sizer1.Add( - self.z_slider, proportion=1, flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND - ) - - self.save_fig = wx.Button(self.settings, wx.ID_ANY, label="Save current view") - self.save_fig.Bind(wx.EVT_BUTTON, self.Screen_shot) - - Sizer = wx.BoxSizer(wx.VERTICAL) - - HSizer = wx.BoxSizer(wx.HORIZONTAL) - - HSizer.Add(Sizer0, 1, wx.EXPAND, 0) - HSizer.Add(Sizer1, 1, wx.EXPAND, 0) - - Sizer.Add(HSizer, 0, wx.EXPAND, 0) - Sizer.Add(self.save_fig, 0, wx.EXPAND, 0) - - self.settings.SetSizer(Sizer) - Sizer.Fit(self.settings) - self.settings.Layout() - - self._mgr.AddPane( - self.settings, - wxaui.AuiPaneInfo() - .Center() - .Dock() - .Bottom() - .CloseButton(False) - .CaptionVisible(False), - ) - self._mgr.Update() - - def x_spacing_onmove(self, evt=None): - if self.image: - try: - offset_mupltiplier = float(self.x_Offset.GetValue()) - except: - offset_mupltiplier = 1.0 - _, y, z = self.image.GetSpacing() - val = self.x_slider.GetValue() - x = (val * offset_mupltiplier) / 100.0 - self.axes.SetTotalLength( - (self.data.shape[0] - 1) * x, - (self.data.shape[1] - 1) * y, - self.data.max() * z, - ) - self.image.SetSpacing(x, y, z) - if self.plot_type == "elevation": - self.warp.Update() - self.outline.Update() - self.iren.Render() - - def y_spacing_onmove(self, evt=None): - if self.image: - try: - offset_mupltiplier = float(self.y_Offset.GetValue()) - except: - offset_mupltiplier = 1.0 - x, _, z = self.image.GetSpacing() - val = self.y_slider.GetValue() - y = (val * offset_mupltiplier) / 100.0 - self.axes.SetTotalLength( - (self.data.shape[0] - 1) * x, - (self.data.shape[1] - 1) * y, - self.data.max() * z, - ) - self.image.SetSpacing(x, y, z) - if self.plot_type == "elevation": - self.warp.Update() - self.outline.Update() - self.iren.Render() - - def z_spacing_onmove(self, evt=None): - if self.image: - try: - offset_mupltiplier = float(self.z_Offset.GetValue()) - except: - offset_mupltiplier = 1.0 - x, y, _ = self.image.GetSpacing() - val = self.z_slider.GetValue() - z = (val / 25.0) * offset_mupltiplier - self.axes.SetTotalLength( - (self.data.shape[0] - 1) * x, - (self.data.shape[1] - 1) * y, - self.data.max() * z, - ) - if self.plot_type == "elevation": - self.warp.SetScaleFactor(z) - self.warp.Update() - self.image.SetSpacing(x, y, z) - self.renderer.ResetCameraClippingRange() - self.outline.Update() - self.iren.Render() - - def reset_sliders(self): - self.x_slider.SetValue(0) - self.y_slider.SetValue(0) - self.z_slider.SetValue(0) - - def isosurface(self, data, isovalue, rendtype): - self.data = data - - self.settings = wx.Panel(self) - - self.plot_type = self.type = "isosurface" - - self.image = self.array_to_3d_imagedata() - - self.iso = vtk.vtkMarchingContourFilter() - self.iso.UseScalarTreeOn() - self.iso.ComputeNormalsOn() - if vtk.vtkVersion.GetVTKMajorVersion() < 6: - self.iso.SetInput(self.image) - else: - self.iso.SetInputData(self.image) - self.iso.SetValue(0, isovalue) - - depthSort = vtk.vtkDepthSortPolyData() - depthSort.SetInputConnection(self.iso.GetOutputPort()) - depthSort.SetDirectionToBackToFront() - depthSort.SetVector(1, 1, 1) - depthSort.SetCamera(self.camera) - depthSort.SortScalarsOn() - depthSort.Update() - - mapper = vtk.vtkPolyDataMapper() - mapper.SetInputConnection(depthSort.GetOutputPort()) - mapper.ScalarVisibilityOff() - mapper.Update() - - self.surf = vtk.vtkActor() - self.surf.SetMapper(mapper) - self.surf.GetProperty().SetColor((0, 0.5, 0.75)) - self.surf.PickableOff() - - outline = vtk.vtkOutlineFilter() - - if vtk.vtkVersion.GetVTKMajorVersion() < 6: - outline.SetInput(self.image) - else: - outline.SetInputData(self.image) - outlineMapper = vtk.vtkPolyDataMapper() - outlineMapper.SetInputConnection(outline.GetOutputPort()) - box = vtk.vtkActor() - box.SetMapper(outlineMapper) - box.GetProperty().SetColor((0, 0, 0)) - box.PickableOff() - - self.renderer.AddActor(box) - - if rendtype == "w": - self.surf.GetProperty().SetRepresentationToWireframe() - elif rendtype == "s": - self.surf.GetProperty().SetRepresentationToSurface() - elif rendtype == "p": - self.surf.GetProperty().SetRepresentationToPoints() - self.surf.GetProperty().SetPointSize(5) - else: - self.surf.GetProperty().SetRepresentationToWireframe() - self.surf.GetProperty().SetInterpolationToGouraud() - self.surf.GetProperty().SetSpecular(0.4) - self.surf.GetProperty().SetSpecularPower(10) - - self.renderer.AddActor(self.surf) - self.build_axes() - - self.center_on_actor(self.surf, out=True) - - sb1 = wx.StaticBox(self.settings, wx.ID_ANY, label="Contour Level") - isovSizer = wx.StaticBoxSizer(sb1, wx.HORIZONTAL) - self.isov_scale = 100.0 - self.isov_slider = wx.Slider( - self.settings, - wx.ID_ANY, - value=isovalue * self.isov_scale, - minValue=int(self.data.min() * self.isov_scale), - maxValue=int(self.data.max() * self.isov_scale), - size=(60, 27), - style=wx.SL_HORIZONTAL, - ) - - self.isov_slider.Bind(wx.EVT_SCROLL, self.on_change_isov) - isovSizer.Add(self.isov_slider, 1, wx.ALIGN_CENTER_VERTICAL, 0) - - rendSizer = wx.BoxSizer() - self.rendlist_label = wx.StaticText(self.settings, label="Rendering mode") - self.rendlist = wx.ComboBox( - self.settings, - id=wx.ID_ANY, - choices=["surface", "wireframe", "points"], - style=wx.CB_READONLY, - ) - self.rendlist.SetValue("wireframe") - self.rendlist.Bind(wx.EVT_COMBOBOX, self.on_change_surf_rend_mode) - - self.opacity_label = wx.StaticText(self.settings, label="Opacity level [0-1]") - self.opacity = wx.TextCtrl( - self.settings, wx.ID_ANY, style=wx.SL_HORIZONTAL | wx.TE_PROCESS_ENTER - ) - self.opacity.SetValue(str(1.0)) - self.opacity.Bind(wx.EVT_TEXT_ENTER, self.on_set_opacity) - - rendSizer.Add(self.rendlist_label, 0, wx.ALIGN_CENTER_VERTICAL, 0) - rendSizer.Add(self.rendlist, 0, wx.ALIGN_CENTER_VERTICAL, 0) - rendSizer.Add(self.opacity_label, 0, wx.ALIGN_CENTER_VERTICAL, 0) - rendSizer.Add(self.opacity, 0, wx.ALIGN_CENTER_VERTICAL, 0) - - sb = wx.StaticBox(self.settings, wx.ID_ANY, label="Slice orientation") - sliceSizer = wx.StaticBoxSizer(sb, wx.HORIZONTAL) - - self.sagittal = wx.RadioButton( - self.settings, wx.ID_ANY, label="sagittal (// to Y,Z)" - ) - self.axial = wx.RadioButton(self.settings, wx.ID_ANY, label="axial (// to X,Y)") - self.coronal = wx.RadioButton( - self.settings, wx.ID_ANY, label="coronal (// to X,Z)" - ) - self.oblique = wx.RadioButton( - self.settings, wx.ID_ANY, label="oblique (// to X,Y+Z)" - ) - - self.Bind(wx.EVT_RADIOBUTTON, self.on_slice_selection, self.sagittal) - self.Bind(wx.EVT_RADIOBUTTON, self.on_slice_selection, self.axial) - self.Bind(wx.EVT_RADIOBUTTON, self.on_slice_selection, self.coronal) - self.Bind(wx.EVT_RADIOBUTTON, self.on_slice_selection, self.oblique) - - sliceSizer.Add(self.sagittal, 1, wx.ALIGN_CENTER_VERTICAL, 0) - sliceSizer.Add(self.axial, 1, wx.ALIGN_CENTER_VERTICAL, 0) - sliceSizer.Add(self.coronal, 1, wx.ALIGN_CENTER_VERTICAL, 0) - sliceSizer.Add(self.oblique, 1, wx.ALIGN_CENTER_VERTICAL, 0) - - self.iren.AddObserver("CharEvent", self.on_keyboard_input) - self.reslice = None - key_doc = wx.StaticText( - self.settings, - wx.ID_ANY, - label="Press '+' and '-' keys to translate the slice", - ) - - self.save_fig = wx.Button(self.settings, wx.ID_ANY, label="Save current view") - self.save_fig.Bind(wx.EVT_BUTTON, self.Screen_shot) - - Sizer = wx.BoxSizer(wx.VERTICAL) - - Sizer.Add(rendSizer, 0, wx.EXPAND, 0) - Sizer.Add(isovSizer, 0, wx.EXPAND, 0) - Sizer.Add(sliceSizer, 0, wx.EXPAND, 0) - Sizer.Add(key_doc, 0, wx.EXPAND, 0) - Sizer.Add(self.save_fig, 0, wx.EXPAND, 0) - - self.iren.Render() - - self.settings.SetSizer(Sizer) - Sizer.Fit(self.settings) - self.settings.Layout() - - self._mgr.AddPane( - self.settings, - wxaui.AuiPaneInfo() - .Center() - .Dock() - .Bottom() - .CloseButton(False) - .CaptionVisible(False), - ) - self._mgr.Update() - - def cpt_isosurf(self, event=None): - try: - isov = float(self.isov.GetValue()) - except: - raise Plotter3DError( - "Contour level has wrong format : %s" % self.isov.GetValue() - ) - self.iso.SetValue(0, isov) - self.iso.Update() - self.iren.Render() - - def on_change_isov(self, event=None): - isov = float(self.isov_slider.GetValue()) / self.isov_scale - self.iso.SetValue(0, isov) - self.iso.Update() - self.iren.Render() - - def on_set_opacity(self, event=None): - opct = float(self.opacity.GetValue()) - self.surf.GetProperty().SetOpacity(opct) - self.iren.Render() - - def on_change_surf_rend_mode(self, event=None): - rendtype = self.rendlist.GetValue() - if rendtype == "wireframe": - self.surf.GetProperty().SetRepresentationToWireframe() - elif rendtype == "surface": - self.surf.GetProperty().SetRepresentationToSurface() - elif rendtype == "points": - self.surf.GetProperty().SetRepresentationToPoints() - self.surf.GetProperty().SetPointSize(3) - self.iren.Render() - - def on_keyboard_input(self, obj, event): - key = self.iren.GetKeyCode() - if key in ["+"]: - self.on_move_slice(1) - elif key in ["-"]: - self.on_move_slice(-1) - - elif key == " ": - self.start_stop_animation() - - def build_axes(self, noZaxis=False): - if self.axes is None: - self.axes = vtk.vtkAxesActor() - # self.axes.SetShaftTypeToCylinder() - if not noZaxis: - self.axes.SetTotalLength( - self.data.shape[0] - 1, - self.data.shape[1] - 1, - self.data.shape[2] - 1, - ) - else: - self.axes.SetTotalLength( - self.data.shape[0] - 1, self.data.shape[1] - 1, 0 - ) - self.axes.SetNormalizedShaftLength(1, 1, 1) - self.axes.SetNormalizedTipLength(0, 0, 0) - # self.axes.SetNormalizedShaftLength( 0.85, 0.85, 0.85 ) - # self.axes.SetNormalizedTipLength( 0.15, 0.15, 0.15 ) - self.axes.AxisLabelsOn() - self.axes.GetXAxisTipProperty().SetColor(0, 0, 1) - self.axes.GetXAxisShaftProperty().SetColor(0, 0, 1) - self.axes.GetXAxisShaftProperty().SetLineWidth(2) - self.axes.SetXAxisLabelText("x") - txtprop = vtk.vtkTextProperty() - txtprop.SetColor(0, 0, 0) - txtprop.SetFontFamilyToArial() - txtprop.SetFontSize(12) - txtprop.SetOpacity(0.5) - self.axes.GetXAxisCaptionActor2D().SetCaptionTextProperty(txtprop) - - self.axes.GetYAxisTipProperty().SetColor(0, 1, 0) - self.axes.GetYAxisShaftProperty().SetColor(0, 1, 0) - self.axes.GetYAxisShaftProperty().SetLineWidth(2) - self.axes.SetYAxisLabelText("y") - txtprop = vtk.vtkTextProperty() - txtprop.SetColor(0, 0, 0) - txtprop.SetFontFamilyToArial() - txtprop.SetFontSize(12) - txtprop.SetOpacity(0.5) - self.axes.GetYAxisCaptionActor2D().SetCaptionTextProperty(txtprop) - - self.axes.GetZAxisTipProperty().SetColor(1, 0, 0) - self.axes.GetZAxisShaftProperty().SetColor(1, 0, 0) - self.axes.GetZAxisShaftProperty().SetLineWidth(2) - self.axes.SetZAxisLabelText("z") - txtprop = vtk.vtkTextProperty() - txtprop.SetColor(0, 0, 0) - txtprop.SetFontFamilyToArial() - txtprop.SetFontSize(12) - txtprop.SetOpacity(0.5) - self.axes.GetZAxisCaptionActor2D().SetCaptionTextProperty(txtprop) - - self.renderer.AddActor(self.axes) - else: - if self.axes.GetVisibility(): - self.axes.VisibilityOff() - else: - self.axes.VisibilityOn() - - def on_slice_selection(self, event=None): - orientation = str(event.GetEventObject().GetLabelText()).lower().split()[0] - self.slice_orientation = orientation - self.slice() - self.iren.Render() - - def slice(self): - self.clear_universe() - - center = [ - self.data.shape[0] / 2.0, - self.data.shape[1] / 2.0, - self.data.shape[2] / 2.0, - ] - # Matrices for axial, coronal, sagittal, oblique view orientations - axial = vtk.vtkMatrix4x4() - axial.DeepCopy( - (1, 0, 0, center[0], 0, 1, 0, center[1], 0, 0, 1, center[2], 0, 0, 0, 1) - ) - - coronal = vtk.vtkMatrix4x4() - coronal.DeepCopy( - (1, 0, 0, center[0], 0, 0, 1, center[1], 0, -1, 0, center[2], 0, 0, 0, 1) - ) - - sagittal = vtk.vtkMatrix4x4() - sagittal.DeepCopy( - (0, 0, -1, center[0], 1, 0, 0, center[1], 0, -1, 0, center[2], 0, 0, 0, 1) - ) - - oblique = vtk.vtkMatrix4x4() - oblique.DeepCopy( - ( - 1, - 0, - 0, - center[0], - 0, - 0.866025, - -0.5, - center[1], - 0, - 0.5, - 0.866025, - center[2], - 0, - 0, - 0, - 1, - ) - ) - - orientation = { - "sagittal": sagittal, - "axial": axial, - "coronal": coronal, - "oblique": oblique, - } - self.orientation_matrix = orientation[self.slice_orientation] - - # Extract a slice in the desired orientation - self.reslice = vtk.vtkImageReslice() - if vtk.vtkVersion.GetVTKMajorVersion() < 6: - self.reslice.SetInput(self.image) - else: - self.reslice.SetInputData(self.image) - # xmi,xma,ymi,yma,zmi,zma - # self.reslice.SetOutputExtent(0, 100, 0, 100, 0, 0) - self.reslice.Update() - self.reslice.SetOutputDimensionality(2) - self.reslice.SetResliceAxes(orientation[self.slice_orientation]) - - table = vtk.vtkLookupTable() - - table.SetRange(self.data.min(), self.data.max()) # image intensity range - table.SetHueRange(0.7, 0) - table.Build() - - # Map the image through the lookup table - color = vtk.vtkImageMapToColors() - color.SetLookupTable(table) - color.SetOutputFormatToRGB() - color.PassAlphaToOutputOff() - color.SetInputConnection(self.reslice.GetOutputPort()) - color.Update() - - # Display the image - self.slice_actor = vtk.vtkImageActor() - - R = np.array( - self.ExtractRotMat(self.orientation_matrix) - ) # extraction de la matrice de rotation depuit la vtk 4x4 - alpha, beta, gamma = self.R2Eul(R) - self.RotaEuler(self.slice_actor, alpha, beta, gamma) - - self.slice_actor.SetPosition(center[0], center[1], center[2]) - if vtk.vtkVersion.GetVTKMajorVersion() < 6: - self.slice_actor.SetInput(color.GetOutput()) - else: - self.slice_actor.SetInputData(color.GetOutputDataObject(0)) - self.slice_actor.Update() - self.actor_list.append(self.slice_actor) - - self.renderer.AddActor(self.slice_actor) - - def center_on_actor(self, actor, out=False): # TODO out is useless : remove param - Xmin, Xmax, Ymin, Ymax, Zmin, Zmax = actor.GetBounds() - Xavg = (Xmin + Xmax) / 2.0 - Yavg = (Ymin + Ymax) / 2.0 - Zavg = (Zmin + Zmax) / 2.0 - self.camera.SetFocalPoint(Xavg, Yavg, Zavg) - self.camera.SetPosition(Xavg, Yavg, 3 * Zmax) - - def clear_universe(self): - for actor in self.actor_list: - actor.VisibilityOff() - self.renderer.RemoveActor(actor) - actor.ReleaseGraphicsResources(self.iren.GetRenderWindow()) - del actor - self.plot_type = "" - self.actor_list = [] - - def on_move_slice(self, t): - if self.reslice is None: - return - self.reslice.Update() - matrix = self.reslice.GetResliceAxes() - # move the center point that we are slicing through - center = matrix.MultiplyPoint((0, 0, t, 1)) - matrix.SetElement(0, 3, center[0]) - matrix.SetElement(1, 3, center[1]) - matrix.SetElement(2, 3, center[2]) - self.slice_actor.SetPosition(center[0], center[1], center[2]) - self.iren.Render() - - def ExtractRotMat(self, mat): - res = [[0, 0, 0], [0, 0, 0], [0, 0, 0]] - for i in range(3): - for j in range(3): - res[i][j] = mat.GetElement(i, j) - return res - - def R2Eul(self, R, tolerance=1e-5): - """ - R must be an indexable of shape (3,3) and represent and ORTHOGONAL POSITIVE - DEFINITE matrix. Otherwise, one should use GetEul(). - """ - from np.linalg import det - - fuzz = 1e-3 - R = np.asarray(R, float) - if det(R) < 0.0: - raise Exception("determinant is negative\n" + str(R)) - if not np.allclose(np.mat(R) * R.T, np.identity(3), atol=tolerance): - raise Exception("not an orthogonal matrix\n" + str(R)) - cang = 2.0 - np.sum(np.square([R[0, 2], R[1, 2], R[2, 0], R[2, 1], R[2, 2]])) - cang = np.sqrt(min(max(cang, 0.0), 1.0)) - if R[2, 2] < 0.0: - cang = -cang - ang = np.arccos(cang) - beta = np.degrees(ang) - sang = np.sin(ang) - if sang > fuzz: - alpha = np.degrees(np.arctan2(R[1, 2], R[0, 2])) - gamma = np.degrees(np.arctan2(R[2, 1], -R[2, 0])) - else: - alpha = np.degrees(np.arctan2(-R[0, 1], R[0, 0] * R[2, 2])) - gamma = 0.0 - if self.almost(beta, 0.0, fuzz): - alpha, beta, gamma = alpha + gamma, 0.0, 0.0 - elif self.almost(beta, 180.0, fuzz): - alpha, beta, gamma = alpha - gamma, 180.0, 0.0 - alpha = np.mod(alpha, 360.0) - gamma = np.mod(gamma, 360.0) - if self.almost(alpha, 360.0, fuzz): - alpha = 0.0 - if self.almost(gamma, 360.0, fuzz): - gamma = 0.0 - return alpha, beta, gamma - - def almost(self, a, b, tolerance=1e-7): - return abs(a - b) < tolerance - - def RotaEuler(self, acteur, alpha, beta, gamma): - acteur.RotateWXYZ(gamma, 0, 0, 1) - acteur.RotateWXYZ(beta, 0, 1, 0) - acteur.RotateWXYZ(alpha, 0, 0, 1) - - def Screen_shot(self, event=None): - windowToImageFilter = vtk.vtkWindowToImageFilter() - windowToImageFilter.SetInput(self.iren.GetRenderWindow()) - windowToImageFilter.SetMagnification( - 3 - ) # set the resolution of the output image (3 times the current resolution of vtk render window) - windowToImageFilter.SetInputBufferTypeToRGBA() # also record the alpha (transparency) channel - windowToImageFilter.Update() - - dlg = wx.FileDialog( - self, - "Save Figure as...", - os.getcwd(), - "", - "*.png", - wx.SAVE | wx.OVERWRITE_PROMPT, - ) - result = dlg.ShowModal() - inFile = dlg.GetPath() - dlg.Destroy() - if ( - result == wx.ID_CANCEL - ): # Either the cancel button was pressed or the window was closed - return - writer = vtk.vtkPNGWriter() - writer.SetFileName(inFile) - writer.SetInputConnection(windowToImageFilter.GetOutputPort()) - writer.Write() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/PlotterData.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/PlotterData.py deleted file mode 100644 index d3d32dc358..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/PlotterData.py +++ /dev/null @@ -1,81 +0,0 @@ -import abc -import collections - -import numpy as np - -import netCDF4 - -import h5py - -from MDANSE.Core.Decorators import compatibleabstractproperty -from MDANSE.IO.NetCDF import find_numeric_variables as netcdf_find_numeric_variables -from MDANSE.IO.HDF5 import find_numeric_variables as hdf_find_numeric_variables - - -class _IPlotterData(metaclass=abc.ABCMeta): - """ - This is the interface for plotter data. - - Plotter data are data supported by the plotter. Currently, only NetCDF is supported but HDF should be supported soon. - """ - - @abc.abstractmethod - def __init__(self): - self._file = None - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - self.close() - - @compatibleabstractproperty - def variables(self): - pass - - def close(self): - """Close the data.""" - self._file.close() - - -class NetCDFPlotterData(_IPlotterData): - """This class implements the plotter data interface for NetCDF data.""" - - def __init__(self, *args, **kwargs): - """Constructor. It takes any arguments that can be passed to netCDF4.Dataset to create an instance of it.""" - - self._file = netCDF4.Dataset(*args, **kwargs) - - self._variables = netcdf_find_numeric_variables( - collections.OrderedDict(), self._file - ) - - @property - def variables(self): - return self._variables - - -class HDFPlotterData(_IPlotterData): - """This class implements the plotter data interface for HDF data.""" - - def __init__(self, *args, **kwargs): - """Constructor. It takes any arguments that can be passed to HDF.File to create an instance of it.""" - - self._file = h5py.File(*args, **kwargs) - - self._variables = collections.OrderedDict() - - hdf_find_numeric_variables(self._variables, self._file) - - @property - def variables(self): - return self._variables - - -PLOTTER_DATA_TYPES = { - ".nc": NetCDFPlotterData, - ".cdf": NetCDFPlotterData, - ".netcdf": NetCDFPlotterData, - ".hdf": HDFPlotterData, - ".h5": HDFPlotterData, -} diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/PlotterPlugin.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/PlotterPlugin.py deleted file mode 100644 index 076ab2ddb6..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/PlotterPlugin.py +++ /dev/null @@ -1,640 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/PlotterPlugin.py -# @brief Implements module/class/test PlotterPlugin -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import collections -import os - -import numpy as np - -from matplotlib.figure import Figure -from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg - -import wx -import wx.aui as wxaui - -from MDANSE import REGISTRY -from MDANSE.Core.Error import Error -from MDANSE.GUI.Plugins.ComponentPlugin import ComponentPlugin -from MDANSE.GUI.Plugins.PlotterData import PLOTTER_DATA_TYPES -from MDANSE.GUI.Plugins.Plotter1D import Plotter1D -from MDANSE.GUI.Plugins.Plotter2D import Plotter2D -from MDANSE.GUI.Plugins.Plotter3D import Plotter3D -from MDANSE.GUI.Icons import ICONS -from MDANSE.IO.IOUtils import load_variables - - -class PlotterError(Error): - pass - - -class PlotterPanel(wx.Panel): - def __init__(self, parent): - wx.Panel.__init__(self, parent, wx.ID_ANY) - self.parent = parent - self._mgr = wxaui.AuiManager(self) - - self.build_panel() - self.build_layout() - - @property - def dataproxy(self): - return self.parent._data - - @property - def active_plot(self): - try: - page = self.plot_notebook.GetPage(self.plot_notebook.GetSelection()) - return page - except: - return None - - def build_panel(self): - self.plot_notebook = wxaui.AuiNotebook(self) - - def build_layout(self): - self._mgr.AddPane( - self.plot_notebook, - wxaui.AuiPaneInfo() - .Center() - .Dock() - .CloseButton(False) - .Caption("Multiple Plot Window"), - ) - self._mgr.Update() - - -class MultiViewPanel(wx.Panel): - def __init__(self, parent): - wx.Panel.__init__(self, parent, wx.ID_ANY) - self.parent = parent - - self.type = "image" - - self.unique_slicer = None - self.related_slicer_checkbox = None - - self._mgr = wxaui.AuiManager(self) - self.Layout() - - @property - def dataproxy(self): - return self.parent.dataproxy - - def AddPane(self, *args, **kwds): - self._mgr.AddPane(*args, **kwds) - - def Update(self): - self._mgr.Update() - - -class DataPanel(wx.Panel): - def __init__(self, parent, *args, **kwds): - wx.Panel.__init__(self, parent, *args, **kwds) - self.parent = parent - self._mgr = wxaui.AuiManager(self) - - self.selectedVar = None - self.activePlot = None - self.selectedPlot = None - - self.unique_slicer = None - self.related_slicer_checkbox = None - - self.build_panel() - - def build_panel(self): - self.setup = wx.Panel(self) - - self._dataPanelSizer = wx.BoxSizer(wx.VERTICAL) - - if self.standalone: - splitterWindow = wx.SplitterWindow(self.setup, style=wx.SP_LIVE_UPDATE) - splitterWindow.SetMinimumPaneSize(50) - - self.datasetlist = wx.ListCtrl( - splitterWindow, wx.ID_ANY, style=wx.LC_REPORT | wx.LC_SINGLE_SEL - ) - self.datasetlist.InsertColumn(0, "key", width=100) - self.datasetlist.InsertColumn(1, "filename", width=100) - self.datasetlist.InsertColumn(2, "path", width=500) - - self.Bind( - wx.EVT_LIST_ITEM_SELECTED, self.on_select_dataset, self.datasetlist - ) - self.Bind(wx.EVT_LIST_KEY_DOWN, self.delete_dataset, self.datasetlist) - - self.datalist = wx.ListCtrl( - splitterWindow, wx.ID_ANY, style=wx.LC_REPORT | wx.LC_SINGLE_SEL - ) - else: - self.datalist = wx.ListCtrl( - self.setup, wx.ID_ANY, style=wx.LC_REPORT | wx.LC_SINGLE_SEL - ) - - self.datalist.InsertColumn(0, "Variable", width=100) - self.datalist.InsertColumn(1, "Axis", width=50) - self.datalist.InsertColumn(2, "Dimension") - self.datalist.InsertColumn(3, "Size") - self.datalist.InsertColumn(4, "Path", width=100) - - if self.standalone: - splitterWindow.SplitHorizontally(self.datasetlist, self.datalist) - - self._plotTypeSizer = wx.BoxSizer(wx.HORIZONTAL) - - self.plot_type_label = wx.StaticText(self.setup, label="Select Plotter") - self.plotter_list = { - "Line": 1, - "Image": 2, - "Elevation": 2, - "2D Slice": 3, - "Iso-Surface": 3, - "Scalar-Field": 3, - } - self.plot_type = wx.ComboBox(self.setup, style=wx.CB_READONLY) - - self._plotTypeSizer.Add(self.plot_type_label, 0, wx.ALIGN_CENTER_VERTICAL) - self._plotTypeSizer.Add(self.plot_type, 1, wx.ALIGN_CENTER_VERTICAL) - - self._2DSliceSizer = wx.BoxSizer(wx.HORIZONTAL) - dimText = wx.StaticText(self.setup, label="Dim:") - self._selectedDimension = wx.SpinCtrl( - self.setup, id=wx.ID_ANY, style=wx.SP_WRAP | wx.SP_ARROW_KEYS - ) - self._selectedDimension.SetRange(0, 2) - sliceText = wx.StaticText(self.setup, label="Slice:") - self._selectedSlice = wx.SpinCtrl( - self.setup, id=wx.ID_ANY, style=wx.SP_WRAP | wx.SP_ARROW_KEYS - ) - self._2DSliceSizer.Add(dimText, 0, wx.CENTER | wx.ALL, 2) - self._2DSliceSizer.Add(self._selectedDimension, 0, wx.ALL, 2) - self._2DSliceSizer.Add(sliceText, 0, wx.CENTER | wx.ALL, 2) - self._2DSliceSizer.Add(self._selectedSlice, 0, wx.ALL, 2) - - self._plotSizer = wx.BoxSizer(wx.HORIZONTAL) - - self.plot_button = wx.Button(self.setup, wx.ID_ANY, label="Plot in new window") - self.replot_button = wx.Button( - self.setup, wx.ID_ANY, label="Plot in current figure" - ) - - self._plotSizer.Add(self.plot_button, 1, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND) - self._plotSizer.Add(self.replot_button, 1, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND) - - if self.standalone: - self._dataPanelSizer.Add(splitterWindow, 2, wx.ALL | wx.EXPAND, 2) - else: - self._dataPanelSizer.Add(self.datalist, 2, wx.ALL | wx.EXPAND, 2) - self._dataPanelSizer.Add(self._plotTypeSizer, 0, wx.ALL | wx.EXPAND, 2) - self._dataPanelSizer.Add(self._2DSliceSizer, 0, wx.ALL | wx.EXPAND, 2) - self._dataPanelSizer.Add(self._plotSizer, 0, wx.ALL | wx.EXPAND, 2) - - self.setup.SetSizer(self._dataPanelSizer) - self._dataPanelSizer.Fit(self.setup) - self.setup.Layout() - - qviewPanel = wx.Panel(self) - sb_sizer2 = wx.BoxSizer(wx.VERTICAL) - - self.qvFigure = Figure(figsize=(1, 1)) - self.qvCanvas = FigureCanvasWxAgg(qviewPanel, wx.ID_ANY, self.qvFigure) - self.qvPlot = self.qvFigure.add_axes([0.01, 0.01, 0.98, 0.98]) - sb_sizer2.Add(self.qvCanvas, 1, wx.ALL | wx.EXPAND, 2) - - qviewPanel.SetSizer(sb_sizer2) - sb_sizer2.Fit(qviewPanel) - qviewPanel.Layout() - - self._mgr.AddPane( - qviewPanel, - wxaui.AuiPaneInfo() - .Dock() - .Bottom() - .Floatable(False) - .CloseButton(False) - .Caption("Quick View") - .MinSize((300, 300)) - .BestSize((300, 300)), - ) - self._mgr.AddPane( - self.setup, - wxaui.AuiPaneInfo() - .Dock() - .Center() - .Floatable(False) - .CloseButton(False) - .Caption("Data"), - ) - - self._mgr.Update() - self._mgr.GetPane(qviewPanel).MinSize((100, 100)) - self._mgr.Update() - - self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.on_select_variables, self.datalist) - self.Bind(wx.EVT_BUTTON, self.on_plot, self.plot_button) - self.Bind(wx.EVT_BUTTON, self.on_replot, self.replot_button) - self.Bind(wx.EVT_COMBOBOX, self.on_select_plot_type, self.plot_type) - self.Bind(wx.EVT_SPINCTRL, self.on_change_dimension, self._selectedDimension) - - @property - def dataDict(self): - if self.standalone: - return self.parent._dataDict - else: - return None - - @property - def standalone(self): - return self.parent.standalone - - @property - def dataproxy(self): - return self.parent._data - - @property - def plotterPanel(self): - return self.parent._plotterPanel - - @property - def plotterNotebook(self): - return self.parent._plotterPanel.plot_notebook - - def delete_dataset(self, event): - keycode = event.GetKeyCode() - if keycode == wx.WXK_DELETE: - dataset = self.datasetlist.GetItemText(self.datasetlist.GetFocusedItem()) - self.dataDict.pop(dataset) - self.datasetlist.DeleteItem(self.datasetlist.GetFocusedItem()) - self.datalist.DeleteAllItems() - self.datasetlist.Select(0, 1) - - def on_change_dimension(self, event): - if self.plot_type.GetValue() != "2D Slice": - return - - if self.selectedVar is None: - return - selectedDim = self._selectedDimension.GetValue() - data = self.dataproxy[self.selectedVar]["data"] - self._selectedSlice.SetRange(0, data.shape[selectedDim] - 1) - - def on_select_dataset(self, event): - if event is None: - return - currentItem = event.GetItem() - var = currentItem.GetText() - self.parent._data = self.dataDict[var]["data"] - self.show_data() - - def on_select_plot_type(self, event): - if self.plot_type.GetValue() == "2D Slice": - self._dataPanelSizer.Show(self._2DSliceSizer) - else: - self._dataPanelSizer.Hide(self._2DSliceSizer) - self._dataPanelSizer.Layout() - - def show_dataset(self, index=0): - self.datasetlist.DeleteAllItems() - for i, k in enumerate(self.dataDict.keys()): - self.datasetlist.InsertItem(i, k) - self.datasetlist.SetItem(i, 1, self.dataDict[k]["basename"]) - self.datasetlist.SetItem(i, 2, self.dataDict[k]["path"]) - self.datasetlist.Select(index, True) - - def show_data(self): - self.datalist.DeleteAllItems() - variables = list(self.dataproxy.keys()) - for i, var in enumerate(sorted(variables)): - self.datalist.InsertItem(i, var) - axis = ",".join(self.dataproxy[var]["axis"]) - self.datalist.SetItem(i, 1, axis) - self.datalist.SetItem(i, 2, str(self.dataproxy[var]["data"].ndim)) - self.datalist.SetItem(i, 3, str(self.dataproxy[var]["data"].shape)) - self.datalist.SetItem(i, 4, self.dataproxy[var]["path"]) - self.datalist.Select(0, True) - - def on_select_variables(self, event=None): - if event is None: - return - currentItem = event.GetItem() - var = currentItem.GetText() - data = self.dataproxy[var]["data"] - ndim = data.ndim - self.plot_type.Clear() - types = [] - for _type, req_dim in list(self.plotter_list.items()): - if ndim == req_dim: - types += [_type] - self.plot_type.SetItems(types) - if not self.plot_type.IsEmpty(): - self.plot_type.SetStringSelection(types[-1]) - - self.selectedVar = var - self.on_change_dimension(None) - self.on_select_plot_type(None) - self.plot_quickview(data) - - def plot_quickview(self, data): - self.qvPlot.clear() - ndim = data.ndim - - if ndim == 1: - self.qvPlot.plot(data) - self.qvFigure.gca().legend( - (self.selectedVar, None), - loc="best", - frameon=True, - shadow=True, - fancybox=False, - ) - elif ndim == 2: - self.qvPlot.imshow(data.T, interpolation="nearest", origin="lower") - - else: - self.qvPlot.text(0.1, 0.5, "No QuickView for data with dimension > 2 ") - self.qvPlot.set_aspect("auto") - - self.qvCanvas.draw() - - def on_plot(self, event=None): - if self.selectedVar is None: - return - - data = self.dataproxy[self.selectedVar]["data"] - plot_type = self.plot_type.GetValue() - if plot_type == "Line": - Plotter = Plotter1D(self) - self.plotterNotebook.AddPage( - Plotter, "%s(%s)" % (self.selectedVar, plot_type) - ) - Plotter.plot(data, self.selectedVar) - - elif plot_type == "Image": - Plotter = Plotter2D(self) - self.plotterNotebook.AddPage( - Plotter, "%s(%s)" % (self.selectedVar, plot_type) - ) - Plotter.plot(data, self.selectedVar) - - elif plot_type == "2D Slice": - Plotter = Plotter2D(self) - self.plotterNotebook.AddPage( - Plotter, "%s(%s)" % (self.selectedVar, plot_type) - ) - dim = self._selectedDimension.GetValue() - slice = self._selectedSlice.GetValue() - if dim == 0: - Plotter.plot(data[slice, :, :], self.selectedVar) - elif dim == 1: - Plotter.plot(data[:, slice, :], self.selectedVar) - elif dim == 2: - Plotter.plot(data[:, :, slice], self.selectedVar) - - elif plot_type == "Elevation": - Plotter = Plotter3D(self.parent) - self.plotterNotebook.AddPage( - Plotter, "%s(%s)" % (self.selectedVar, plot_type) - ) - Plotter.elevation(data) - - elif plot_type == "Iso-Surface": - Plotter = Plotter3D(self.parent) - self.plotterNotebook.AddPage( - Plotter, "%s(%s)" % (self.selectedVar, plot_type) - ) - Plotter.isosurface(data, data.mean(), "w") - - elif plot_type == "Scalar-Field": - Plotter = Plotter3D(self.parent) - self.plotterNotebook.AddPage( - Plotter, "%s(%s)" % (self.selectedVar, plot_type) - ) - Plotter.scalarfield(data) - else: - raise PlotterError("Unrecognized plotter type : %s" % plot_type) - - def on_replot(self, event=None): - self.selectedPlot = self.plotterPanel.active_plot - - if self.selectedPlot is None: - return - - plot_type = self.plot_type.GetValue() - if plot_type == "Line" and self.selectedPlot.type == "line": - data = self.dataproxy[self.selectedVar]["data"] - self.selectedPlot.plot(data, self.selectedVar) - - if plot_type == "Image" and self.selectedPlot.type == "image": - data = self.dataproxy[self.selectedVar]["data"] - if hasattr(self.selectedPlot, "AddPane"): - Plotter = Plotter2D(self.selectedPlot) - Plotter.plot(data, self.selectedVar) - self.selectedPlot.AddPane( - Plotter, - wxaui.AuiPaneInfo() - .Right() - .CloseButton(True) - .CaptionVisible(True) - .Caption(self.selectedVar) - .MinSize((200, -1)), - ) - self.selectedPlot.Update() - else: - li_idx = self.plotterNotebook.GetPageIndex(self.selectedPlot) - - multiplot = MultiViewPanel(self) - - NewPlotter = Plotter2D(multiplot) - NewPlotter.plot(data, self.selectedVar) - - OldPlotter = Plotter2D(multiplot) - OldPlotter.replot(self.selectedPlot) - - multiplot.AddPane( - NewPlotter, - wxaui.AuiPaneInfo() - .Right() - .CloseButton(True) - .CaptionVisible(True) - .Caption(self.selectedVar) - .MinSize((200, -1)), - ) - multiplot.AddPane( - OldPlotter, - wxaui.AuiPaneInfo() - .Center() - .CloseButton(True) - .CaptionVisible(True) - .Caption(self.selectedPlot.varname), - ) - multiplot.Update() - - self.selectedPlot.Destroy() - self.selectedPlot = None - self.plotterNotebook.RemovePage(li_idx) - self.plotterNotebook.AddPage( - multiplot, "*MultiView*(Image)", select=True - ) - - -class PlotterPlugin(ComponentPlugin): - label = "2D/3D Plotter" - - ancestor = ["netcdf_data"] - - category = ("Plotter",) - - def __init__(self, parent, mode="embeded"): - self.standalone = False - - if mode == "standalone": - self.make_standalone() - - ComponentPlugin.__init__(self, parent) - - def build_panel(self): - self._dataPanel = DataPanel(self) - self._plotterPanel = PlotterPanel(self) - - self._mgr.AddPane( - self._dataPanel, - wxaui.AuiPaneInfo() - .Dock() - .Left() - .Floatable(False) - .CloseButton(False) - .CaptionVisible(False) - .MinSize((300, -1)), - ) - self._mgr.AddPane( - self._plotterPanel, - wxaui.AuiPaneInfo() - .Center() - .Dock() - .Floatable(False) - .CloseButton(False) - .CaptionVisible(False), - ) - - def make_standalone(self): - self.standalone = True - self._dataDict = collections.OrderedDict() - - def plug(self): - self._data = self.dataproxy.data - self._dataPanel.show_data() - - self._parent._mgr.GetPane(self).Dock().Floatable(False).Center().CloseButton( - True - ).Caption("2D/3D Plotter") - self._parent._mgr.Update() - - -class PlotterFrame(wx.Frame): - def __init__(self, parent, title="2D/3D Plotter"): - wx.Frame.__init__( - self, - parent, - wx.ID_ANY, - title, - style=wx.DEFAULT_FRAME_STYLE - | wx.MINIMIZE_BOX - | wx.MAXIMIZE_BOX - | wx.RESIZE_BORDER, - ) - self.__build_dialog() - self.__build_menu() - - def __build_menu(self): - mainMenu = wx.MenuBar() - fileMenu = wx.Menu() - loadData = fileMenu.Append(wx.ID_ANY, "Load") - - mainMenu.Append(fileMenu, "File") - - icon = wx.Icon() - icon.CopyFromBitmap(ICONS["plot", 32, 32]) - self.SetIcon(icon) - - self.SetMenuBar(mainMenu) - - self.Bind(wx.EVT_MENU, self.on_load_data, loadData) - self.Bind(wx.EVT_CLOSE, self.on_close, self) - - def on_close(self, event=None): - self.plugin._dataPanel._mgr.UnInit() - self.plugin._plotterPanel._mgr.UnInit() - self.plugin._mgr.UnInit() - self.Destroy() - - def on_load_data(self, event=None): - filters = ( - "NetCDF and HDF files (*.nc;*.netcdf;*.h5;*.hdf)|*.nc;*.netcdf;*.h5;*.hdf|" - "NetCDF file (*.nc)|*.nc|HDF file (*.h5)|*.h5|All files (*.*)|*.*" - ) - dialog = wx.FileDialog( - self, message="Open file...", wildcard=filters, style=wx.FD_MULTIPLE - ) - if dialog.ShowModal() == wx.ID_CANCEL: - return - - baselist = dialog.GetFilenames() - filelist = dialog.GetPaths() - - for basename, filename in zip(baselist, filelist): - ext = os.path.splitext(filename)[1] - with PLOTTER_DATA_TYPES[ext](filename, "r") as f: - data = load_variables(f.variables) - - unique_name = self.unique(basename, self.plugin._dataDict) - - self.plugin._dataDict[unique_name] = { - "data": data, - "path": filename, - "basename": basename, - } - self.plugin._dataPanel.show_dataset(-1) - - def unique(self, key, dic): - skey = key - i = 0 - while key in list(dic.keys()): - key = skey + "_%d" % i - i += 1 - return key - - def __build_dialog(self): - mainPanel = wx.Panel(self, wx.ID_ANY) - - mainSizer = wx.BoxSizer(wx.VERTICAL) - - self.plugin = PlotterPlugin(mainPanel, "standalone") - - mainSizer.Add(self.plugin, 1, wx.ALL | wx.EXPAND, 5) - - mainPanel.SetSizer(mainSizer) - mainSizer.Fit(mainPanel) - mainPanel.Layout() - - self.SetSize((1000, 700)) - - -REGISTRY["plotter"] = PlotterPlugin - -if __name__ == "__main__": - app = wx.App(False) - f = PlotterFrame(None) - f.Show() - app.MainLoop() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/PlotterSettings.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/PlotterSettings.py deleted file mode 100644 index e576060e17..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/PlotterSettings.py +++ /dev/null @@ -1,836 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/PlotterSettings.py -# @brief Implements module/class/test PlotterSettings -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import matplotlib - -import wx -from MDANSE.Core.Error import Error -from MDANSE.Framework.Units import UnitError, measure - - -class UnitsSettingsError(Error): - pass - - -class UnitsSettingsDialog: - def checkUnits(self, oldUnit, newUnit): - if oldUnit != newUnit: - try: - m = measure(1.0, oldUnit, equivalent=True) - m.toval(newUnit) - except UnitError: - raise UnitsSettingsError( - "the axis unit (%s) is inconsistent with the current unit (%s) " - % (newUnit, oldUnit) - ) - - -class ImageSettingsDialog(wx.Dialog, UnitsSettingsDialog): - def __init__(self, parent=None): - wx.Dialog.__init__( - self, - parent, - wx.ID_ANY, - title="Image Settings", - style=wx.DEFAULT_DIALOG_STYLE - | wx.RESIZE_BORDER - | wx.MINIMIZE_BOX - | wx.MAXIMIZE_BOX, - ) - self.parent = parent - self.build_dialog() - - def build_dialog(self): - self.norm_choices = ["none", "log"] - self.aspect_choices = ["equal", "auto"] - self.interpolation_choices = [ - "none", - "nearest", - "bilinear", - "bicubic", - "spline16", - "spline36", - "hanning", - "hamming", - "hermite", - "kaiser", - "quadric", - "catrom", - "gaussian", - "bessel", - "mitchell", - "sinc", - "lanczos", - ] - - Sizer = wx.BoxSizer(wx.VERTICAL) - - sb = wx.StaticBox(self, wx.ID_ANY, label="Label") - sbsizer = wx.StaticBoxSizer(sb, wx.VERTICAL) - - gbSizer = wx.GridBagSizer(5, 5) - - self.title_label = wx.StaticText( - self, label="Title", style=wx.ALIGN_CENTER_VERTICAL - ) - self.title = wx.TextCtrl( - self, wx.ID_ANY, style=wx.SL_HORIZONTAL | wx.TE_PROCESS_ENTER - ) - - self.Xlabel_label = wx.StaticText( - self, label="X Axis", style=wx.ALIGN_CENTER_VERTICAL - ) - self.Xlabel = wx.TextCtrl( - self, wx.ID_ANY, style=wx.SL_HORIZONTAL | wx.TE_PROCESS_ENTER - ) - - self.Ylabel_label = wx.StaticText( - self, label="Y Axis", style=wx.ALIGN_CENTER_VERTICAL - ) - self.Ylabel = wx.TextCtrl( - self, wx.ID_ANY, style=wx.SL_HORIZONTAL | wx.TE_PROCESS_ENTER - ) - - gbSizer.Add(self.title_label, (0, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer.Add(self.title, (0, 1), flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND) - gbSizer.Add(self.Xlabel_label, (1, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer.Add(self.Xlabel, (1, 1), flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND) - gbSizer.Add(self.Ylabel_label, (2, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer.Add(self.Ylabel, (2, 1), flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND) - - gbSizer.AddGrowableCol(1) - - sbsizer.Add(gbSizer, 0, wx.EXPAND, 5) - - Sizer.Add(sbsizer, 0, wx.EXPAND) - - gbSizer2 = wx.GridBagSizer(5, 5) - - hsizer = wx.BoxSizer(wx.HORIZONTAL) - - sb2 = wx.StaticBox(self, wx.ID_ANY, label="Aspect") - sbsizer2 = wx.StaticBoxSizer(sb2, wx.VERTICAL) - - self.aspect_label = wx.StaticText( - self, label="Proportions", style=wx.ALIGN_CENTER_VERTICAL - ) - self.aspect = wx.ComboBox( - self, id=wx.ID_ANY, choices=self.aspect_choices, style=wx.CB_READONLY - ) - - self.interpolation_label = wx.StaticText( - self, label="Interpolation", style=wx.ALIGN_CENTER_VERTICAL - ) - self.interpolation = wx.ComboBox( - self, id=wx.ID_ANY, choices=self.interpolation_choices, style=wx.CB_READONLY - ) - - self.norm_label = wx.StaticText( - self, label="Scale", style=wx.ALIGN_CENTER_VERTICAL - ) - self.normType = wx.ComboBox( - self, id=wx.ID_ANY, choices=self.norm_choices, style=wx.CB_READONLY - ) - self.normType.SetValue(self.norm_choices[0]) - - gbSizer2.Add(self.aspect_label, (0, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer2.Add(self.aspect, (0, 2), flag=wx.ALIGN_CENTER_VERTICAL) - - gbSizer2.Add(self.interpolation_label, (1, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer2.Add(self.interpolation, (1, 2), flag=wx.ALIGN_CENTER_VERTICAL) - - gbSizer2.Add(self.norm_label, (2, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer2.Add(self.normType, (2, 2), flag=wx.ALIGN_CENTER_VERTICAL) - - sbsizer2.Add(gbSizer2, 0, wx.ALIGN_CENTER_VERTICAL, 0) - - gbSizer1 = wx.GridBagSizer(5, 5) - - sb1 = wx.StaticBox(self, wx.ID_ANY, label="Units") - sbsizer1 = wx.StaticBoxSizer(sb1, wx.VERTICAL) - - self.X_label = wx.StaticText(self, label="X", style=wx.ALIGN_CENTER_VERTICAL) - - self.Xunit = wx.TextCtrl( - self, wx.ID_ANY, style=wx.SL_HORIZONTAL | wx.TE_PROCESS_ENTER - ) - - self.Y_label = wx.StaticText(self, label="Y", style=wx.ALIGN_CENTER_VERTICAL) - - self.Yunit = wx.TextCtrl( - self, wx.ID_ANY, style=wx.SL_HORIZONTAL | wx.TE_PROCESS_ENTER - ) - - gbSizer1.Add(self.X_label, (0, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer1.Add(self.Xunit, (0, 2), flag=wx.ALIGN_CENTER_VERTICAL) - - gbSizer1.Add(self.Y_label, (1, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer1.Add(self.Yunit, (1, 2), flag=wx.ALIGN_CENTER_VERTICAL) - - sbsizer1.Add(gbSizer1, 0, wx.EXPAND, 5) - - hsizer.Add(sbsizer2, 0, wx.EXPAND) - hsizer.Add(sbsizer1, 0, wx.EXPAND) - - Sizer.Add(hsizer, 0, wx.EXPAND) - - hsizer1 = wx.BoxSizer(wx.HORIZONTAL) - self.apply_button = wx.Button(self, wx.ID_ANY, label="Apply") - hsizer1.Add(self.apply_button, 0, wx.EXPAND, 0) - - Sizer.Add(hsizer1, 0, wx.ALIGN_RIGHT | wx.RIGHT | wx.ALL, 5) - - self.SetSizer(Sizer) - Sizer.Fit(self) - self.Layout() - - self.Bind(wx.EVT_BUTTON, self.set_settings, self.apply_button) - - self.get_settings() - - def get_settings(self, event=None): - self.title.SetValue(self.parent.figure.gca().get_title()) - self.Xlabel.SetValue(self.parent.Xlabel) - self.Ylabel.SetValue(self.parent.Ylabel) - - self.Xunit.SetValue(str(self.parent.Xunit)) - self.Yunit.SetValue(str(self.parent.Yunit)) - - self.aspect.SetValue(self.parent.figure.gca().get_aspect()) - self.interpolation.SetValue(self.parent.interpolation) - self.normType.SetValue(self.parent.normType) - - def set_settings(self, event=None): - self.checkUnits(self.parent.Xunit, self.Xunit.GetValue()) - self.checkUnits(self.parent.Yunit, self.Yunit.GetValue()) - - self.parent.figure.gca().set_title(self.title.GetValue()) - self.parent.Xlabel = self.Xlabel.GetValue() - self.parent.Ylabel = self.Ylabel.GetValue() - - if ( - self.parent.Xunit != self.Xunit.GetValue() - or self.parent.Yunit != self.Yunit.GetValue() - ): - self.parent.Xunit = self.Xunit.GetValue() - self.parent.Yunit = self.Yunit.GetValue() - self.parent.set_ticks() - self.parent.reset_axis() - - self.parent.figure.gca().set_xlabel(self.parent.Xlabel + self.parent.fmt_Xunit) - self.parent.figure.gca().set_ylabel(self.parent.Ylabel + self.parent.fmt_Yunit) - - self.parent.aspect = self.aspect.GetValue() - self.parent.interpolation = self.interpolation.GetValue() - self.parent.normType = self.normType.GetValue() - - self.parent.figure.gca().set_aspect(self.parent.aspect) - self.parent.ax.set_interpolation(self.parent.interpolation) - - self.parent.scale(True) - self.parent.color_bar.update_normal(self.parent.ax) - self.parent.canvas.draw() - - -class GeneralSettingsDialog(wx.Dialog): - def __init__(self, parent=None): - wx.Dialog.__init__( - self, - parent, - wx.ID_ANY, - title="General Settings", - style=wx.DEFAULT_DIALOG_STYLE - | wx.RESIZE_BORDER - | wx.MINIMIZE_BOX - | wx.MAXIMIZE_BOX, - ) - self.parent = parent - self.build_dialog() - - def build_dialog(self): - self.legend_location_choice = [ - "best", - "upper right", - "upper left", - "lower left", - "lower right", - "right", - "center left", - "center right", - "lower center", - "upper center", - "center", - ] - self.style_choice = ["-", "--", "-.", ":", "None"] - - Sizer = wx.BoxSizer(wx.VERTICAL) - - sb = wx.StaticBox(self, wx.ID_ANY, label="Label") - sbsizer0 = wx.StaticBoxSizer(sb, wx.VERTICAL) - - gbSizer0 = wx.GridBagSizer(5, 5) - - self.title_label = wx.StaticText( - self, label="Title", style=wx.ALIGN_CENTER_VERTICAL - ) - self.title = wx.TextCtrl( - self, wx.ID_ANY, style=wx.SL_HORIZONTAL | wx.TE_PROCESS_ENTER - ) - - self.Xlabel_label = wx.StaticText( - self, label="X Axis", style=wx.ALIGN_CENTER_VERTICAL - ) - self.Xlabel = wx.TextCtrl( - self, wx.ID_ANY, style=wx.SL_HORIZONTAL | wx.TE_PROCESS_ENTER - ) - - self.Ylabel_label = wx.StaticText( - self, label="Y Axis", style=wx.ALIGN_CENTER_VERTICAL - ) - self.Ylabel = wx.TextCtrl( - self, wx.ID_ANY, style=wx.SL_HORIZONTAL | wx.TE_PROCESS_ENTER - ) - - gbSizer0.Add(self.title_label, (0, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer0.Add(self.title, (0, 1), flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND) - gbSizer0.Add(self.Xlabel_label, (1, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer0.Add(self.Xlabel, (1, 1), flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND) - gbSizer0.Add(self.Ylabel_label, (2, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer0.Add(self.Ylabel, (2, 1), flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND) - - gbSizer0.AddGrowableCol(1) - - sbsizer0.Add(gbSizer0, 1, wx.EXPAND, 5) - - sb = wx.StaticBox(self, wx.ID_ANY, label="Legend") - sbsizer1 = wx.StaticBoxSizer(sb, wx.VERTICAL) - - self.show_legend = wx.CheckBox(self, id=wx.ID_ANY, label="Show") - - hsizer3 = wx.BoxSizer(wx.HORIZONTAL) - self.legend_location_label = wx.StaticText( - self, label="Location", style=wx.ALIGN_CENTER_VERTICAL - ) - self.legend_location = wx.ComboBox( - self, - id=wx.ID_ANY, - choices=self.legend_location_choice, - style=wx.CB_READONLY, - ) - self.legend_location.SetValue(self.legend_location_choice[0]) - self.legend_style_label = wx.StaticText( - self, label="Style", style=wx.ALIGN_CENTER_VERTICAL - ) - self.frame_on = wx.CheckBox(self, id=wx.ID_ANY, label="Frame on") - self.fancy_box = wx.CheckBox(self, id=wx.ID_ANY, label="Fancy box") - self.shadow = wx.CheckBox(self, id=wx.ID_ANY, label="Shadow") - - self.frame_on.SetValue(True) - self.fancy_box.SetValue(False) - self.shadow.SetValue(True) - - hsizer3.Add(self.legend_location_label, 0, wx.ALIGN_CENTER_VERTICAL, 0) - hsizer3.Add(self.legend_location, 1, wx.ALIGN_CENTER_VERTICAL, 0) - hsizer3.AddSpacer(20) - hsizer3.Add(self.legend_style_label, 0, wx.ALIGN_CENTER_VERTICAL, 0) - hsizer3.Add(self.frame_on, 0, wx.ALIGN_CENTER_VERTICAL, 0) - hsizer3.Add(self.fancy_box, 0, wx.ALIGN_CENTER_VERTICAL, 0) - hsizer3.Add(self.shadow, 0, wx.ALIGN_CENTER_VERTICAL, 0) - - sbsizer1.Add(self.show_legend, 0, wx.ALIGN_CENTER_VERTICAL, 0) - sbsizer1.Add(hsizer3, 0, wx.ALIGN_CENTER_VERTICAL, 0) - - sb = wx.StaticBox(self, wx.ID_ANY, label="Grid") - sbsizer2 = wx.StaticBoxSizer(sb, wx.VERTICAL) - - hsizer4 = wx.BoxSizer(wx.HORIZONTAL) - self.grid_syle_label = wx.StaticText( - self, label="Style", style=wx.ALIGN_CENTER_VERTICAL - ) - self.grid_style = wx.ComboBox( - self, id=wx.ID_ANY, choices=self.style_choice, style=wx.CB_READONLY - ) - - self.grid_style.SetValue(self.style_choice[-1]) - - self.grid_width_label = wx.StaticText( - self, label="Width", style=wx.ALIGN_CENTER_VERTICAL - ) - self.grid_width = wx.SpinCtrl(self, id=wx.ID_ANY, style=wx.SP_ARROW_KEYS) - - self.grid_color_label = wx.StaticText( - self, label="Color", style=wx.ALIGN_CENTER_VERTICAL - ) - self.grid_color_picker = wx.ColourPickerCtrl(self, id=wx.ID_ANY, col="black") - - hsizer4.Add(self.grid_syle_label, 0, wx.ALIGN_CENTER_VERTICAL, 0) - hsizer4.Add(self.grid_style, 1, wx.ALIGN_CENTER_VERTICAL, 0) - hsizer4.AddSpacer(20) - hsizer4.Add(self.grid_width_label, 0, wx.ALIGN_CENTER_VERTICAL, 0) - hsizer4.Add(self.grid_width, 1, wx.ALIGN_CENTER_VERTICAL, 0) - hsizer4.AddSpacer(20) - hsizer4.Add(self.grid_color_label, 0, wx.ALIGN_CENTER_VERTICAL, 0) - hsizer4.Add(self.grid_color_picker, 1, wx.ALIGN_CENTER_VERTICAL, 0) - - sbsizer2.Add(hsizer4, 0, wx.ALIGN_CENTER_VERTICAL, 0) - - hsizer5 = wx.BoxSizer(wx.HORIZONTAL) - self.apply_button = wx.Button(self, wx.ID_ANY, label="Apply") - hsizer5.Add( - self.apply_button, - 0, - wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.ALIGN_RIGHT, - 0, - ) - - Sizer.Add(sbsizer0, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) - Sizer.Add(sbsizer1, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) - Sizer.Add(sbsizer2, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) - Sizer.Add(hsizer5, 0, wx.ALIGN_RIGHT | wx.RIGHT | wx.ALL, 5) - - self.SetSizer(Sizer) - Sizer.Fit(self) - self.Layout() - - self.Bind(wx.EVT_BUTTON, self.set_settings, self.apply_button) - - self.get_settings() - - def get_settings(self, event=None): - self.title.SetValue(self.parent.figure.gca().get_title()) - self.Xlabel.SetValue(self.parent.Xlabel) - self.Ylabel.SetValue(self.parent.Ylabel) - self.show_legend.SetValue(self.parent.show_legend) - self.grid_style.SetValue(self.parent.gridStyle) - self.grid_width.SetValue(self.parent.gridWidth) - self.grid_color_picker.SetColour( - wx.Colour( - int(self.parent.gridColor[0] * 255), - int(self.parent.gridColor[1] * 255), - int(self.parent.gridColor[2] * 255), - ) - ) - - def set_settings(self, event=None): - self.parent.figure.gca().set_title(self.title.GetValue()) - self.parent.Xlabel = self.Xlabel.GetValue() - self.parent.Ylabel = self.Ylabel.GetValue() - - self.parent.figure.gca().set_xlabel(self.parent.Xlabel + self.parent.fmt_Xunit) - self.parent.figure.gca().set_ylabel(self.parent.Ylabel + self.parent.fmt_Yunit) - - if self.show_legend.GetValue(): - self.parent.show_legend = True - self.update_currentFig_legend() - else: - self.parent.show_legend = False - self.parent.figure.gca().legend_ = None - - self.update_currentFig_grid() - - self.parent.canvas.draw() - - def update_currentFig_legend(self): - self.parent.legend_location = self.legend_location.GetValue() - self.parent.legend_frameon = self.frame_on.GetValue() - self.parent.legend_shadow = self.shadow.GetValue() - self.parent.legend_fancybox = self.fancy_box.GetValue() - - self.parent.update_legend() - - self.parent.canvas.draw() - - def update_currentFig_grid(self): - style = self.grid_style.GetValue() - width = self.grid_width.GetValue() - color = self.grid_color_picker.GetColour() - rvb_color = (color.Red() / 255.0, color.Green() / 255.0, color.Blue() / 255.0) - - self.parent.gridStyle = style - self.parent.gridWidth = width - self.parent.gridColor = rvb_color - - self.parent.figure.gca().grid(True, linestyle=style) - self.parent.figure.gca().grid(True, linewidth=width) - self.parent.figure.gca().grid(True, color=rvb_color) - - self.parent.canvas.draw() - - -class AxesSettingsDialog(wx.Dialog, UnitsSettingsDialog): - def __init__(self, parent=None): - wx.Dialog.__init__( - self, - parent, - wx.ID_ANY, - title="Axes Settings", - style=wx.DEFAULT_DIALOG_STYLE - | wx.RESIZE_BORDER - | wx.MINIMIZE_BOX - | wx.MAXIMIZE_BOX, - ) - self.parent = parent - self.build_dialog() - - def build_dialog(self): - self.axis_scales_choices = ["linear", "symlog", "ln", "log 10", "log 2"] - - Sizer = wx.BoxSizer(wx.VERTICAL) - - hsizer0 = wx.BoxSizer(wx.HORIZONTAL) - - sb0 = wx.StaticBox(self, wx.ID_ANY, label="Bounds") - sbsizer0 = wx.StaticBoxSizer(sb0, wx.VERTICAL) - - gbSizer0 = wx.GridBagSizer(5, 5) - - self.Xmin_label = wx.StaticText( - self, label="X Min", style=wx.ALIGN_CENTER_VERTICAL - ) - self.Xmin = wx.TextCtrl( - self, wx.ID_ANY, style=wx.SL_HORIZONTAL | wx.TE_PROCESS_ENTER - ) - - self.Ymin_label = wx.StaticText( - self, label="Y Min", style=wx.ALIGN_CENTER_VERTICAL - ) - self.Ymin = wx.TextCtrl( - self, wx.ID_ANY, style=wx.SL_HORIZONTAL | wx.TE_PROCESS_ENTER - ) - - self.Xmax_label = wx.StaticText( - self, label="X Max", style=wx.ALIGN_CENTER_VERTICAL - ) - self.Xmax = wx.TextCtrl( - self, wx.ID_ANY, style=wx.SL_HORIZONTAL | wx.TE_PROCESS_ENTER - ) - - self.Ymax_label = wx.StaticText( - self, label="Y Max", style=wx.ALIGN_CENTER_VERTICAL - ) - self.Ymax = wx.TextCtrl( - self, wx.ID_ANY, style=wx.SL_HORIZONTAL | wx.TE_PROCESS_ENTER - ) - - self.auto_fit_button = wx.Button(self, wx.ID_ANY, label="Auto fit") - - gbSizer0.Add(self.Xmin_label, (0, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer0.Add(self.Xmin, (0, 1), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer0.Add(self.Ymin_label, (1, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer0.Add(self.Ymin, (1, 1), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer0.Add(self.Xmax_label, (0, 2), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer0.Add(self.Xmax, (0, 3), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer0.Add(self.Ymax_label, (1, 2), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer0.Add(self.Ymax, (1, 3), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer0.Add( - self.auto_fit_button, - (2, 1), - span=(1, 3), - flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, - ) - sbsizer0.Add(gbSizer0, 1, wx.EXPAND, 5) - - sb1 = wx.StaticBox(self, wx.ID_ANY, label="Unit and Scale") - sbsizer1 = wx.StaticBoxSizer(sb1, wx.VERTICAL) - - gbSizer1 = wx.GridBagSizer(5, 5) - - self.Xscale_label = wx.StaticText( - self, label="X", style=wx.ALIGN_CENTER_VERTICAL - ) - self.Xscale = wx.ComboBox( - self, id=wx.ID_ANY, choices=self.axis_scales_choices, style=wx.CB_READONLY - ) - - self.Xunit = wx.TextCtrl( - self, wx.ID_ANY, style=wx.SL_HORIZONTAL | wx.TE_PROCESS_ENTER - ) - - self.Yscale_label = wx.StaticText( - self, label="Y", style=wx.ALIGN_CENTER_VERTICAL - ) - self.Yscale = wx.ComboBox( - self, id=wx.ID_ANY, choices=self.axis_scales_choices, style=wx.CB_READONLY - ) - - self.Yunit = wx.TextCtrl( - self, wx.ID_ANY, style=wx.SL_HORIZONTAL | wx.TE_PROCESS_ENTER - ) - - gbSizer1.Add(self.Xscale_label, (0, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer1.Add(self.Xunit, (0, 2), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer1.Add(self.Xscale, (0, 4), flag=wx.ALIGN_CENTER_VERTICAL) - - gbSizer1.Add(self.Yscale_label, (1, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer1.Add(self.Yunit, (1, 2), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer1.Add(self.Yscale, (1, 4), flag=wx.ALIGN_CENTER_VERTICAL) - - sbsizer1.Add(gbSizer1, 1, wx.EXPAND, 5) - - hsizer0.Add(sbsizer0, 1, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) - hsizer0.Add(sbsizer1, 1, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) - - hsizer1 = wx.BoxSizer(wx.HORIZONTAL) - self.apply_button = wx.Button(self, wx.ID_ANY, label="Apply") - hsizer1.Add(self.apply_button, 0, wx.EXPAND, 0) - - Sizer.Add(hsizer0, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) - Sizer.Add(hsizer1, 0, wx.ALIGN_RIGHT | wx.RIGHT | wx.ALL, 5) - - self.SetSizer(Sizer) - Sizer.Fit(self) - self.Layout() - - self.Bind(wx.EVT_BUTTON, self.auto_fit, self.auto_fit_button) - self.Bind(wx.EVT_BUTTON, self.set_settings, self.apply_button) - - self.get_settings() - - def get_settings(self, event=None): - [Xmin, Xmax, Ymin, Ymax] = self.parent.figure.gca().axis() - self.parent.Xmin = Xmin - self.parent.Ymin = Ymin - self.parent.Xmax = Xmax - self.parent.Ymax = Ymax - - self.Xmin.SetValue(str(self.parent.Xmin)) - self.Ymin.SetValue(str(self.parent.Ymin)) - self.Xmax.SetValue(str(self.parent.Xmax)) - self.Ymax.SetValue(str(self.parent.Ymax)) - - self.Xunit.SetValue(str(self.parent.Xunit)) - self.Yunit.SetValue(str(self.parent.Yunit)) - - self.Xscale.SetValue(self.parent.Xscale) - self.Yscale.SetValue(self.parent.Yscale) - - def set_settings(self, event=None): - # CheckUnits. checkUnits method will raise exception if needed - self.checkUnits(self.parent.Xunit, self.Xunit.GetValue()) - self.checkUnits(self.parent.Yunit, self.Yunit.GetValue()) - - self.parent.Xunit = self.Xunit.GetValue() - self.parent.Yunit = self.Yunit.GetValue() - - self.parent.figure.gca().set_xlabel(self.parent.Xlabel + self.parent.fmt_Xunit) - self.parent.figure.gca().set_ylabel(self.parent.Ylabel + self.parent.fmt_Yunit) - - self.parent.Xscale = self.Xscale.GetValue() - self.parent.Yscale = self.Yscale.GetValue() - - self.parent.scale_xAxis() - self.parent.scale_yAxis() - - self.parent.Xmin = float(self.Xmin.GetValue()) - self.parent.Ymin = float(self.Ymin.GetValue()) - self.parent.Xmax = float(self.Xmax.GetValue()) - self.parent.Ymax = float(self.Ymax.GetValue()) - - self.parent.figure.gca().axis( - [self.parent.Xmin, self.parent.Xmax, self.parent.Ymin, self.parent.Ymax] - ) - - self.parent.set_ticks() - self.parent.canvas.draw() - - def auto_fit(self, event=None): - self.parent.on_auto_fit(event=event) - self.Xmin.SetValue(str(self.parent.Xmin)) - self.Ymin.SetValue(str(self.parent.Ymin)) - self.Xmax.SetValue(str(self.parent.Xmax)) - self.Ymax.SetValue(str(self.parent.Ymax)) - - -class LinesSettingsDialog(wx.Dialog): - def __init__(self, parent=None): - wx.Dialog.__init__( - self, - parent, - wx.ID_ANY, - title="Lines Settings", - style=wx.DEFAULT_DIALOG_STYLE - | wx.RESIZE_BORDER - | wx.MINIMIZE_BOX - | wx.MAXIMIZE_BOX, - ) - self.parent = parent - self.current_line = None - self.build_dialog() - - def build_dialog(self): - self.marker = ["o", "^", "s", "p", "*"] - - self.style_choice = ["-", "--", "-.", ":", "None"] + self.marker - - Sizer = wx.BoxSizer(wx.VERTICAL) - - bagSizer = wx.GridBagSizer(hgap=5, vgap=5) - - self.lines = wx.ListCtrl(self, wx.ID_ANY, style=wx.LC_REPORT) - self.lines.InsertColumn(0, "Lines") - - self.del_button = wx.Button(self, wx.ID_ANY, label="Delete") - - self.color_label = wx.StaticText( - self, label="Color", style=wx.ALIGN_CENTER_VERTICAL - ) - self.color_picker = wx.ColourPickerCtrl(self, id=wx.ID_ANY, col="black") - - self.legend_label = wx.StaticText( - self, label="Legend", style=wx.ALIGN_CENTER_VERTICAL - ) - self.legend = wx.TextCtrl( - self, wx.ID_ANY, style=wx.SL_HORIZONTAL | wx.TE_PROCESS_ENTER - ) - - self.style_label = wx.StaticText( - self, label="Style", style=wx.ALIGN_CENTER_VERTICAL - ) - self.style = wx.ComboBox( - self, id=wx.ID_ANY, choices=self.style_choice, style=wx.CB_READONLY - ) - - self.width_label = wx.StaticText( - self, label="Width", style=wx.ALIGN_CENTER_VERTICAL - ) - self.width = wx.SpinCtrl(self, id=wx.ID_ANY, style=wx.SP_ARROW_KEYS) - - bagSizer.Add(self.lines, pos=(0, 0), span=(4, 3), flag=wx.EXPAND) - - bagSizer.Add(self.del_button, pos=(4, 0), span=(1, 3), flag=wx.EXPAND) - - bagSizer.Add(self.legend_label, pos=(1, 4), flag=wx.ALIGN_CENTER_VERTICAL) - bagSizer.Add( - self.legend, - pos=(1, 5), - span=(1, 5), - flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, - ) - - bagSizer.Add(self.style_label, pos=(2, 4), flag=wx.ALIGN_CENTER_VERTICAL) - bagSizer.Add(self.style, pos=(2, 5), flag=wx.ALIGN_CENTER_VERTICAL) - - bagSizer.Add(self.width_label, pos=(2, 7), flag=wx.ALIGN_CENTER_VERTICAL) - bagSizer.Add(self.width, pos=(2, 8), flag=wx.ALIGN_CENTER_VERTICAL) - - bagSizer.Add(self.color_label, pos=(3, 4), flag=wx.ALIGN_CENTER_VERTICAL) - bagSizer.Add(self.color_picker, pos=(3, 5), flag=wx.ALIGN_CENTER_VERTICAL) - - hsizer1 = wx.BoxSizer(wx.HORIZONTAL) - self.apply_button = wx.Button(self, wx.ID_ANY, label="Apply") - hsizer1.Add(self.apply_button, 0, wx.EXPAND, 0) - - Sizer.Add(bagSizer, 0, wx.EXPAND | wx.ALL, 5) - Sizer.Add(hsizer1, 0, wx.ALIGN_RIGHT | wx.RIGHT | wx.ALL, 5) - - self.SetSizer(Sizer) - Sizer.Fit(self) - self.Layout() - - self.Bind(wx.EVT_BUTTON, self.delete_line, self.del_button) - self.Bind(wx.EVT_BUTTON, self.set_settings, self.apply_button) - self.Bind(wx.EVT_LIST_ITEM_FOCUSED, self.on_select_item, self.lines) - self.Bind(wx.EVT_CLOSE, self.close_dialog) - - self.set_lines() - - def close_dialog(self, event): - self.parent.selectedLine.set_alpha(1.0) - self.parent.figure.canvas.draw() - self.EndModal(0) - self.Destroy() - - def set_lines(self): - self.lines.DeleteAllItems() - _id = 0 - for k in list(self.parent.plots.keys()): - if type(self.parent.plots[k][0].get_color()) is str: - try: - r, g, b = matplotlib.colors.colorConverter.colors[ - self.parent.plots[k][0].get_color() - ] - except KeyError: - color = self.parent.plots[k][0].get_color().lstrip("#") - r, g, b = tuple( - int(color[i : i + 2], 16) / 255.0 for i in (0, 2, 4) - ) - else: - r, g, b = self.parent.plots[k][0].get_color() - self.lines.InsertStringItem(index=_id, label=k) - color = wx.Colour(int(r * 255), int(g * 255), int(b * 255)) - self.lines.SetItemTextColour(_id, color) - _id += 1 - - def on_select_item(self, event): - line_name = event.GetLabel() - if not line_name: - return - self.current_line = self.parent.plots[line_name][0] - if self.parent.selectedLine is not None: - self.parent.selectedLine.set_alpha(1.0) - self.parent.figure.canvas.draw() - - # set new selection and alpha - self.parent.selectedLine = self.current_line - self.parent.selectedLine.set_alpha(0.4) - self.parent.figure.canvas.draw() - - if type(self.current_line.get_color()) is str: - try: - r, g, b = matplotlib.colors.colorConverter.colors[ - self.current_line.get_color() - ] - except KeyError: - color = self.current_line.get_color().lstrip("#") - r, g, b = tuple(int(color[i : i + 2], 16) / 255.0 for i in (0, 2, 4)) - else: - r, g, b = self.current_line.get_color() - color = wx.Colour(int(r * 255), int(g * 255), int(b * 255)) - self.color_picker.SetColour(color) - self.legend.SetValue(self.parent.plots[line_name][1]) - self.style.SetValue(self.current_line.get_linestyle()) - self.width.SetValue(self.current_line.get_linewidth()) - - def set_settings(self, event=None): - if self.current_line is None: - return - - color = self.color_picker.GetColour() - self.current_line.set_color( - (color.Red() / 255.0, color.Green() / 255.0, color.Blue() / 255.0) - ) - for v in list(self.parent.plots.values()): - if v[0] is self.current_line: - new_legend = self.legend.GetValue() - if new_legend != v[1]: - v[1] = new_legend - self.parent.update_legend() - s = self.style.GetValue() - if s in self.marker: - self.current_line.set_linestyle("None") - self.current_line.set_marker(s) - else: - self.current_line.set_marker("") - self.current_line.set_linestyle(self.style.GetValue()) - self.current_line.set_linewidth(self.width.GetValue()) - if self.parent.show_legend: - self.parent.update_legend() - self.parent.canvas.draw() - self.set_lines() - - def delete_line(self, event=None): - if self.parent.delete_line(self.current_line): - self.parent.selectedLine = None - self.set_lines() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/PlotterTicker.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/PlotterTicker.py deleted file mode 100644 index 12be4783a7..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/PlotterTicker.py +++ /dev/null @@ -1,103 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/PlotterTicker.py -# @brief Implements module/class/test PlotterTicker -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import matplotlib.ticker - - -class ScaledLocator(matplotlib.ticker.MaxNLocator): - """ - Locates regular intervals along an axis scaled by *dx* and shifted by - *x0*. For example, this would locate minutes on an axis plotted in seconds - if dx=60. This differs from MultipleLocator in that an approriate interval - of dx units will be chosen similar to the default MaxNLocator. - - see https://stackoverflow.com/questions/9451395/customize-x-axis-in-matplotlib - """ - - def __init__(self, dx=1.0, x0=0.0): - self.dx = dx - self.x0 = x0 - matplotlib.ticker.MaxNLocator.__init__(self, nbins=9, steps=[1, 2, 5, 10]) - - def rescale(self, x): - return x * self.dx + self.x0 - - def inv_rescale(self, x): - return (x - self.x0) / self.dx - - # def __call__(self): - # vmin, vmax = self.axis.get_view_interval() - # vmin, vmax = self.rescale(vmin), self.rescale(vmax) - # vmin, vmax = matplotlib.transforms.nonsingular(vmin, vmax, expander = 0.05) - # locs = self.bin_boundaries(vmin, vmax) - # locs = self.inv_rescale(locs) - # prune = self._prune - # if prune=='lower': - # locs = locs[1:] - # elif prune=='upper': - # locs = locs[:-1] - # elif prune=='both': - # locs = locs[1:-1] - # return self.raise_if_exceeds(locs) - - -class ScaledFormatter(matplotlib.ticker.ScalarFormatter): - """Formats tick labels scaled by *dx* and shifted by *x0*.""" - - def __init__(self, dx=1.0, x0=0.0, **kwargs): - super(ScaledFormatter, self).__init__(**kwargs) - self.dx, self.x0 = dx, x0 - - def rescale(self, x): - return x * self.dx + self.x0 - - def pprint_val(self, x, d): - """ - Formats the value `x` based on the size of the axis range `d`. - """ - # If the number is not too big and it's an int, format it as an int. - if abs(x) < 1e4 and x == int(x): - return "%d" % x - - if d < 1e-2: - fmt = "%1.3e" - elif d < 1e-1: - fmt = "%1.3f" - elif d > 1e5: - fmt = "%1.1e" - elif d > 10: - fmt = "%1.1f" - elif d > 1: - fmt = "%1.2f" - else: - fmt = "%1.3f" - s = fmt % x - tup = s.split("e") - if len(tup) == 2: - mantissa = tup[0].rstrip("0").rstrip(".") - sign = tup[1][0].replace("+", "") - exponent = tup[1][1:].lstrip("0") - s = "%se%s%s" % (mantissa, sign, exponent) - else: - s = s.rstrip("0").rstrip(".") - return s - - def __call__(self, x, pos=None): - xmin, xmax = self.axis.get_view_interval() - xmin, xmax = self.rescale(xmin), self.rescale(xmax) - d = abs(xmax - xmin) - x = self.rescale(x) - s = self.pprint_val(x, d) - return s diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/QVectorsPlugin.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/QVectorsPlugin.py deleted file mode 100644 index fda74ab305..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/QVectorsPlugin.py +++ /dev/null @@ -1,293 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/QVectorsPlugin.py -# @brief Implements module/class/test QVectorsPlugin -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import os - -import wx -import wx.aui as wxaui -import wx.grid as wxgrid -from wx.lib.delayedresult import startWorker - -from MDANSE import LOGGER, REGISTRY -from MDANSE.GUI.Plugins.UserDefinitionPlugin import UserDefinitionPlugin -from MDANSE.GUI.ComboWidgets.ConfigurationPanel import ConfigurationPanel -from MDANSE.GUI.ComboWidgets.ProgressBar import ProgressBar - - -class QVectorsData(wxgrid.PyGridTableBase): - def __init__(self, data=None): - wxgrid.PyGridTableBase.__init__(self) - - self._colLabels = ["Qx", "Qy", "Qz", "|Q|", "h", "k", "l"] - - self._data = data - - self._grid = [] - if self._data is not None: - for v in list(self._data.values()): - if not v: - continue - - for i in range(v["n_q_vectors"]): - temp = [] - temp.extend(["%8.3f" % val for val in v["q_vectors"][:, i]]) - temp.extend(["%8.3f" % v["q"]]) - if v["hkls"] is not None: - temp.extend(["%d" % val for val in v["hkls"][:, i]]) - else: - temp.extend(["-"] * 3) - - self._grid.append(temp) - - @property - def data(self): - return self._data - - def GetAttr(self, row, col, kind): - attr = wxgrid.GridCellAttr() - attr.SetBackgroundColour(wx.NamedColour("LIGHT BLUE")) - if col == 3: - attr.SetTextColour(wx.RED) - attr.SetReadOnly(True) - attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTRE) - - return attr - - def GetNumberRows(self): - return len(self._grid) - - def GetNumberCols(self): - return 7 - - def GetColLabelValue(self, col): - return self._colLabels[col] - - def GetRowLabelValue(self, row): - return row + 1 - - def GetValue(self, row, col): - if self._grid is None: - return "-" - else: - return self._grid[row][col] - - def SetValue(self, row, col, value): - pass - - -class QVectorsPanel(wx.Panel): - def __init__(self, generator, parameters, *args, **kwargs): - wx.Panel.__init__(self, *args, **kwargs) - - self._generator = generator - self._parameters = parameters - - self._grid = wxgrid.Grid(self) - self._grid.DisableCellEditControl() - - self._progress = ProgressBar(self) - - sizer = wx.BoxSizer(wx.VERTICAL) - sizer.Add(self._grid, 1, wx.ALL | wx.EXPAND, 5) - sizer.Add(self._progress, 0, wx.ALL | wx.EXPAND, 5) - - self.SetSizer(sizer) - - @property - def grid(self): - return self._grid - - @property - def generator(self): - return self._generator - - @property - def parameters(self): - return self._parameters - - @property - def progress(self): - return self._progress - - -class QVectorsPlugin(UserDefinitionPlugin): - label = "Q vectors" - - ancestor = ["hdf_trajectory"] - - def __init__(self, parent, *args, **kwargs): - self._currentGenerator = None - - self._value = None - - UserDefinitionPlugin.__init__(self, parent, size=(800, 700)) - - def build_panel(self): - sizer = wx.BoxSizer(wx.VERTICAL) - - # Widgets and sizers related to generator section - self._mainPanel = wx.ScrolledWindow(self, wx.ID_ANY, size=self.GetSize()) - self._mainPanel.SetScrollbars(20, 20, 50, 50) - sb1 = wx.StaticBox(self._mainPanel, wx.ID_ANY, label="generator") - sbSizer1 = wx.StaticBoxSizer(sb1, wx.VERTICAL) - self._availableGenerators = wx.Choice(self._mainPanel, wx.ID_ANY) - generateButton = wx.Button(self._mainPanel, wx.ID_ANY, label="Generate") - sbSizer1.Add(self._availableGenerators, 1, wx.ALL | wx.EXPAND, 5) - sizer.Add(sbSizer1, 0, wx.ALL | wx.EXPAND, 5) - - # Widgets and sizers related to parameters section - sb2 = wx.StaticBox(self._mainPanel, wx.ID_ANY, label="parameters") - self._parametersSizer = wx.StaticBoxSizer(sb2, wx.VERTICAL) - sizer.Add(self._parametersSizer, 0, wx.ALL | wx.EXPAND, 5) - - self._notebook = wxaui.AuiNotebook( - self._mainPanel, - wx.ID_ANY, - style=wxaui.AUI_NB_DEFAULT_STYLE & ~wxaui.AUI_NB_TAB_MOVE, - ) - - sizer.Add(self._notebook, 3, wx.ALL | wx.EXPAND, 5) - - sizer.Add(generateButton, 0, wx.ALL | wx.EXPAND, 5) - - self._mainPanel.SetSizer(sizer) - - self.Bind(wxaui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.on_close_tab, self._notebook) - self.Bind(wx.EVT_BUTTON, self.on_generate_q_vectors, generateButton) - self.Bind(wx.EVT_CHOICE, self.on_select_generator, self._availableGenerators) - - def plug(self): - self.parent.mgr.GetPane(self).Float().Dockable(False).CloseButton( - True - ).BestSize((600, 800)) - - 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) - - if self._trajectory.universe.is_periodic: - choices = list(REGISTRY["q_vectors"].keys()) - else: - choices = [ - k for k, v in list(REGISTRY["q_vectors"].items()) if not v.is_lattice - ] - self._availableGenerators.SetItems(choices) - self._availableGenerators.SetSelection(0) - - self.select_generator(self._availableGenerators.GetStringSelection()) - - def on_close(self, event): - self.Destroy() - - def on_close_tab(self, event): - qPanel = event.GetEventObject().GetPage(event.GetSelection()) - if qPanel.progress.is_running(): - d = wx.MessageDialog( - None, - "The background task is still running. You must cancel it before closing this tab.", - "Warning", - wx.OK | wx.ICON_WARNING, - ) - d.ShowModal() - event.Veto() - return - - def generate_q_vectors(self, generator): - generator.generate() - - return generator["q_vectors"] - - def generate_q_vectors_done(self, result, qPanel): - data = result.get() - if data: - table = QVectorsData(data) - qPanel.grid.SetTable(table) - qPanel.grid.Refresh() - - def on_generate_q_vectors(self, event): - generator = self._availableGenerators.GetStringSelection() - generator = REGISTRY["q_vectors"][generator](self._trajectory.universe) - parameters = self._configurationPanel.get_value() - generator.setup(parameters) - - qPanel = QVectorsPanel(generator, parameters, self._mainPanel, wx.ID_ANY) - self._notebook.AddPage(qPanel, "Q Vectors") - - generator.setStatus(qPanel.progress) - - startWorker( - self.generate_q_vectors_done, - self.generate_q_vectors, - cargs=(qPanel,), - wargs=(generator,), - ) - - def on_select_generator(self, event): - self.select_generator(event.GetString()) - - def validate(self): - if self._notebook.GetPageCount() == 0: - LOGGER("No Q vectors generated.", "error") - return - - qPanel = self._notebook.GetPage(self._notebook.GetSelection()) - - if qPanel._grid.GetTable().data is None: - LOGGER("No data is the selected Q vectors tab", "error") - return - - ud = {} - ud["parameters"] = (qPanel.generator._type, qPanel.parameters) - ud["generator"] = qPanel.generator._type - ud["q_vectors"] = qPanel.grid.GetTable().data - ud["is_lattice"] = qPanel.generator.is_lattice - - if not ud["q_vectors"]: - LOGGER("No Q vectors generated.", "error", ["dialog"]) - return None - - return ud - - def select_generator(self, generatorName): - if generatorName == self._currentGenerator: - return - - self._currentGenerator = REGISTRY["q_vectors"][generatorName]( - self._trajectory.universe - ) - - self._parametersSizer.Clear(deleteWindows=True) - - self.Freeze() - - self._configurationPanel = ConfigurationPanel( - self._mainPanel, self._currentGenerator, None - ) - - self._parametersSizer.Add(self._configurationPanel, 1, wx.ALL | wx.EXPAND, 5) - - self.Thaw() - - self._parametersSizer.Layout() - - self._mgr.Update() - - -REGISTRY["q_vectors"] = QVectorsPlugin diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/TrajectoryViewerPlugin.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/TrajectoryViewerPlugin.py deleted file mode 100644 index 57d29b2ffe..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/TrajectoryViewerPlugin.py +++ /dev/null @@ -1,255 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/AtomSelectionPlugin.py -# @brief Implements module/class/test AtomSelectionPlugin -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -from distutils.version import LooseVersion -import os - -import wx -import wx.aui as wxaui - -from matplotlib.figure import Figure -from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg, NavigationToolbar2WxAgg - -from MDANSE import LOGGER, REGISTRY - -from MDANSE.GUI import PUBLISHER -from MDANSE.GUI.Plugins.DataPlugin import get_data_plugin -from MDANSE.GUI.Plugins.ComponentPlugin import ComponentPlugin - - -class TrajectoryViewerPlugin(ComponentPlugin): - label = "Trajectory Viewer" - - ancestor = ["mmtk_trajectory", "molecular_viewer"] - - _dimensions = {"x": 0, "y": 1, "z": 2} - - _units = {"configuration": "nm", "velocities": "nm/ps", "gradients": "amu*nm/ps2"} - - def __init__(self, parent, *args, **kwargs): - ComponentPlugin.__init__(self, parent, size=(600, 500), *args, **kwargs) - - PUBLISHER.subscribe( - self.msg_select_atoms_from_viewer, "msg_select_atoms_from_viewer" - ) - - def build_panel(self): - panel = wx.Panel(self, wx.ID_ANY) - - sizer = wx.BoxSizer(wx.VERTICAL) - - selectedOptionsSizer = wx.BoxSizer(wx.HORIZONTAL) - - selectedVariableText = wx.StaticText(panel, wx.ID_ANY, label="Variable:") - self._selectedVariable = wx.ComboBox(panel, wx.ID_ANY, style=wx.CB_READONLY) - - selectedAtomText = wx.StaticText(panel, wx.ID_ANY, label="Atom:") - self._selectedAtom = wx.SpinCtrl( - panel, wx.ID_ANY, style=wx.SP_WRAP | wx.SP_ARROW_KEYS - ) - - selectedDimensionText = wx.StaticText(panel, wx.ID_ANY, label="Dimension:") - self._selectedDimension = wx.ComboBox( - panel, wx.ID_ANY, choices=["x", "y", "z"], style=wx.CB_READONLY - ) - - selectedOptionsSizer.Add( - selectedVariableText, 0, wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 2 - ) - selectedOptionsSizer.Add(self._selectedVariable, 1, wx.CENTER | wx.EXPAND, 2) - selectedOptionsSizer.Add( - selectedAtomText, 0, wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 2 - ) - selectedOptionsSizer.Add(self._selectedAtom, 1, wx.CENTER | wx.EXPAND, 2) - selectedOptionsSizer.Add( - selectedDimensionText, 0, wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 2 - ) - selectedOptionsSizer.Add(self._selectedDimension, 1, wx.CENTER | wx.EXPAND, 2) - - self._figure = Figure(figsize=(1, 1)) - self._figure.add_subplot(111) - self._canvas = FigureCanvasWxAgg(panel, wx.ID_ANY, self._figure) - self._toolbar = NavigationToolbar2WxAgg(self._canvas) - self._toolbar.Realize() - - self._selectedLine = None - - actionsSizer = wx.BoxSizer(wx.HORIZONTAL) - - clearPlotButton = wx.Button(panel, label="Clear") - self._plotOnSameFigure = wx.CheckBox(panel, label="Plot on same figure") - self._showLegend = wx.CheckBox(panel, label="Show legend") - - actionsSizer.Add(clearPlotButton, 0, wx.CENTER, 2) - actionsSizer.Add(self._plotOnSameFigure, 0, wx.CENTER, 2) - actionsSizer.Add(self._showLegend, 0, wx.CENTER, 2) - - sizer.Add(selectedOptionsSizer, 0, wx.ALL | wx.EXPAND, 2) - sizer.Add(self._canvas, 1, wx.ALL | wx.EXPAND, 2) - sizer.Add(self._toolbar) - sizer.Add(actionsSizer, 0, wx.ALIGN_CENTER, 2) - - panel.SetSizer(sizer) - sizer.Fit(panel) - panel.Layout() - - self._mgr.AddPane( - panel, - wxaui.AuiPaneInfo() - .Center() - .Dock() - .CaptionVisible(False) - .CloseButton(False) - .MinSize(self.GetSize()), - ) - self._mgr.Update() - - self.Bind(wx.EVT_COMBOBOX, self.on_select_option, self._selectedVariable) - self.Bind(wx.EVT_SPINCTRL, self.on_select_option, self._selectedAtom) - self.Bind(wx.EVT_COMBOBOX, self.on_select_option, self._selectedDimension) - self.Bind(wx.EVT_BUTTON, self.on_clear_plot, clearPlotButton) - self.Bind(wx.EVT_CHECKBOX, self.on_showhide_legend, self._showLegend) - - self._canvas.mpl_connect("pick_event", self.on_pick_line) - self._canvas.mpl_connect("key_press_event", self.on_key_press) - - def plug(self): - self._parent._mgr.GetPane(self).Float().Floatable(True).Dockable( - True - ).CloseButton(True) - - self._parent._mgr.Update() - - self.set_trajectory(self.dataproxy.data) - - def set_trajectory(self, trajectory): - self._trajectory = trajectory - nAtoms = self._trajectory.chemical_system.number_of_atoms() - - self._target = os.path.basename(self._trajectory.filename) - - trajectoryVariables = [] - for k in self._trajectory.file["/configuration"]: - trajectoryVariables.append(k) - self._selectedVariable.SetItems(trajectoryVariables) - - self._selectedAtom.SetRange(0, nAtoms - 1) - - def msg_select_atoms_from_viewer(self, message): - dataPlugin, selection = message - - if dataPlugin != get_data_plugin(self): - return - - self._selectedAtom.SetValue(selection[-1]) - - self.on_select_option(None) - - def on_showhide_legend(self, event): - if self._showLegend.GetValue(): - self._figure.gca().legend(loc="best") - else: - self._figure.gca().legend().remove() - self._canvas.draw() - - def on_select_option(self, event): - variable = self._selectedVariable.GetValue() - atom = self._selectedAtom.GetValue() - dimension = self._selectedDimension.GetValue() - - if not variable or not dimension: - return - - atom = self._selectedAtom.GetValue() - - self._plot(variable, atom, dimension) - - def on_pick_line(self, event): - # set alpha of previous selection to 1 - if self._selectedLine is not None: - self._selectedLine.set_alpha(1.0) - self._selectedLine.figure.canvas.draw() - - # unselect previous selection - if event.artist == self._selectedLine: - self._selectedLine = None - return - - self._selectedLine = event.artist - self._selectedLine.set_alpha(0.4) - self._selectedLine.figure.canvas.draw() - - def on_key_press(self, event=None): - if event.key == "delete": - if self._selectedLine is None: - return - - d = wx.MessageDialog( - None, - "Do you really want delete this line ?", - "Question", - wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, - ) - if d.ShowModal() == wx.ID_NO: - return - - self._selectedLine.remove() - self._selectedLine = None - - if not self._figure.gca().lines: - self._figure.gca().set_prop_cycle(None) - - if self._showLegend.GetValue(): - self.update_legend() - - self._canvas.draw() - - def update_legend(self): - self._figure.gca().legend().remove() - if self._figure.gca().lines: - self._figure.gca().legend(loc="best") - self._canvas.draw() - - def _plot(self, variable, atom, dimension): - dimensionNumber = TrajectoryViewerPlugin._dimensions[ - self._selectedDimension.GetValue() - ] - - time = self._trajectory.file["time"] - data = self._trajectory.read_configuration_trajectory( - atom, 0, len(self._trajectory), 1, variable=variable - ) - - label = "%s - %d - %s" % (variable, atom, dimension) - - if not self._plotOnSameFigure.GetValue(): - self._figure.gca().clear() - - self._figure.gca().set_xlabel("time (ps)") - self._figure.gca().set_ylabel( - "%s (%s)" % (variable, TrajectoryViewerPlugin._units.get(variable, "au")) - ) - self._figure.gca().plot( - time[:], data[:, dimensionNumber], label=label, picker=3 - ) - self._canvas.draw() - - self.on_showhide_legend(None) - - def on_clear_plot(self, event): - self._figure.gca().clear() - self._canvas.draw() - - -REGISTRY["trajectory_viewer"] = TrajectoryViewerPlugin diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/UserDefinitionPlugin.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/UserDefinitionPlugin.py deleted file mode 100644 index 6ce170f691..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/UserDefinitionPlugin.py +++ /dev/null @@ -1,92 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/UserDefinitionPlugin.py -# @brief Implements module/class/test UserDefinitionPlugin -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx -import wx.aui as wxaui - -from MDANSE import LOGGER, REGISTRY -from MDANSE.Framework.UserDefinitionStore import UD_STORE -from MDANSE.GUI import PUBLISHER -from MDANSE.GUI.Plugins.ComponentPlugin import ComponentPlugin - - -class UserDefinitionPlugin(ComponentPlugin): - category = ("User definition",) - - def __init__(self, parent, *args, **kwargs): - ComponentPlugin.__init__(self, parent, *args, **kwargs) - - self.add_ud_panel() - - self._mgr.AddPane( - self._mainPanel, - wxaui.AuiPaneInfo() - .DestroyOnClose() - .Center() - .Dock() - .CaptionVisible(False) - .CloseButton(False) - .BestSize(self.GetSize()), - ) - - self._mgr.Update() - - def add_ud_panel(self): - udPanel = wx.Panel(self._mainPanel, wx.ID_ANY) - - sb = wx.StaticBox(udPanel, wx.ID_ANY) - actionsSizer = wx.StaticBoxSizer(sb, wx.HORIZONTAL) - - self._udName = wx.TextCtrl(udPanel, wx.ID_ANY, style=wx.TE_PROCESS_ENTER) - saveButton = wx.Button(udPanel, wx.ID_ANY, label="Save") - - actionsSizer.Add(self._udName, 1, wx.ALL | wx.EXPAND, 5) - actionsSizer.Add(saveButton, 0, wx.ALL, 5) - - udPanel.SetSizer(actionsSizer) - - self._mainPanel.GetSizer().Add(udPanel, 0, wx.EXPAND | wx.ALL, 5) - - self.Bind(wx.EVT_BUTTON, lambda evt: self.on_save(evt), saveButton) - - def on_save(self, event): - name = str(self._udName.GetValue().strip()) - - if not name: - LOGGER("Empty user definition name.", "error", ["dialog"]) - return - - value = self.validate() - if value is None: - return - - if UD_STORE.has_definition(self._target, self._type, name): - LOGGER( - "There is already an user-definition with that name.", - "error", - ["dialog"], - ) - return - - UD_STORE.set_definition(self._target, self._type, name, value) - - PUBLISHER.sendMessage("msg_set_ud", message=None) - - UD_STORE.save() - - LOGGER("User definition %r successfully set." % name, "info", ["console"]) - - -REGISTRY["user_definition"] = UserDefinitionPlugin diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/__init__.py deleted file mode 100644 index 663dcbba26..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Plugins/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Plugins/__init__.py -# @brief Implements module/class/test __init__ -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/PluginsTreePanel.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/PluginsTreePanel.py deleted file mode 100644 index 5909d16585..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/PluginsTreePanel.py +++ /dev/null @@ -1,159 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/PluginsTreePanel.py -# @brief Implements module/class/test PluginsTreePanel -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import collections -import pickle - -import wx - -from MDANSE import REGISTRY - -from MDANSE.GUI import PUBLISHER - - -class DataObject(wx.TextDataObject): - def __init__(self, pluginStr): - wx.TextDataObject.__init__(self) - - self.SetText(pluginStr) - - -class PluginsTreePanel(wx.Panel): - def __init__(self, parent): - wx.Panel.__init__(self, parent, wx.ID_ANY) - - self.build_panel() - - self.build_layout() - - self.build_plugins_tree() - - self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.on_drag, self._tree) - self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.on_double_click) - - PUBLISHER.subscribe(self.msg_set_plugins_tree, "msg_set_plugins_tree") - - self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy) - - @property - def tree(self): - return self._tree - - def OnDestroy(self, event): - PUBLISHER.subscribe(self.msg_set_plugins_tree, "msg_set_plugins_tree") - event.Skip() - - def build_panel(self): - self._tree = wx.TreeCtrl( - self, wx.ID_ANY, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT - ) - - self._root = self._tree.AddRoot("root") - - def build_layout(self): - sizer = wx.BoxSizer(wx.VERTICAL) - - sizer.Add(self._tree, 1, wx.EXPAND | wx.ALL, 5) - - self.SetSizer(sizer) - - def build_plugins_tree(self): - self._hierarchy = collections.OrderedDict() - - for kls in list(REGISTRY["plugin"].values()): - ancestor = getattr(kls, "ancestor", []) - - if not ancestor: - continue - - category = getattr(kls, "category", ("Miscellaneous",)) - - ancestors = [] - for anc in ancestor: - ancestors.append(anc) - if anc in list(REGISTRY["plugin"].keys()): - ancestors.extend( - [c._type for c in REGISTRY["plugin"][anc].__subclasses__()] - ) - - for a in ancestors: - d = self._hierarchy.setdefault(a, collections.OrderedDict()) - - for cat in category: - d = d.setdefault(cat, collections.OrderedDict()) - - d[kls._type] = True - - def on_double_click(self, event): - data = self._tree.GetItemData(event.GetItem()) - - self.TopLevelParent.panels["working"].active_page.currentWindow.drop(data) - - def on_drag(self, event=None): - if event is None: - return - - data = self._tree.GetPyData(event.GetItem()) - - if data is None: - return - - draginfo = pickle.dumps(data) - - tdo = wx.CustomDataObject(wx.CustomDataFormat("Plugin")) - - tdo.SetData(draginfo) - - tds = wx.DropSource(self._tree) - - tds.SetData(tdo) - - tds.DoDragDrop(True) - - event.Skip() - - def set_plugins_tree(self, node, data): - if not data: - self._tree.AppendItem(node, "No plugins available") - return - - for k, v in sorted(data.items()): - plugin = REGISTRY["plugin"].get(k, None) - - if plugin is None: - label = k - data = None - else: - label = getattr(plugin, "label", plugin._type) - data = k - - subnode = self._tree.AppendItem(node, label, data=data) - - if v is True: - continue - - self.set_plugins_tree(subnode, v) - - def msg_set_plugins_tree(self, message): - if self._tree.GetCount() != 0: - self._tree.DeleteChildren(self._root) - - plugin = message - if plugin is None: - return - - self.set_plugins_tree(self._root, self._hierarchy.get(plugin._type, {})) - - self.TopLevelParent._mgr.Update() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/RegistryViewer.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/RegistryViewer.py deleted file mode 100644 index 49c2fd167f..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/RegistryViewer.py +++ /dev/null @@ -1,99 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/RegistryViewer.py -# @brief Implements module/class/test RegistryViewer -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import os - -import wx -import wx.html as wxhtml - -from MDANSE import PLATFORM, REGISTRY - - -class RegistryViewer(wx.Dialog): - def __init__(self, parent, *args, **kwargs): - wx.Dialog.__init__( - self, - parent, - wx.ID_ANY, - size=(800, 400), - title="Registry viewer", - style=wx.DEFAULT_DIALOG_STYLE - | wx.MINIMIZE_BOX - | wx.MAXIMIZE_BOX - | wx.RESIZE_BORDER, - ) - - dialogSizer = wx.BoxSizer(wx.VERTICAL) - - mainPanel = wx.Panel(self, wx.ID_ANY, size=self.GetSize()) - - mainSizer = wx.BoxSizer(wx.HORIZONTAL) - - self._tree = wx.TreeCtrl( - mainPanel, wx.ID_ANY, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT - ) - self._root = self._tree.AddRoot("root") - - mainSizer.Add(self._tree, 1, wx.ALL | wx.EXPAND, 5) - - self._info = wxhtml.HtmlWindow(mainPanel, wx.ID_ANY, size=self.GetSize()) - - mainSizer.Add(self._info, 1, wx.ALL | wx.EXPAND, 5) - - mainPanel.SetSizer(mainSizer) - - self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.on_double_click_data) - - self.set_plugins_tree(self._root, REGISTRY._registry) - - dialogSizer.Add(mainPanel, 1, wx.EXPAND) - - self.SetSizer(dialogSizer) - - def set_plugins_tree(self, node, data): - for k, v in sorted(data.items()): - if isinstance(v, dict): - subnode = self._tree.AppendItem(node, str(k), data=None) - self.set_plugins_tree(subnode, v) - - else: - dataItem = wx.TreeItemData(v) - self._tree.AppendItem(node, str(k), data=dataItem) - - def on_double_click_data(self, event): - ItemData = self._tree.GetItemData(event.GetItem()) - - if ItemData is None: - return - - if ItemData.GetData() is None: - return - - moduleFullName = PLATFORM.full_dotted_module(ItemData.GetData()) - - if moduleFullName is None: - moduleDocPath = "" - else: - moduleDocPath = os.path.join(PLATFORM.help_path(), moduleFullName + ".html") - - self._info.LoadPage(moduleDocPath) - - -if __name__ == "__main__": - app = wx.App(False) - f = RegistryViewer(None) - f.ShowModal() - f.Destroy() - app.MainLoop() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/UnitsEditor.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/UnitsEditor.py deleted file mode 100644 index 0f7cbd1237..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/UnitsEditor.py +++ /dev/null @@ -1,379 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/UserDefinitionViewer.py -# @brief Implements module/class/test UserDefinitionViewer -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import collections -import copy - -import wx - -from MDANSE import LOGGER -from MDANSE.Framework.Units import _UNAMES, UNITS_MANAGER - - -class FloatValidator(wx.PyValidator): - """This validator is used to ensure that the user has entered a float - into the text control of MyFrame. - """ - - def __init__(self): - """Standard constructor.""" - wx.PyValidator.__init__(self) - - def Clone(self): - """Standard cloner. - - Note that every validator must implement the Clone() method. - """ - return FloatValidator() - - def Validate(self, win): - textCtrl = self.GetWindow() - num_string = textCtrl.GetValue() - try: - float(num_string) - except: - wx.MessageBox( - "Please enter numbers only", "Invalid Input", wx.OK | wx.ICON_ERROR - ) - return False - else: - return True - - def TransferToWindow(self): - """Transfer data from validator to window. - - The default implementation returns False, indicating that an error - occurred. We simply return True, as we don't do any data transfer. - """ - return True - - def TransferFromWindow(self): - """Transfer data from window to validator. - - The default implementation returns False, indicating that an error - occurred. We simply return True, as we don't do any data transfer. - """ - return True - - -class NewUnitDialog(wx.Dialog): - """ - This class pops up a dialog that prompts the user for registering a new element in the database. - """ - - def __init__(self, *args, **kwargs): - """ - The constructor. - """ - - # The base class constructor - wx.Dialog.__init__(self, *args, **kwargs) - - self.Center() - - # Create text and answer box widgets - staticLabel = wx.StaticText(self, wx.ID_ANY, "Unit name") - self._unit = wx.TextCtrl(self, wx.ID_ANY) - - self._labels = collections.OrderedDict() - self._dimensions = collections.OrderedDict() - for uname in _UNAMES: - self._labels[uname] = wx.StaticText(self, label=uname) - self._dimensions[uname] = wx.SpinCtrl(self, id=wx.ID_ANY, style=wx.SP_WRAP) - self._dimensions[uname].SetRange(-100, 100) - self._dimensions[uname].SetValue(0) - - factorLabel = wx.StaticText(self, label="Factor") - self._factor = wx.TextCtrl( - self, - wx.ID_ANY, - style=wx.TE_PROCESS_ENTER | wx.TE_PROCESS_TAB, - validator=FloatValidator(), - ) - self._factor.SetValue("1.0") - - # Create buttons - ok = wx.Button(self, wx.ID_OK, "OK") - ok.SetDefault() - cancel = wx.Button(self, wx.ID_CANCEL, "Cancel") - - # Create main sizer and add the instruction text to the top - main_sizer = wx.BoxSizer(wx.VERTICAL) - - unitNameSizer = wx.BoxSizer(wx.HORIZONTAL) - unitNameSizer.Add(staticLabel, 0, wx.ALIGN_CENTER_VERTICAL, 5) - unitNameSizer.Add(self._unit, 1, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5) - - factorSizer = wx.BoxSizer(wx.HORIZONTAL) - factorSizer.Add(factorLabel, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - factorSizer.Add(self._factor, 1, wx.ALL, 5) - - dimensionsSizer = wx.GridBagSizer(5, 5) - for comp, k in enumerate(self._dimensions): - dimensionsSizer.Add( - self._labels[k], (comp, 0), flag=wx.ALIGN_CENTER_VERTICAL - ) - dimensionsSizer.Add(self._dimensions[k], (comp, 1), flag=wx.EXPAND) - dimensionsSizer.AddGrowableCol(1) - - # Place buttons to appear as a standard dialogue - button_sizer = wx.StdDialogButtonSizer() - button_sizer.AddButton(cancel) - button_sizer.AddButton(ok) - button_sizer.Realize() - - main_sizer.Add(unitNameSizer, 0, wx.ALL | wx.EXPAND, 5) - main_sizer.Add(factorSizer, 0, wx.ALIGN_LEFT | wx.EXPAND, 5) - main_sizer.Add(dimensionsSizer, 0, wx.ALL | wx.EXPAND, 5) - main_sizer.Add(button_sizer, 0, wx.EXPAND) - - # Give a minimum size for the dialog but ensure that everything fits inside - self.SetMinSize(wx.Size(400, 160)) - self.SetSizerAndFit(main_sizer) - self.Fit() - - self.Bind(wx.EVT_BUTTON, self.on_ok, ok) - - def GetValue(self, event=None): - """ - Handler called when the user clicks on the OK button of the property dialog. - """ - - unit = self._unit.GetValue().strip() - - factor = self._factor.GetValue() - - dim = [v.GetValue() for v in list(self._dimensions.values())] - - return unit, factor, dim - - def on_ok(self, event): - unit, factor, _ = self.GetValue() - - if not unit: - wx.MessageBox( - "Please enter a unit name", "Invalid Input", wx.OK | wx.ICON_ERROR - ) - return - - try: - float(factor) - except ValueError: - wx.MessageBox( - "Please enter a valid number for factor", - "Invalid Input", - wx.OK | wx.ICON_ERROR, - ) - return - - if UNITS_MANAGER.has_unit(unit): - wx.MessageBox( - "This unit already exists", "Invalid Input", wx.OK | wx.ICON_ERROR - ) - return - - self.EndModal(wx.ID_OK) - - -class UnitsEditor(wx.Dialog): - def __init__(self, parent, title="Units Editor", standalone=False): - wx.Dialog.__init__( - self, - parent, - wx.ID_ANY, - size=(600, 500), - title=title, - style=wx.DEFAULT_DIALOG_STYLE - | wx.MINIMIZE_BOX - | wx.MAXIMIZE_BOX - | wx.RESIZE_BORDER, - ) - - self._standalone = standalone - - self._dialogSizer = wx.BoxSizer(wx.VERTICAL) - - self._build() - - def _build(self): - mainPanel = wx.Panel(self, wx.ID_ANY, size=self.GetSize()) - - self._defaultUnits = copy.deepcopy(UNITS_MANAGER.units) - - self._unitsList = wx.ListBox( - mainPanel, - wx.ID_ANY, - choices=sorted(self._defaultUnits.keys()), - style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT | wx.TR_EDIT_LABELS, - ) - - self._cancel = wx.Button(mainPanel, wx.ID_ANY, label="Cancel") - self._save = wx.Button(mainPanel, wx.ID_ANY, label="Save") - self._ok = wx.Button(mainPanel, wx.ID_ANY, label="OK") - - factorPanel = wx.Panel(mainPanel, wx.ID_ANY) - factorLabel = wx.StaticText(factorPanel, label="Factor") - self._factor = wx.TextCtrl(factorPanel, wx.ID_ANY, style=wx.TE_READONLY) - - dimensionsPanel = wx.Panel(mainPanel, wx.ID_ANY) - self._labels = collections.OrderedDict() - self._dimensions = collections.OrderedDict() - for uname in _UNAMES: - self._labels[uname] = wx.StaticText(dimensionsPanel, label=uname) - self._dimensions[uname] = wx.TextCtrl( - dimensionsPanel, id=wx.ID_ANY, style=wx.TE_READONLY - ) - - addUnit = wx.Button(mainPanel, wx.ID_ANY, label="Add unit") - - mainSizer = wx.BoxSizer(wx.VERTICAL) - - factorSizer = wx.BoxSizer(wx.HORIZONTAL) - factorSizer.Add(factorLabel, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - factorSizer.Add(self._factor, 1, wx.ALL, 5) - factorPanel.SetSizer(factorSizer) - - dimensionsSizer = wx.GridBagSizer(5, 5) - for comp, k in enumerate(self._dimensions): - dimensionsSizer.Add( - self._labels[k], (comp, 0), flag=wx.ALIGN_CENTER_VERTICAL - ) - dimensionsSizer.Add(self._dimensions[k], (comp, 1), flag=wx.EXPAND) - dimensionsSizer.AddGrowableCol(1) - dimensionsPanel.SetSizer(dimensionsSizer) - - unitsSizer = wx.BoxSizer(wx.VERTICAL) - unitsSizer.Add(self._unitsList, 1, wx.ALL | wx.EXPAND, 5) - unitsSizer.Add(addUnit, 0, wx.ALL | wx.EXPAND, 5) - - infoSizer = wx.BoxSizer(wx.HORIZONTAL) - infoSizer.Add(unitsSizer, 1, wx.ALL | wx.EXPAND, 5) - infoSizer.Add(factorPanel, 1, wx.ALL, 5) - infoSizer.Add(dimensionsPanel, 1, wx.ALL | wx.EXPAND, 5) - - buttonsSizer = wx.BoxSizer(wx.HORIZONTAL) - buttonsSizer.Add(self._cancel, 0, wx.ALL, 5) - buttonsSizer.Add(self._save, 0, wx.ALL, 5) - buttonsSizer.Add(self._ok, 0, wx.ALL, 5) - - mainSizer.Add(infoSizer, 1, wx.ALL | wx.EXPAND, 5) - mainSizer.Add(buttonsSizer, 0, wx.ALL | wx.ALIGN_RIGHT, 5) - mainPanel.SetSizer(mainSizer) - - self.Bind(wx.EVT_LISTBOX, self.on_select_unit, self._unitsList) - self.Bind(wx.EVT_CLOSE, self.on_close, self) - self.Bind(wx.EVT_BUTTON, self.on_close, self._cancel) - self.Bind(wx.EVT_BUTTON, lambda evt: self.on_ok(evt, True), self._save) - self.Bind(wx.EVT_BUTTON, lambda evt: self.on_ok(evt, False), self._ok) - self._unitsList.Bind(wx.EVT_KEY_DOWN, self.on_delete_unit) - self.Bind(wx.EVT_BUTTON, self.on_add_unit, addUnit) - - self._dialogSizer.Add(mainPanel, 1, wx.EXPAND) - - self.SetSizer(self._dialogSizer) - - def validate(self): - if not self._factor.GetValidator().Validate(self._factor): - return False - - else: - return True - - def on_add_unit(self, event): - d = NewUnitDialog(self, title="Add unit", size=(400, 220)) - - # If the new element dialog is closed by clicking on OK. - if d.ShowModal() == wx.ID_CANCEL: - return - - # Get rid of wxpython unicode string formatting - unitName, factor, dimension = d.GetValue() - - factor = float(factor) - - if UNITS_MANAGER.has_unit(unitName): - d = wx.MessageDialog( - None, - "This unit already exists. Do you want to overwrite it ?", - "Question", - wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, - ) - if d.ShowModal() == wx.ID_NO: - return - - UNITS_MANAGER.add_unit(unitName, factor, *dimension) - - units = sorted(UNITS_MANAGER.units.keys()) - self._unitsList.SetItems(units) - - def on_close(self, event): - UNITS_MANAGER.units = self._defaultUnits - - self.EndModal(wx.CANCEL) - - self.Destroy() - - def on_delete_unit(self, event): - keycode = event.GetKeyCode() - if keycode == wx.WXK_DELETE: - idx = self._unitsList.GetSelection() - selected_unit = self._unitsList.GetString(idx) - - d = wx.MessageDialog( - None, - "Do you really want to delete this unit ?", - "Question", - wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, - ) - if d.ShowModal() == wx.ID_NO: - return - - UNITS_MANAGER.delete_unit(selected_unit) - self._unitsList.Delete(idx) - - def on_select_unit(self, event): - selected_unit = self._unitsList.GetString(self._unitsList.GetSelection()) - selected_unit = UNITS_MANAGER.get_unit(selected_unit) - - self._factor.SetValue(str(selected_unit.factor)) - - dim = selected_unit.dimension - for k, v in zip(_UNAMES, dim): - self._dimensions[k].SetValue(str(v)) - - def on_ok(self, event, save=False): - if save: - UNITS_MANAGER.save() - if self._standalone: - wx.MessageBox( - "Units database saved successfully", - "Success", - wx.OK | wx.ICON_INFORMATION, - ) - else: - LOGGER("Units database saved successfully", "info") - self.EndModal(wx.ID_OK) - self.Destroy() - else: - self.EndModal(wx.ID_OK) - self.Destroy() - - -if __name__ == "__main__": - app = wx.App(False) - f = UnitsEditor(None) - f.ShowModal() - f.Destroy() - app.MainLoop() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/UserDefinitionViewer.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/UserDefinitionViewer.py deleted file mode 100644 index 5706c9af65..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/UserDefinitionViewer.py +++ /dev/null @@ -1,265 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/UserDefinitionViewer.py -# @brief Implements module/class/test UserDefinitionViewer -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx - -from MDANSE import LOGGER -from MDANSE.Framework.UserDefinitionStore import UD_STORE - -from MDANSE.GUI import PUBLISHER - - -class UserDefinitionViewer(wx.Dialog): - def __init__(self, parent, title="User Definition Viewer", ud=None, editable=True): - wx.Dialog.__init__( - self, - parent, - wx.ID_ANY, - size=(800, 400), - title=title, - style=wx.DEFAULT_DIALOG_STYLE - | wx.MINIMIZE_BOX - | wx.MAXIMIZE_BOX - | wx.RESIZE_BORDER, - ) - - self._udTree = {} - - dialogSizer = wx.BoxSizer(wx.VERTICAL) - - mainPanel = wx.Panel(self, wx.ID_ANY, size=self.GetSize()) - - self._tree = wx.TreeCtrl( - mainPanel, - wx.ID_ANY, - style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT | wx.TR_EDIT_LABELS, - ) - - self._root = self._tree.AddRoot("root") - - self.build_tree(self._root, UD_STORE.definitions) - - self._info = wx.TextCtrl( - mainPanel, wx.ID_ANY, style=wx.TE_MULTILINE | wx.TE_READONLY - ) - - self._save = wx.Button(mainPanel, wx.ID_ANY, label="Save user definitions") - - mainSizer = wx.BoxSizer(wx.VERTICAL) - - infoSizer = wx.BoxSizer(wx.HORIZONTAL) - infoSizer.Add(self._tree, 1, wx.ALL | wx.EXPAND, 5) - infoSizer.Add(self._info, 2, wx.ALL | wx.EXPAND, 5) - - mainSizer.Add(infoSizer, 1, wx.ALL | wx.EXPAND, 5) - mainSizer.Add(self._save, 0, wx.ALL | wx.EXPAND, 5) - mainPanel.SetSizer(mainSizer) - - self.Bind(wx.EVT_TREE_SEL_CHANGED, self.on_show_info) - self.Bind(wx.EVT_TREE_KEY_DOWN, self.on_delete, self._tree) - self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.on_rename, self._tree) - self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.on_try_rename, self._tree) - self.Bind(wx.EVT_CLOSE, self.on_close, self) - - self.Bind(wx.EVT_BUTTON, self.on_save_ud, self._save) - - if ud is not None: - self.expand_ud(ud) - - self.set_editable(editable) - - dialogSizer.Add(mainPanel, 1, wx.EXPAND) - - self.SetSizer(dialogSizer) - - def set_editable(self, editable=True): - self._editable = editable - - self._save.Show(self._editable) - - def get_item_level(self, item): - parent = self._tree.GetItemParent(item) - - if parent == self._tree.GetRootItem(): - return 1 - else: - return 1 + self.get_item_level(parent) - - def build_tree(self, node, data): - for k, v in sorted(data.items()): - dataItem = wx.TreeItemData(v) - subnode = self._tree.AppendItem(node, str(k), data=dataItem) - - self._tree.SetItemTextColour(subnode, "blue") - - if isinstance(v, dict): - self.build_tree(subnode, v) - - def find_ud(self, baseitem, itemNames): - if not itemNames: - return baseitem - - name = itemNames.pop(0) - - item, cookie = self._tree.GetFirstChild(baseitem) - - while item.IsOk(): - if self._tree.GetItemText(item) == name: - baseitem = item - return self.find_ud(baseitem, itemNames) - item, cookie = self._tree.GetNextChild(baseitem, cookie) - - return None - - def expand_ud(self, ud): - item = self.find_ud(self._root, ud) - - if item is None: - return - - self._tree.SelectItem(item, True) - - while True: - item = self._tree.GetItemParent(item) - if item == self._root: - break - self._tree.Expand(item) - - def on_close(self, event): - self.EndModal(wx.CANCEL) - - self.Destroy() - - def on_show_info(self, event=None): - currentItem = self._tree.GetSelection() - - itemData = self._tree.GetItemData(currentItem) - - if itemData is None: - return - - data = itemData.GetData() - - level = self.get_item_level(currentItem) - - if level <= 3: - self._info.SetValue( - "Contains the followings definitions: %s" % list(data.keys()) - ) - return - - self._info.SetValue(str(itemData.GetData())) - - def on_delete(self, event): - if not self._editable: - return - - keycode = event.GetKeyCode() - - if keycode == wx.WXK_DELETE: - currentItem = self._tree.GetSelection() - - level = self.get_item_level(currentItem) - - if level > 3: - return - - d = wx.MessageDialog( - None, - "Do you really want to delete this definition ?", - "Question", - wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, - ) - if d.ShowModal() == wx.ID_NO: - return - - currentItemName = str(self._tree.GetItemText(currentItem)) - - if level == 1: - UD_STORE.remove_definition(currentItemName) - elif level == 2: - targetItem = self._tree.GetItemParent(currentItem) - targetItemName = str(self._tree.GetItemText(targetItem)) - UD_STORE.remove_definition(targetItemName, currentItemName) - elif level == 3: - sectionItem = self._tree.GetItemParent(currentItem) - sectionItemName = str(self._tree.GetItemText(sectionItem)) - targetItem = self._tree.GetItemParent(sectionItem) - targetItemName = str(self._tree.GetItemText(targetItem)) - UD_STORE.remove_definition( - targetItemName, sectionItemName, currentItemName - ) - else: - return - - self._tree.DeleteChildren(currentItem) - self._tree.Delete(currentItem) - self._udTree.clear() - self._info.Clear() - - PUBLISHER.sendMessage("msg_set_ud", message=None) - - def on_save_ud(self, event): - UD_STORE.save() - - LOGGER("User definitions successfully saved.", "info", ["console"]) - - def on_try_rename(self, event): - if not self._editable: - event.Veto() - return - - currentItem = self._tree.GetSelection() - level = self.get_item_level(currentItem) - - if level != 3: - event.Veto() - return - - def on_rename(self, event): - if not self._editable: - return - - currentItem = event.GetItem() - - currentItemName = str(self._tree.GetItemText(currentItem)) - newItemName = self._tree.GetEditControl().GetValue() - - if currentItemName == newItemName: - return - - sectionItem = self._tree.GetItemParent(currentItem) - sectionItemName = str(self._tree.GetItemText(sectionItem)) - targetItem = self._tree.GetItemParent(sectionItem) - targetItemName = str(self._tree.GetItemText(targetItem)) - - currentItemData = self._tree.GetItemData(currentItem) - - UD_STORE.set_definition( - targetItemName, sectionItemName, newItemName, currentItemData.GetData() - ) - UD_STORE.remove_definition(targetItemName, sectionItemName, currentItemName) - - -if __name__ == "__main__": - app = wx.App(False) - f = UserDefinitionViewer( - None, - ud=["protein_in_periodic_universe.nc", "atom_selection", "sfdfdfsd"], - editable=True, - ) - f.ShowModal() - f.Destroy() - app.MainLoop() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/AtomSelectionWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/AtomSelectionWidget.py deleted file mode 100644 index 528bc32492..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/AtomSelectionWidget.py +++ /dev/null @@ -1,147 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/AtomSelectionWidget.py -# @brief Implements module/class/test AtomSelectionWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import os - -import wx - -from MDANSE import REGISTRY -from MDANSE.Framework.UserDefinitionStore import UD_STORE - -from MDANSE.GUI import PUBLISHER -from MDANSE.GUI.Widgets.UserDefinitionWidget import ( - UserDefinitionDialog, - UserDefinitionWidget, -) -from MDANSE.GUI.Icons import ICONS - - -class AtomSelectionWidget(UserDefinitionWidget): - def add_widgets(self): - self._sizer = wx.BoxSizer(wx.VERTICAL) - - panel = wx.Panel(self._widgetPanel, wx.ID_ANY) - sizer = wx.BoxSizer(wx.HORIZONTAL) - - new = wx.Button(panel, wx.ID_ANY, label="Set new selection") - new.SetToolTip(wx.ToolTip("Pop up selection dialog")) - add = wx.BitmapButton(panel, wx.ID_ANY, ICONS["plus", 16, 16]) - add.SetToolTip(wx.ToolTip("Add a new line")) - - sizer.Add(new, 0, wx.ALL | wx.ALIGN_RIGHT, 5) - sizer.Add(add, 0, wx.ALL | wx.ALIGN_RIGHT, 5) - - panel.SetSizer(sizer) - - self._sizer.Add(panel, 1, wx.ALL | wx.ALIGN_RIGHT, 5) - - self._choices = [] - - PUBLISHER.subscribe(self.msg_set_ud, "msg_set_ud") - - self.Bind(wx.EVT_BUTTON, self.on_new_definition, new) - self.Bind(wx.EVT_BUTTON, self.on_add_definition, add) - - return self._sizer - - 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") - 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(remove, 0, wx.ALL | wx.EXPAND, 5) - - panel.SetSizer(sizer) - - self._sizer.Add(panel, 1, wx.ALL | wx.EXPAND, 5) - - self._widgetPanel.GrandParent.Layout() - self._widgetPanel.GrandParent.Refresh() - - self.Bind(wx.EVT_BUTTON, self.on_view_definition, view) - self.Bind(wx.EVT_BUTTON, self.on_remove_definition, remove) - - def on_new_definition(self, event): - dlg = UserDefinitionDialog(None, self._trajectory, "atom_selection") - - dlg.ShowModal() - - def on_remove_definition(self, event): - self._sizer.Detach(event.GetEventObject().Parent) - - event.GetEventObject().Parent.Destroy() - - self._widgetPanel.GrandParent.Layout() - - def get_widget_value(self): - sizerItemList = list(self._sizer.GetChildren()) - del sizerItemList[0] - - uds = [] - for sizerItem in sizerItemList: - panel = sizerItem.GetWindow() - children = panel.GetChildren() - udName = children[0] - uds.append(udName.GetStringSelection()) - - if not uds: - return None - else: - return uds - - def msg_set_ud(self, message): - uds = UD_STORE.filter(self._basename, self._type) - - sizerItemList = list(self._sizer.GetChildren()) - del sizerItemList[0] - - for sizerItem in sizerItemList: - panel = sizerItem.GetWindow() - children = panel.GetChildren() - udName = children[0] - oldSelection = udName.GetStringSelection() - udName.SetItems(uds) - udName.SetStringSelection(oldSelection) - - -REGISTRY["atom_selection"] = AtomSelectionWidget - -if __name__ == "__main__": - from MDANSE import PLATFORM - from MDANSE.MolecularDynamics.Trajectory import Trajectory - - t = Trajectory( - os.path.join( - PLATFORM.example_data_directory(), "Trajectories", "HDF", "waterbox.h5" - ) - ) - - app = wx.App(False) - - p = UserDefinitionDialog(None, t, "q_vectors") - - p.SetSize((800, 800)) - - p.ShowModal() - - app.MainLoop() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/AtomTransmutationWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/AtomTransmutationWidget.py deleted file mode 100644 index ae54b4e1e5..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/AtomTransmutationWidget.py +++ /dev/null @@ -1,82 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/AtomTransmutationWidget.py -# @brief Implements module/class/test AtomTransmutationWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx - -from MDANSE import REGISTRY -from MDANSE.Chemistry import ATOMS_DATABASE -from MDANSE.Framework.Configurators.IConfigurator import ConfiguratorError -from MDANSE.Framework.UserDefinitionStore import UD_STORE -from MDANSE.GUI.Widgets.AtomSelectionWidget import AtomSelectionWidget -from MDANSE.GUI.Icons import ICONS - - -class AtomTransmutationWidget(AtomSelectionWidget): - udType = "atom_selection" - - 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=ATOMS_DATABASE.atoms - ) - 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) - - self._sizer.Add(panel, 1, wx.ALL | wx.EXPAND, 5) - - self._widgetPanel.GrandParent.Layout() - self._widgetPanel.GrandParent.Refresh() - - 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 sizerItemList: - panel = sizerItem.GetWindow() - children = panel.GetChildren() - udName = children[0].GetStringSelection() - element = children[2].GetStringSelection() - - if not element: - raise ConfiguratorError( - "No target element provided for %r selection." % udName - ) - - uds.append([udName, element]) - - if not uds: - return None - else: - return uds - - -REGISTRY["atom_transmutation"] = AtomTransmutationWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/AtomsListWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/AtomsListWidget.py deleted file mode 100644 index 1c8ed990f7..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/AtomsListWidget.py +++ /dev/null @@ -1,47 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/AtomsListWidget.py -# @brief Implements module/class/test AtomsListWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -from MDANSE import REGISTRY -from MDANSE.Framework.UserDefinitionStore import UD_STORE -from MDANSE.GUI.Widgets.UserDefinitionWidget import ( - UserDefinitionWidget, - UserDefinitionDialog, -) - - -class AtomListWidget(UserDefinitionWidget): - def on_new_definition(self, event): - dlg = UserDefinitionDialog(self, self._trajectory, self._type) - - dlg.plugin.set_natoms(self._configurator._nAtoms) - - dlg.plugin.enable_natoms_selection(False) - - dlg.ShowModal() - - def msg_set_ud(self, message): - uds = UD_STORE.filter(self._basename, self._type) - - uds = [ - v - for v in uds - if UD_STORE.get_definition(self._basename, self._type, v)["natoms"] - == self._configurator._nAtoms - ] - - self._availableUDs.SetItems(uds) - - -REGISTRY["atoms_list"] = AtomListWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/BooleanWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/BooleanWidget.py deleted file mode 100644 index 85907eccdb..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/BooleanWidget.py +++ /dev/null @@ -1,37 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/BooleanWidget.py -# @brief Implements module/class/test BooleanWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx - -from MDANSE import REGISTRY -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class BooleanWidget(IWidget): - def add_widgets(self): - sizer = wx.BoxSizer(wx.VERTICAL) - - self._boolean = wx.CheckBox(self._widgetPanel, wx.ID_ANY, label="Yes") - self._boolean.SetValue(self._configurator.default) - - sizer.Add(self._boolean, 1, wx.ALL | wx.EXPAND, 5) - - return sizer - - def get_widget_value(self): - return self._boolean.GetValue() - - -REGISTRY["boolean"] = BooleanWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/FloatWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/FloatWidget.py deleted file mode 100644 index 78e5cd906d..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/FloatWidget.py +++ /dev/null @@ -1,51 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/FloatWidget.py -# @brief Implements module/class/test FloatWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx - -from MDANSE import REGISTRY -from MDANSE.Framework.Configurable import ConfigurationError -from MDANSE.GUI.Widgets.StringWidget import StringWidget - - -class FloatWidget(StringWidget): - def add_widgets(self): - sizer = wx.BoxSizer(wx.VERTICAL) - - self._float = wx.TextCtrl( - self._widgetPanel, - wx.ID_ANY, - value=str(self._configurator.default), - style=wx.TE_PROCESS_ENTER, - ) - - sizer.Add(self._float, 0, wx.ALL, 5) - - return sizer - - def get_widget_value(self): - try: - val = float(self._float.GetValue()) - except ValueError: - raise ConfigurationError("Invalid value for %r entry" % self.name) - else: - return val - - @property - def widget(self): - return self._float - - -REGISTRY["float"] = FloatWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/FramesWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/FramesWidget.py deleted file mode 100644 index 2a7ba72e59..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/FramesWidget.py +++ /dev/null @@ -1,94 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/FramesWidget.py -# @brief Implements module/class/test FramesWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx -import wx.lib.intctrl as wxintctrl - -from MDANSE import REGISTRY -from MDANSE.Framework.InputData.EmptyData import EmptyData - -from MDANSE.GUI.DataController import DATA_CONTROLLER -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class FramesWidget(IWidget): - def add_widgets(self): - sizer = wx.BoxSizer(wx.HORIZONTAL) - - gbSizer = wx.GridBagSizer(5, 5) - - firstLabel = wx.StaticText(self._widgetPanel, wx.ID_ANY, label="First frame") - self._first = wxintctrl.IntCtrl( - self._widgetPanel, wx.ID_ANY, limited=True, allow_none=False - ) - - labelLabel = wx.StaticText(self._widgetPanel, wx.ID_ANY, label="Last frame") - self._last = wxintctrl.IntCtrl( - self._widgetPanel, wx.ID_ANY, limited=True, allow_none=False - ) - - stepLabel = wx.StaticText(self._widgetPanel, wx.ID_ANY, label="Frame step") - self._step = wxintctrl.IntCtrl( - self._widgetPanel, wx.ID_ANY, limited=True, allow_none=False - ) - - gbSizer.Add(firstLabel, (0, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer.Add(labelLabel, (0, 3), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer.Add(stepLabel, (0, 6), flag=wx.ALIGN_CENTER_VERTICAL) - - gbSizer.Add(self._first, (0, 1), flag=wx.EXPAND) - gbSizer.Add(self._last, (0, 4), flag=wx.EXPAND) - gbSizer.Add(self._step, (0, 7), flag=wx.EXPAND) - - gbSizer.AddGrowableCol(1) - gbSizer.AddGrowableCol(4) - gbSizer.AddGrowableCol(7) - - sizer.Add(gbSizer, 1, wx.ALL | wx.EXPAND, 5) - - return sizer - - def get_widget_value(self): - val = (self._first.GetValue(), self._last.GetValue(), self._step.GetValue()) - - return val - - def set_data(self, datakey): - self._trajectory = DATA_CONTROLLER[datakey] - - nFrames = len(self._trajectory.data) - 1 - - self._first.SetMin(0) - self._first.SetMax(nFrames - 1) - self._first.SetValue(0) - - self._last.SetMin(1) - self._last.SetMax(nFrames) - self._last.SetValue(nFrames) - - self._step.SetMin(1) - self._step.SetMax(nFrames) - self._step.SetValue(1) - - @property - def time(self): - f, l, s = self.get_value() - - time = self._trajectory.data.time[f:l:s] - - return time - - -REGISTRY["frames"] = FramesWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/GroupingLevelWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/GroupingLevelWidget.py deleted file mode 100644 index 341abf4944..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/GroupingLevelWidget.py +++ /dev/null @@ -1,24 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/GroupingLevelWidget.py -# @brief Implements module/class/test GroupingLevelWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -from MDANSE import REGISTRY -from MDANSE.GUI.Widgets.SingleChoiceWidget import SingleChoiceWidget - - -class GroupingLevelWidget(SingleChoiceWidget): - label = "Group coordinates by" - - -REGISTRY["grouping_level"] = GroupingLevelWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/HDFTrajectoryWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/HDFTrajectoryWidget.py deleted file mode 100644 index b9aa806e70..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/HDFTrajectoryWidget.py +++ /dev/null @@ -1,53 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/HDFTrajectoryWidget.py -# @brief Implements module/class/test HDFTrajectoryWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx - -from MDANSE import REGISTRY -from MDANSE.Framework.Configurable import ConfigurationError -from MDANSE.MolecularDynamics.Trajectory import Trajectory - -from MDANSE.GUI.DataController import DATA_CONTROLLER -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class HDFTrajectoryWidget(IWidget): - def add_widgets(self): - sizer = wx.BoxSizer(wx.VERTICAL) - - self._trajectory = wx.StaticText(self._widgetPanel, wx.ID_ANY) - - sizer.Add(self._trajectory, 1, wx.ALL | wx.EXPAND, 5) - - return sizer - - def set_data(self, datakey): - data = DATA_CONTROLLER[datakey].data - - if not isinstance(data, Trajectory): - return - - self._trajectory.SetLabel(datakey) - - def get_widget_value(self): - filename = self._trajectory.GetLabelText() - - if not filename: - raise ConfigurationError("No trajectory file selected", self) - - return filename - - -REGISTRY["hdf_trajectory"] = HDFTrajectoryWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/IWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/IWidget.py deleted file mode 100644 index 73402d41f4..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/IWidget.py +++ /dev/null @@ -1,98 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/IWidget.py -# @brief Implements module/class/test IWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import abc - -import wx - -from MDANSE.GUI import PUBLISHER - - -class IWidget(wx.Panel): - _registry = "widget" - - def __init__(self, parent, name, configurator, type, *args, **kwargs): - wx.Panel.__init__(self, parent, wx.ID_ANY, *args, **kwargs) - - self._parent = parent - - self._name = name - - self._configurator = configurator - - self._label = self._configurator.label - - self._type = type - - self.initialize() - - self.build_panel() - - self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy) - - PUBLISHER.subscribe(self._set_data, "msg_set_data") - - @property - def label(self): - return self._label - - @property - def name(self): - return self._name - - def initialize(self): - pass - - @abc.abstractmethod - def get_widget_value(self): - pass - - @abc.abstractmethod - def add_widgets(self): - pass - - def build_panel(self): - self._staticBox = wx.StaticBox(self, wx.ID_ANY, label=self.label) - - self._staticBoxSizer = wx.StaticBoxSizer(self._staticBox, wx.VERTICAL) - - self._widgetPanel = wx.Panel(self, wx.ID_ANY) - - self._widgetPanelSizer = self.add_widgets() - - self._widgetPanel.SetSizer(self._widgetPanelSizer) - - self._staticBoxSizer.Add(self._widgetPanel, 1, wx.ALL | wx.EXPAND, 0) - - self.SetSizer(self._staticBoxSizer) - - self._widgetPanel.GrandParent.Refresh() - - def get_value(self): - return self.get_widget_value() - - def set_data(self, datakey): - pass - - def _set_data(self, message): - plugin = message - if not plugin.is_parent(self): - return - - self.set_data(plugin.datakey) - - def OnDestroy(self, event): - PUBLISHER.unsubscribe(self._set_data, "msg_set_data") - event.Skip() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/InputDirectoryWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/InputDirectoryWidget.py deleted file mode 100644 index d9ea4c34eb..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/InputDirectoryWidget.py +++ /dev/null @@ -1,44 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/InputDirectoryWidget.py -# @brief Implements module/class/test InputDirectoryWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx -import wx.lib.filebrowsebutton as wxfile - -from MDANSE import REGISTRY -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class InputDirectoryWidget(IWidget): - def add_widgets(self): - default = self._configurator.default - - sizer = wx.BoxSizer(wx.VERTICAL) - - self._dirname = wxfile.DirBrowseButton( - self._widgetPanel, wx.ID_ANY, startDirectory=default, newDirectory=True - ) - self._dirname.SetValue(default) - - sizer.Add(self._dirname, 1, wx.ALL | wx.EXPAND, 0) - - return sizer - - def get_widget_value(self): - dirname = self._dirname.GetValue() - - return dirname - - -REGISTRY["input_directory"] = InputDirectoryWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/InputFileWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/InputFileWidget.py deleted file mode 100644 index 0c8e0f26ee..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/InputFileWidget.py +++ /dev/null @@ -1,62 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/InputFileWidget.py -# @brief Implements module/class/test InputFileWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx -import wx.lib.filebrowsebutton as wxfile - -from MDANSE import REGISTRY -from MDANSE.Framework.Configurable import ConfigurationError -from MDANSE.GUI import PUBLISHER -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class InputFileWidget(IWidget): - def add_widgets(self): - default = self._configurator.default - wildcard = self._configurator.wildcard - - sizer = wx.BoxSizer(wx.VERTICAL) - - self._browser = wxfile.FileBrowseButton( - self._widgetPanel, - wx.ID_ANY, - labelText="", - initialValue=default, - startDirectory=default, - fileMask=wildcard, - changeCallback=self.on_file_browsed, - ) - - sizer.Add(self._browser, 1, wx.ALL | wx.EXPAND, 5) - - return sizer - - def get_widget_value(self): - filename = self._browser.GetValue() - - if not self._configurator.optional: - if not filename: - raise ConfigurationError("No input file selected", self) - - return filename - - def on_file_browsed(self, event): - filename = self._browser.GetValue() - PUBLISHER.sendMessage( - "input_file_loaded", message=(self._configurator, filename) - ) - - -REGISTRY["input_file"] = InputFileWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/InstrumentResolutionWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/InstrumentResolutionWidget.py deleted file mode 100644 index c644c7fb20..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/InstrumentResolutionWidget.py +++ /dev/null @@ -1,241 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/InstrumentResolutionWidget.py -# @brief Implements module/class/test InstrumentResolutionWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import numpy as np - -from matplotlib.figure import Figure -from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigCanvas -from matplotlib.backends.backend_wxagg import ( - NavigationToolbar2WxAgg as NavigationToolbar, -) - -import wx - -from MDANSE import REGISTRY -from MDANSE.GUI.Widgets.IWidget import IWidget -from MDANSE.GUI.DataController import DATA_CONTROLLER -from MDANSE.GUI.ComboWidgets.ConfigurationPanel import ConfigurationPanel - - -class InstrumentResolutionDialog(wx.Dialog): - def __init__(self, parent=None, nSteps=100, timeStep=1.0): - wx.Dialog.__init__( - self, - parent, - wx.ID_ANY, - title="Instrument resolution", - style=wx.DEFAULT_DIALOG_STYLE - | wx.RESIZE_BORDER - | wx.MINIMIZE_BOX - | wx.MAXIMIZE_BOX, - ) - - self._parent = parent - - self._nSteps = nSteps - - self._timeStep = timeStep - - self._omegas = ( - 2.0 * np.pi * np.fft.fftshift(np.fft.fftfreq(self._nSteps, timeStep)) - ) - - self._currentKernel = None - - self._value = None - - self.build_dialog() - - def build_dialog(self): - sizer = wx.GridBagSizer(5, 5) - - sb = wx.StaticBox(self, wx.ID_ANY, label="kernel") - sbSizer = wx.StaticBoxSizer(sb, wx.HORIZONTAL) - self._kernelChoice = wx.Choice( - self, wx.ID_ANY, choices=list(REGISTRY["instrument_resolution"].keys()) - ) - self._kernelChoice.SetSelection(0) - sbSizer.Add(self._kernelChoice, 1, wx.ALL | wx.EXPAND, 5) - sizer.Add(sbSizer, (0, 0), flag=wx.EXPAND) - - self._parametersWidgets = ["", {}] - sb = wx.StaticBox(self, wx.ID_ANY, label="parameters") - self._parametersSizer = wx.StaticBoxSizer(sb, wx.HORIZONTAL) - sizer.Add(self._parametersSizer, (1, 0), flag=wx.EXPAND) - - sb = wx.StaticBox(self, wx.ID_ANY) - sbSizer = wx.StaticBoxSizer(sb, wx.HORIZONTAL) - self._cancel = wx.Button(self, wx.ID_ANY, label="Discard and quit") - self._plot = wx.Button(self, wx.ID_ANY, label="Plot") - self._ok = wx.Button(self, wx.ID_ANY, label="Save and quit") - sbSizer.Add(self._cancel, 0, wx.ALL, 5) - sbSizer.Add((-1, -1), 1, wx.ALL | wx.EXPAND, 5) - sbSizer.Add(self._plot, 0, wx.ALL, 5) - sbSizer.Add(self._ok, 0, wx.ALL, 5) - sizer.Add(sbSizer, (2, 0), span=(1, 2), flag=wx.EXPAND) - - sb = wx.StaticBox(self, wx.ID_ANY, label="plot") - sbSizer = wx.StaticBoxSizer(sb, wx.VERTICAL) - self._dpi = 100 - self._figure = Figure((5.0, 4.0), dpi=self._dpi) - self._canvas = FigCanvas(self, -1, self._figure) - self._axis = self._figure.add_subplot(111) - self._toolbar = NavigationToolbar(self._canvas) - sbSizer.Add(self._canvas, 1, wx.LEFT | wx.TOP | wx.GROW) - sbSizer.Add(self._toolbar, 0, wx.EXPAND) - sizer.Add(sbSizer, (0, 1), span=(2, 1), flag=wx.EXPAND) - - sizer.AddGrowableRow(1) - sizer.AddGrowableCol(1) - - self.SetSizer(sizer) - self.select_kernel(self._kernelChoice.GetStringSelection()) - - self.Bind(wx.EVT_BUTTON, self.on_cancel, self._cancel) - self.Bind(wx.EVT_BUTTON, self.on_plot_kernel, self._plot) - self.Bind(wx.EVT_BUTTON, self.on_ok, self._ok) - self.Bind(wx.EVT_CHOICE, self.on_select_kernel, self._kernelChoice) - # self.Bind(wx.EVT_CLOSE, self.on_close) - - self.plot() - - @property - def value(self): - return self._value - - def on_cancel(self, event): - self._value = None - - self.Close() - - def on_ok(self, event): - if not self._parametersPanel.validate(): - return - - self._value = (self._currentKernel, self._parametersPanel.get_value()) - - self.Close() - - def on_plot_kernel(self, event): - self.plot() - - def plot(self): - if not self._parametersPanel.validate(): - return - - kernelClass = REGISTRY["instrument_resolution"][self._currentKernel] - - resolution = kernelClass() - - resolution.setup(self._parametersPanel.get_value()) - - resolution.set_kernel(self._omegas, self._timeStep) - - self._axis.clear() - - self._axis.plot(self._omegas, resolution.omegaWindow) - self._axis.set_xlabel("omega (rad/ps)") - self._axis.set_ylabel("instrument resolution (a.u)") - - self._canvas.draw() - - def on_select_kernel(self, event): - self.select_kernel(event.GetString()) - - self.plot() - - def select_kernel(self, kernelName): - if kernelName == self._currentKernel: - return - - self._currentKernel = kernelName - - self._parametersSizer.Clear(deleteWindows=True) - - resolution = REGISTRY["instrument_resolution"][kernelName]() - - self.Freeze() - - self._parametersPanel = ConfigurationPanel(self, resolution, None) - for w in list(self._parametersPanel.widgets.values()): - self.Bind(wx.EVT_TEXT_ENTER, self.plot, w.widget) - - self._parametersSizer.Add(self._parametersPanel, 0, wx.ALL | wx.EXPAND, 5) - - self.Thaw() - - self._parametersSizer.Layout() - - self.Fit() - - -class InstrumentResolutionWidget(IWidget): - def add_widgets(self): - sizer = wx.BoxSizer(wx.HORIZONTAL) - - self._resolution = wx.TextCtrl( - self._widgetPanel, wx.ID_ANY, value=str(self._configurator.default) - ) - - self._setResolution = wx.Button(self._widgetPanel, wx.ID_ANY, label="Set") - self._setResolution.Enable(False) - - sizer.Add(self._resolution, 1, wx.ALL | wx.EXPAND, 5) - sizer.Add(self._setResolution, 0, wx.ALL | wx.EXPAND, 5) - - self.Bind(wx.EVT_BUTTON, self.on_set_instrument_resolution, self._setResolution) - - return sizer - - def get_widget_value(self): - return eval(self._resolution.GetValue()) - - def on_set_instrument_resolution(self, event): - frameCfgName = self._configurator.dependencies["frames"] - time = self.Parent.widgets[frameCfgName].time - timeStep = time[1] - time[0] - nSteps = len(time) - - self._instrumentResolutionDialog = InstrumentResolutionDialog( - self, nSteps, timeStep - ) - - self._instrumentResolutionDialog.ShowModal() - - value = self._instrumentResolutionDialog.value - - if value is not None: - self._resolution.SetValue(str(value)) - - self._instrumentResolutionDialog.Destroy() - - def set_data(self, datakey): - self._trajectory = DATA_CONTROLLER[datakey] - - self._setResolution.Enable(True) - - -REGISTRY["instrument_resolution"] = InstrumentResolutionWidget - -if __name__ == "__main__": - app = wx.App(False) - - p = InstrumentResolutionDialog() - - p.SetSize((800, 800)) - - p.ShowModal() - - app.MainLoop() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/IntegerWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/IntegerWidget.py deleted file mode 100644 index 0133ea305d..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/IntegerWidget.py +++ /dev/null @@ -1,60 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/IntegerWidget.py -# @brief Implements module/class/test IntegerWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx -import wx.lib.intctrl as wxintctrl - -from MDANSE import REGISTRY -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class IntegerWidget(IWidget): - def add_widgets(self): - sizer = wx.BoxSizer(wx.VERTICAL) - - cfg = self._configurator - - if self._configurator.choices: - self._integer = wx.SpinCtrl( - self._widgetPanel, - wx.ID_ANY, - min=cfg.choices[0], - max=cfg.choices[-1], - initial=cfg.default, - style=wx.SP_ARROW_KEYS | wx.SP_WRAP, - ) - else: - self._integer = wxintctrl.IntCtrl( - self._widgetPanel, - wx.ID_ANY, - value=cfg.default, - min=cfg.mini, - max=cfg.maxi, - limited=True, - allow_none=False, - style=wx.ALIGN_RIGHT, - ) - - sizer.Add(self._integer, 0, wx.ALL, 5) - - return sizer - - def get_widget_value(self): - val = self._integer.GetValue() - - return val - - -REGISTRY["integer"] = IntegerWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/InterpolationOrderWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/InterpolationOrderWidget.py deleted file mode 100644 index afd858b535..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/InterpolationOrderWidget.py +++ /dev/null @@ -1,52 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/InterpolationOrderWidget.py -# @brief Implements module/class/test InterpolationOrderWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx - -from MDANSE import REGISTRY -from MDANSE.GUI.DataController import DATA_CONTROLLER -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class InterpolationOrderWidget(IWidget): - def add_widgets(self): - sizer = wx.BoxSizer(wx.HORIZONTAL) - - label = wx.StaticText(self._widgetPanel, wx.ID_ANY, label="interpolation order") - - self._interpolationOrder = wx.Choice(self._widgetPanel, wx.ID_ANY) - - sizer.Add(label, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - sizer.Add(self._interpolationOrder, 0, wx.ALL, 5) - - return sizer - - def set_data(self, datakey): - trajectory = DATA_CONTROLLER[datakey] - - if "velocities" in trajectory.data.variables(): - self._interpolationOrder.SetItems(self._configurator.choices) - else: - self._interpolationOrder.SetItems(self._configurator.choices[1:]) - - self._interpolationOrder.SetStringSelection(self._configurator.choices[0]) - - def get_widget_value(self): - value = self._interpolationOrder.GetStringSelection() - - return value - - -REGISTRY["interpolation_order"] = InterpolationOrderWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/McStasInstrumentWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/McStasInstrumentWidget.py deleted file mode 100644 index 7b1f970f02..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/McStasInstrumentWidget.py +++ /dev/null @@ -1,88 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/McStasInstrumentWidget.py -# @brief Implements module/class/test McStasInstrumentWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import os -import re -import subprocess - -import wx - -from MDANSE import REGISTRY - -from MDANSE.GUI import PUBLISHER -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class McStasInstrumentWidget(IWidget): - _mcStasTypes = {"double": float, "int": int, "string": str} - - def add_widgets(self): - sizer = wx.BoxSizer(wx.HORIZONTAL) - - self._instrument = wx.Choice(self._widgetPanel, wx.ID_ANY) - - self._browse = wx.Button(self._widgetPanel, wx.ID_ANY, label="Browse") - - sizer.Add(self._instrument, 1, wx.ALL | wx.EXPAND, 5) - sizer.Add(self._browse, 0, wx.ALL, 5) - - self.Bind(wx.EVT_CHOICE, self.on_select_instrument, self._instrument) - self.Bind(wx.EVT_BUTTON, self.on_browse_instrument, self._browse) - - return sizer - - def on_browse_instrument(self, event): - dlg = wx.FileDialog( - self, - "select instrument executable", - os.getcwd(), - style=wx.FD_OPEN | wx.FD_CHANGE_DIR, - ) - - if dlg.ShowModal() == wx.ID_OK: - path = dlg.GetPath() - if not path in self._instrument.GetItems(): - self.select_instrument(path) - - dlg.Destroy() - - def select_instrument(self, path): - s = subprocess.Popen( - [path, "-h"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT - ) - instrParams = dict( - [ - (v[0], [v[1], v[2]]) - for v in re.findall( - "(\w+)\s*\((\w+)\)\s*\[default='(\S+)'\]", s.communicate()[0] - ) - ] - ) - self._instrument.Append(path) - self._instrument.Select(self._instrument.GetCount() - 1) - - PUBLISHER.sendMessage("msg_set_instrument", message=(self, instrParams)) - - def on_select_instrument(self, event): - if event.GetString() == self._instrument.GetStringSelection(): - return - - self.select_instrument(event.GetString()) - - def get_widget_value(self): - return self._instrument.GetStringSelection() - - -REGISTRY["mcstas_instrument"] = McStasInstrumentWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/McStasOptionsWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/McStasOptionsWidget.py deleted file mode 100644 index f5eb24f408..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/McStasOptionsWidget.py +++ /dev/null @@ -1,55 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/McStasOptionsWidget.py -# @brief Implements module/class/test McStasOptionsWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import collections - -import wx - -from MDANSE import REGISTRY -from MDANSE.Framework.Configurable import Configurable -from MDANSE.GUI.ComboWidgets.ConfigurationPanel import ConfigurationPanel -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class McStasOptionsWidget(IWidget): - _mcStasTypes = {"double": "float", "int": "integer", "str": "input_file"} - - def add_widgets(self): - sizer = wx.BoxSizer(wx.VERTICAL) - - options = Configurable() - - settings = collections.OrderedDict() - for name, value in list(self._configurator.default.items()): - settings[name] = ( - self._mcStasTypes[type(value).__name__], - {"default": value}, - ) - - options.set_settings(settings) - - self._panel = ConfigurationPanel(self._widgetPanel, options, None) - - sizer.Add(self._panel, 0, wx.ALL | wx.EXPAND, 5) - - return sizer - - def get_widget_value(self): - val = self._panel.get_value() - - return val - - -REGISTRY["mcstas_options"] = McStasOptionsWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/McStasParametersWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/McStasParametersWidget.py deleted file mode 100644 index 7b285e5777..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/McStasParametersWidget.py +++ /dev/null @@ -1,97 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/McStasParametersWidget.py -# @brief Implements module/class/test McStasParametersWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import collections - -import wx - -from MDANSE import REGISTRY -from MDANSE.Framework.Configurable import ConfigurationError -from MDANSE.Framework.Configurable import Configurable - -from MDANSE.GUI import PUBLISHER -from MDANSE.GUI.ComboWidgets.ConfigurationPanel import ConfigurationPanel -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class McStasParametersWidget(IWidget): - _mcStasTypes = {"double": "float", "int": "integer", "string": "input_file"} - - def initialize(self): - self._configurationPanel = None - - def add_widgets(self): - self._sizer = wx.BoxSizer(wx.VERTICAL) - - PUBLISHER.subscribe(self.msg_set_instrument, "msg_set_instrument") - - return self._sizer - - def OnDestroy(self, event): - PUBLISHER.unsubscribe(self.msg_set_instrument, "msg_set_instrument") - - IWidget.OnDestroy(self, event) - - def msg_set_instrument(self, message): - widget, parameters = message - - if not widget.Parent == self.Parent: - return - - for k in self._configurator.exclude: - parameters.pop(k) - - self._parameters = Configurable() - - settings = collections.OrderedDict() - for name, value in list(parameters.items()): - typ, default = value - settings[name] = (self._mcStasTypes[typ], {"default": default}) - - self._parameters.set_settings(settings) - - self._sizer.Clear(deleteWindows=True) - - self._widgetPanel.Freeze() - self._configurationPanel = ConfigurationPanel( - self._widgetPanel, self._parameters, None - ) - - for name, value in list(parameters.items()): - typ, default = value - if typ == "string": - self._configurationPanel.widgets[name]._browser.SetLabel( - "Text/File Entry" - ) - - self._sizer.Add(self._configurationPanel, 1, wx.ALL | wx.EXPAND, 5) - - self._widgetPanel.Thaw() - - self.Parent.Layout() - - # Trick to show the scrollbar after updating the configuration panel. - self.Parent.Parent.SendSizeEvent() - - def get_widget_value(self): - if self._configurationPanel is None: - raise ConfigurationError("McStas instrument is not yet defined") - - val = self._configurationPanel.get_value() - - return val - - -REGISTRY["mcstas_parameters"] = McStasParametersWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/MultipleChoicesWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/MultipleChoicesWidget.py deleted file mode 100644 index 268f707180..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/MultipleChoicesWidget.py +++ /dev/null @@ -1,44 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/MultipleChoicesWidget.py -# @brief Implements module/class/test MultipleChoicesWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx.combo - -from MDANSE import REGISTRY -from MDANSE.GUI.ComboWidgets.ComboCheckbox import ComboCheckbox -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class MultipleChoicesWidget(IWidget): - def add_widgets(self): - sizer = wx.BoxSizer(wx.VERTICAL) - - cfg = self._configurator - - self._choices = wx.combo.ComboCtrl( - self._widgetPanel, value=cfg.label, style=wx.CB_READONLY - ) - tcp = ComboCheckbox(cfg.choices, cfg.nChoices) - self._choices.SetPopupControl(tcp) - tcp.checklistbox.SetCheckedStrings(cfg.default) - - sizer.Add(self._choices, 1, wx.ALL | wx.EXPAND, 5) - - return sizer - - def get_widget_value(self): - return self._choices.GetStringSelection() - - -REGISTRY["multiple_choices"] = MultipleChoicesWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/NetCDFInputFileWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/NetCDFInputFileWidget.py deleted file mode 100644 index 40c34080aa..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/NetCDFInputFileWidget.py +++ /dev/null @@ -1,69 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/NetCDFInputFileWidget.py -# @brief Implements module/class/test NetCDFInputFileWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx - -import netCDF4 - -from MDANSE import REGISTRY -from MDANSE.Framework.Configurable import ConfigurationError - -from MDANSE.GUI import PUBLISHER -from MDANSE.GUI.DataController import DATA_CONTROLLER -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class NetCDFInputFileWidget(IWidget): - def __getattr__(self, attr): - return self._netcdf.variables[attr][:] - - def add_widgets(self): - sizer = wx.BoxSizer(wx.VERTICAL) - - self._selectNetCDF = wx.Choice(self._widgetPanel, wx.ID_ANY) - - sizer.Add(self._selectNetCDF, 1, wx.ALL | wx.EXPAND, 5) - - self.Bind(wx.EVT_CHOICE, self.on_select_netcdf, self._selectNetCDF) - - return sizer - - def on_select_netcdf(self, event): - filename = event.GetString() - - PUBLISHER.sendMessage("msg_set_netcdf", message=(self, filename)) - - def set_data(self, datakey): - self._netcdf = DATA_CONTROLLER[datakey].netcdf - - if not isinstance(self._netcdf, netCDF4.Dataset): - return - - self._selectNetCDF.SetItems(list(DATA_CONTROLLER.keys())) - - self._selectNetCDF.SetStringSelection(datakey) - - PUBLISHER.sendMessage("msg_set_netcdf", message=(self, datakey)) - - def get_widget_value(self): - filename = self._selectNetCDF.GetStringSelection() - - if not filename: - raise ConfigurationError("No NetCDF file selected", self) - - return filename - - -REGISTRY["netcdf_input_file"] = NetCDFInputFileWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/OutputDirectoryWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/OutputDirectoryWidget.py deleted file mode 100644 index 03ba57ef57..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/OutputDirectoryWidget.py +++ /dev/null @@ -1,25 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/OutputDirectoryWidget.py -# @brief Implements module/class/test OutputDirectoryWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -from MDANSE import REGISTRY - -from MDANSE.GUI.Widgets.InputDirectoryWidget import InputDirectoryWidget - - -class OutputDirectoryWidget(InputDirectoryWidget): - pass - - -REGISTRY["output_directory"] = OutputDirectoryWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/OutputFilesWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/OutputFilesWidget.py deleted file mode 100644 index cf6620f90e..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/OutputFilesWidget.py +++ /dev/null @@ -1,104 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/OutputFilesWidget.py -# @brief Implements module/class/test OutputFilesWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import glob -import itertools -import os -import os.path - -import wx -import wx.lib.filebrowsebutton as wxfile - -from MDANSE import REGISTRY - -from MDANSE.GUI.ComboWidgets.ComboCheckbox import ComboCheckbox -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class OutputFilesWidget(IWidget): - def __init__(self, *args, **kwargs): - IWidget.__init__(self, *args, **kwargs) - - @staticmethod - def _get_unique_filename(directory, basename): - filesInDirectory = [ - os.path.join(directory, e) - for e in itertools.chain( - glob.iglob(os.path.join(directory, "*")), - glob.iglob(os.path.join(directory, ".*")), - ) - if os.path.isfile(os.path.join(directory, e)) - ] - basenames = [os.path.splitext(f)[0] for f in filesInDirectory] - - initialPath = path = os.path.join(directory, basename) - comp = 1 - while True: - if path in basenames: - path = "%s(%d)" % (initialPath, comp) - comp += 1 - continue - return path - - def add_widgets(self): - sizer = wx.BoxSizer(wx.VERTICAL) - - self._filename = wxfile.FileBrowseButton( - self._widgetPanel, - wx.ID_ANY, - fileMode=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT, - labelText="Basename", - ) - - self._formats = wx.ComboCtrl( - self._widgetPanel, value="output formats", style=wx.CB_READONLY - ) - - tcp = ComboCheckbox(self._configurator.formats) - - self._formats.SetPopupControl(tcp) - - hSizer = wx.BoxSizer(wx.HORIZONTAL) - - hSizer.Add(self._filename, 4, wx.EXPAND | wx.ALL, 5) - hSizer.Add(self._formats, 1, wx.EXPAND | wx.ALL, 5) - - sizer.Add(hSizer, 0, wx.ALL | wx.EXPAND, 0) - - if len(self._configurator.formats) == 1: - self._formats.Hide() - - return sizer - - def get_widget_value(self): - filename = self._filename.GetValue() - - formats = self._formats.GetPopupControl().GetControl().GetCheckedStrings() - - return (filename, formats) - - def set_data(self, datakey): - basename = "%s_%s" % ( - os.path.splitext(os.path.basename(datakey))[0], - self._parent.type, - ) - trajectoryDir = os.path.dirname(datakey) - - path = OutputFilesWidget._get_unique_filename(trajectoryDir, basename) - - self._filename.SetValue(path) - - -REGISTRY["output_files"] = OutputFilesWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/PartialChargesWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/PartialChargesWidget.py deleted file mode 100644 index 44f9a32293..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/PartialChargesWidget.py +++ /dev/null @@ -1,54 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/PartialChargesWidget.py -# @brief Implements module/class/test PartialChargesWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import os - -import wx - -from MDANSE import REGISTRY - -from MDANSE.GUI.Widgets.UserDefinitionWidget import ( - UserDefinitionDialog, - UserDefinitionWidget, -) - - -class PartialChargesWidget(UserDefinitionWidget): - pass - - -REGISTRY["partial_charges"] = PartialChargesWidget - -if __name__ == "__main__": - from MDANSE import PLATFORM - from MDANSE.MolecularDynamics.Trajectory import Trajectory - - t = Trajectory( - os.path.join( - PLATFORM.example_data_directory(), "Trajectories", "HDF", "waterbox.h5" - ) - ) - - app = wx.App(False) - - p = UserDefinitionDialog(None, t, "partial_charges") - - p.SetSize((800, 800)) - - p.ShowModal() - - p.Destroy() - - app.MainLoop() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/ProjectionWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/ProjectionWidget.py deleted file mode 100644 index 2e58d51459..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/ProjectionWidget.py +++ /dev/null @@ -1,126 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/ProjectionWidget.py -# @brief Implements module/class/test ProjectionWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx - -from MDANSE import REGISTRY -from MDANSE.Framework.Configurable import ConfigurationError - -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class ProjectionWidget(IWidget): - def add_widgets(self): - sizer = wx.BoxSizer(wx.VERTICAL) - - gbSizer = wx.GridBagSizer(0, 0) - - self._none = wx.RadioButton( - self._widgetPanel, wx.ID_ANY, label="None", style=wx.RB_GROUP - ) - self._none.SetValue(True) - self._axial = wx.RadioButton(self._widgetPanel, wx.ID_ANY, label="Axial") - self._planar = wx.RadioButton(self._widgetPanel, wx.ID_ANY, label="Planar") - - self._panelAxial = wx.Panel(self._widgetPanel, wx.ID_ANY) - sizerAxial = wx.BoxSizer(wx.HORIZONTAL) - - labelAxial = wx.StaticText( - self._panelAxial, wx.ID_ANY, size=(80, -1), label="Axis vector" - ) - self._ax = wx.TextCtrl(self._panelAxial, wx.ID_ANY) - self._ay = wx.TextCtrl(self._panelAxial, wx.ID_ANY) - self._az = wx.TextCtrl(self._panelAxial, wx.ID_ANY) - - sizerAxial.Add(labelAxial, flag=wx.ALIGN_CENTER_VERTICAL) - sizerAxial.Add(self._ax, 1, wx.EXPAND | wx.ALL, 5) - sizerAxial.Add(self._ay, 1, wx.EXPAND | wx.ALL, 5) - sizerAxial.Add(self._az, 1, wx.EXPAND | wx.ALL, 5) - - self._panelAxial.SetSizer(sizerAxial) - self._panelAxial.Enable(False) - - self._panelPlanar = wx.Panel(self._widgetPanel, wx.ID_ANY) - sizerPlanar = wx.BoxSizer(wx.HORIZONTAL) - - labelPlanar = wx.StaticText( - self._panelPlanar, wx.ID_ANY, size=(80, -1), label="Normal vector" - ) - self._px = wx.TextCtrl(self._panelPlanar, wx.ID_ANY) - self._py = wx.TextCtrl(self._panelPlanar, wx.ID_ANY) - self._pz = wx.TextCtrl(self._panelPlanar, wx.ID_ANY) - - sizerPlanar.Add(labelPlanar, flag=wx.ALIGN_CENTER_VERTICAL) - sizerPlanar.Add(self._px, 1, wx.EXPAND | wx.ALL, 5) - sizerPlanar.Add(self._py, 1, wx.EXPAND | wx.ALL, 5) - sizerPlanar.Add(self._pz, 1, wx.EXPAND | wx.ALL, 5) - - self._panelPlanar.SetSizer(sizerPlanar) - self._panelPlanar.Enable(False) - - gbSizer.Add(self._none, (0, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer.Add(self._axial, (1, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer.Add(self._planar, (2, 0), flag=wx.ALIGN_CENTER_VERTICAL) - - gbSizer.Add(self._panelAxial, (1, 2), flag=wx.EXPAND) - - gbSizer.Add(self._panelPlanar, (2, 2), flag=wx.EXPAND) - - sizer.Add(gbSizer, 1, wx.EXPAND | wx.ALL, 5) - - self.Bind(wx.EVT_RADIOBUTTON, self.on_select_projection_mode, self._none) - self.Bind(wx.EVT_RADIOBUTTON, self.on_select_projection_mode, self._axial) - self.Bind(wx.EVT_RADIOBUTTON, self.on_select_projection_mode, self._planar) - - return sizer - - def get_widget_value(self): - rb = [rb for rb in (self._none, self._axial, self._planar) if rb.GetValue()][0] - - if rb == self._none: - return None - - elif rb == self._axial: - try: - val = ( - "axial", - tuple( - [float(v.GetValue()) for v in (self._ax, self._ay, self._az)] - ), - ) - except ValueError: - raise ConfigurationError("Invalid value for %r entry" % self.name) - else: - return val - - elif rb == self._planar: - try: - val = ( - "planar", - tuple([v.GetValue() for v in (self._px, self._py, self._pz)]), - ) - except ValueError: - raise ConfigurationError("Invalid value for %r entry" % self.name) - else: - return val - - def on_select_projection_mode(self, event): - rb = event.GetEventObject() - - self._panelAxial.Enable(rb == self._axial) - self._panelPlanar.Enable(rb == self._planar) - - -REGISTRY["projection"] = ProjectionWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/PythonObjectWidgets.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/PythonObjectWidgets.py deleted file mode 100644 index 90ec8b5093..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/PythonObjectWidgets.py +++ /dev/null @@ -1,51 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/PythonObjectWidgets.py -# @brief Implements module/class/test PythonObjectWidgets -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import ast - -import wx - -from MDANSE import REGISTRY - -from MDANSE.GUI.Widgets.IWidget import IWidget -from MDANSE.Framework.Configurators.IConfigurator import ConfiguratorError - - -class PythonObjectWidget(IWidget): - def add_widgets(self): - sizer = wx.BoxSizer(wx.VERTICAL) - - self._string = wx.TextCtrl( - self._widgetPanel, wx.ID_ANY, value=repr(self._configurator.default) - ) - - sizer.Add(self._string, 1, wx.ALL | wx.EXPAND, 5) - - return sizer - - def get_widget_value(self): - val = self._string.GetValue() - - try: - return ast.literal_eval(val) - except SyntaxError as e: - raise ConfiguratorError( - "The inputted python code could not be parsed due to the following error:\n\n" - "SyntaxError: %s" % e, - self, - ) - - -REGISTRY["python_object"] = PythonObjectWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/QVectorsWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/QVectorsWidget.py deleted file mode 100644 index 40a5e07b6d..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/QVectorsWidget.py +++ /dev/null @@ -1,54 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/QVectorsWidget.py -# @brief Implements module/class/test QVectorsWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import os - -import wx - -from MDANSE import REGISTRY - -from MDANSE.GUI.Widgets.UserDefinitionWidget import ( - UserDefinitionDialog, - UserDefinitionWidget, -) - - -class QVectorsWidget(UserDefinitionWidget): - pass - - -REGISTRY["q_vectors"] = QVectorsWidget - -if __name__ == "__main__": - from MDANSE import PLATFORM - from MDANSE.MolecularDynamics.Trajectory import Trajectory - - t = Trajectory( - os.path.join( - PLATFORM.example_data_directory(), "Trajectories", "HDF", "waterbox.h5" - ) - ) - - app = wx.App(False) - - p = UserDefinitionDialog(None, t, "q_vectors") - - p.SetSize((800, 800)) - - p.ShowModal() - - p.Destroy() - - app.MainLoop() diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/RangeWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/RangeWidget.py deleted file mode 100644 index 7b03123169..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/RangeWidget.py +++ /dev/null @@ -1,69 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/RangeWidget.py -# @brief Implements module/class/test RangeWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx - -from MDANSE import REGISTRY -from MDANSE.Framework.Configurable import ConfigurationError - -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class RangeWidget(IWidget): - def add_widgets(self): - sizer = wx.BoxSizer(wx.VERTICAL) - - gbSizer = wx.GridBagSizer(5, 5) - - firstLabel = wx.StaticText(self._widgetPanel, wx.ID_ANY, label="from") - labelLabel = wx.StaticText(self._widgetPanel, wx.ID_ANY, label="to") - stepLabel = wx.StaticText(self._widgetPanel, wx.ID_ANY, label="by step of") - - self._first = wx.TextCtrl(self._widgetPanel, wx.ID_ANY) - self._last = wx.TextCtrl(self._widgetPanel, wx.ID_ANY) - self._step = wx.TextCtrl(self._widgetPanel, wx.ID_ANY) - - first, last, step = self._configurator.default - - self._first.SetValue(str(first)) - self._last.SetValue(str(last)) - self._step.SetValue(str(step)) - - gbSizer.Add(firstLabel, (0, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer.Add(labelLabel, (0, 3), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer.Add(stepLabel, (0, 6), flag=wx.ALIGN_CENTER_VERTICAL) - - gbSizer.Add(self._first, (0, 1), flag=wx.EXPAND) - gbSizer.Add(self._last, (0, 4), flag=wx.EXPAND) - gbSizer.Add(self._step, (0, 7), flag=wx.EXPAND) - - sizer.Add(gbSizer, 1, wx.ALL | wx.EXPAND, 5) - - return sizer - - def get_widget_value(self): - try: - val = ( - self._configurator.valueType(self._first.GetValue()), - self._configurator.valueType(self._last.GetValue()), - self._configurator.valueType(self._step.GetValue()), - ) - except ValueError: - raise ConfigurationError("Invalid value for %r entry" % self.name) - else: - return val - - -REGISTRY["range"] = RangeWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/RunningModeWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/RunningModeWidget.py deleted file mode 100644 index 730c271980..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/RunningModeWidget.py +++ /dev/null @@ -1,95 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/RunningModeWidget.py -# @brief Implements module/class/test RunningModeWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import multiprocessing - -import wx - -from MDANSE import REGISTRY - -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class RunningModeWidget(IWidget): - def initialize(self): - self._totalNumberOfProcessors = multiprocessing.cpu_count() - - def add_widgets(self): - sizer = wx.BoxSizer(wx.VERTICAL) - - panel = wx.Panel(self._widgetPanel, wx.ID_ANY, style=wx.BORDER_SUNKEN) - - gbSizer = wx.GridBagSizer(5, 5) - - self._radiobuttons = [] - self._radiobuttons.append( - wx.RadioButton( - panel, - wx.ID_ANY, - label="monoprocessor", - style=wx.RB_GROUP, - name="monoprocessor", - ) - ) - self._radiobuttons.append( - wx.RadioButton( - panel, wx.ID_ANY, label="multiprocessor", name="multiprocessor" - ) - ) - self._radiobuttons[0].SetValue(True) - - self._processors = wx.SpinCtrl( - panel, - wx.ID_ANY, - initial=1, - min=1, - max=multiprocessing.cpu_count(), - style=wx.SP_WRAP | wx.SP_ARROW_KEYS, - ) - self._processors.Enable(False) - - gbSizer.Add(self._radiobuttons[0], (0, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer.Add(self._radiobuttons[1], (1, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer.Add(self._processors, (1, 1)) - - panel.SetSizer(gbSizer) - - sizer.Add(panel, 1, wx.ALL | wx.EXPAND, 5) - - for rb in self._radiobuttons: - rb.Bind(wx.EVT_RADIOBUTTON, self.on_select_running_mode) - - return sizer - - def get_widget_value(self): - name = [rb for rb in self._radiobuttons if rb.GetValue()][0].GetName() - - if name == "monoprocessor": - value = ("monoprocessor",) - - elif name == "multiprocessor": - value = ("multiprocessor", self._processors.GetValue()) - - return value - - def on_select_running_mode(self, event): - btn = event.GetEventObject() - - name = btn.GetName() - - self._processors.Enable(name == "multiprocessor") - - -REGISTRY["running_mode"] = RunningModeWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/SingleChoiceWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/SingleChoiceWidget.py deleted file mode 100644 index 2685d57796..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/SingleChoiceWidget.py +++ /dev/null @@ -1,40 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/SingleChoiceWidget.py -# @brief Implements module/class/test SingleChoiceWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx - -from MDANSE import REGISTRY - -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class SingleChoiceWidget(IWidget): - def add_widgets(self): - sizer = wx.BoxSizer(wx.VERTICAL) - - self._choices = wx.Choice( - self._widgetPanel, wx.ID_ANY, choices=self._configurator.choices - ) - self._choices.SetStringSelection(self._configurator.default) - - sizer.Add(self._choices, 1, wx.ALL | wx.EXPAND, 5) - - return sizer - - def get_widget_value(self): - return self._choices.GetStringSelection() - - -REGISTRY["single_choice"] = SingleChoiceWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/SingleOutputFileWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/SingleOutputFileWidget.py deleted file mode 100644 index 77d55be5f9..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/SingleOutputFileWidget.py +++ /dev/null @@ -1,110 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/OutputFilesWidget.py -# @brief Implements module/class/test OutputFilesWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import glob -import itertools -import os -import os.path - -import wx.combo -import wx.lib.filebrowsebutton as wxfile - -from MDANSE import REGISTRY - -from MDANSE.GUI import PUBLISHER -from MDANSE.GUI.ComboWidgets.ComboCheckbox import ComboCheckbox -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class SingleOutputFileWidget(IWidget): - def __init__(self, *args, **kwargs): - IWidget.__init__(self, *args, **kwargs) - - PUBLISHER.subscribe(self.msg_input_file_set, "input_file_loaded") - - @staticmethod - def _get_unique_filename(filename): - directory = os.path.dirname(filename) - - filesInDirectory = [ - os.path.join(directory, e) - for e in itertools.chain( - glob.iglob(os.path.join(directory, "*")), - glob.iglob(os.path.join(directory, ".*")), - ) - if os.path.isfile(os.path.join(directory, e)) - ] - - path = filename - comp = 1 - while True: - if path in filesInDirectory: - filenameWithoutExtension = os.path.splitext(filename)[0] - path = "%s(%d)" % (filenameWithoutExtension, comp) - comp += 1 - continue - return path - - def add_widgets(self): - sizer = wx.BoxSizer(wx.VERTICAL) - - self._filename = wxfile.FileBrowseButton( - self._widgetPanel, - wx.ID_ANY, - fileMode=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT, - labelText="Filename", - ) - - hSizer = wx.BoxSizer(wx.HORIZONTAL) - - hSizer.Add(self._filename, 4, wx.EXPAND | wx.ALL, 5) - - sizer.Add(hSizer, 0, wx.ALL | wx.EXPAND, 0) - - return sizer - - def get_widget_value(self): - filename = self._filename.GetValue() - - return (os.path.splitext(filename)[0], self._configurator.format) - - def msg_input_file_set(self, message): - configurator, inputFilename = message - - if self._configurator.root is None: - return - - if self._configurator.root == configurator.name: - inputFileNameWithoutExtension = os.path.splitext(inputFilename)[0] - filename = "%s%s" % ( - inputFileNameWithoutExtension, - REGISTRY["format"][self._configurator.format].extension, - ) - - path = SingleOutputFileWidget._get_unique_filename(filename) - self._filename.SetValue(path) - - def set_data(self, datakey): - if datakey is None: - filename = os.path.join(os.getcwd(), "output.nc") - else: - filename = datakey - - path = SingleOutputFileWidget._get_unique_filename(filename) - - self._filename.SetValue(path) - - -REGISTRY["single_output_file"] = SingleOutputFileWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/StringWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/StringWidget.py deleted file mode 100644 index a3cb67a3fd..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/StringWidget.py +++ /dev/null @@ -1,41 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/StringWidget.py -# @brief Implements module/class/test StringWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx - -from MDANSE import REGISTRY - -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class StringWidget(IWidget): - def add_widgets(self): - sizer = wx.BoxSizer(wx.VERTICAL) - - self._string = wx.TextCtrl( - self._widgetPanel, wx.ID_ANY, value=self._configurator.default - ) - - sizer.Add(self._string, 0, wx.ALL, 5) - - return sizer - - def get_widget_value(self): - val = self._string.GetValue() - - return val - - -REGISTRY["string"] = StringWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/TrajectoryVariableWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/TrajectoryVariableWidget.py deleted file mode 100644 index 2de2d54db8..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/TrajectoryVariableWidget.py +++ /dev/null @@ -1,43 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/TrajectoryVariableWidget.py -# @brief Implements module/class/test TrajectoryVariableWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx - -from MDANSE import REGISTRY - -from MDANSE.GUI.DataController import DATA_CONTROLLER -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class TrajectoryVariableWidget(IWidget): - def add_widgets(self): - sizer = wx.BoxSizer(wx.VERTICAL) - - self._variable = wx.Choice(self._widgetPanel, wx.ID_ANY, choices=[]) - - sizer.Add(self._variable, 1, wx.ALL | wx.EXPAND, 5) - - return sizer - - def get_widget_value(self): - return self._variable.GetStringSelection() - - def set_data(self, datakey): - trajectory = DATA_CONTROLLER[datakey].data - self._variable.SetItems([v for v in trajectory["/configuration"]]) - self._variable.SetSelection(0) - - -REGISTRY["trajectory_variable"] = TrajectoryVariableWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/UserDefinitionWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/UserDefinitionWidget.py deleted file mode 100644 index 6117ebde6a..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/UserDefinitionWidget.py +++ /dev/null @@ -1,122 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/UserDefinitionWidget.py -# @brief Implements module/class/test UserDefinitionWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import abc -import os - -import wx -import wx.aui as wxaui - -from MDANSE import LOGGER, REGISTRY -from MDANSE.Framework.UserDefinitionStore import UD_STORE - -from MDANSE.GUI import PUBLISHER -from MDANSE.GUI.DataController import DATA_CONTROLLER -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class UserDefinitionDialog(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.SetSize(self._plugin.GetSize()) - - self._plugin.set_trajectory(trajectory) - - PUBLISHER.sendMessage("msg_set_data", message=self._plugin) - - @property - def plugin(self): - return self._plugin - - -class UserDefinitionWidget(IWidget, metaclass=abc.ABCMeta): - def add_widgets(self): - sizer = wx.BoxSizer(wx.HORIZONTAL) - - self._availableUDs = wx.Choice(self._widgetPanel, wx.ID_ANY, style=wx.CB_SORT) - viewUD = wx.Button( - self._widgetPanel, wx.ID_ANY, label="View selected definition" - ) - newUD = wx.Button(self._widgetPanel, wx.ID_ANY, label="New definition") - sizer.Add(self._availableUDs, 1, wx.ALL | wx.EXPAND, 5) - sizer.Add(viewUD, 0, wx.ALL | wx.EXPAND, 5) - sizer.Add(newUD, 0, wx.ALL | wx.EXPAND, 5) - - PUBLISHER.subscribe(self.msg_set_ud, "msg_set_ud") - - self.Bind(wx.EVT_BUTTON, self.on_view_definition, viewUD) - self.Bind(wx.EVT_BUTTON, self.on_new_definition, newUD) - - return sizer - - def OnDestroy(self, event): - PUBLISHER.unsubscribe(self.msg_set_ud, "msg_set_ud") - IWidget.OnDestroy(self, event) - - def on_view_definition(self, event): - viewUD = event.GetEventObject() - ud = viewUD.Parent.GetChildren()[0].GetStringSelection() - if not ud: - LOGGER("Please select a user definition", "error", ["dialog"]) - return - - from MDANSE.GUI.UserDefinitionViewer import UserDefinitionViewer - - f = UserDefinitionViewer(self, ud=[self._basename, self._type, ud]) - - f.Show() - - def on_new_definition(self, event): - dlg = UserDefinitionDialog(None, self._trajectory, self._type) - - dlg.ShowModal() - - def get_widget_value(self): - return str(self._availableUDs.GetStringSelection()) - - def set_data(self, datakey): - self._filename = datakey - - self._trajectory = DATA_CONTROLLER[datakey] - - self._basename = os.path.basename(self._filename) - - self.msg_set_ud(None) - - def msg_set_ud(self, message): - uds = UD_STORE.filter(self._basename, self._type) - - currentSelection = self._availableUDs.GetStringSelection() - - self._availableUDs.SetItems(uds) - - if currentSelection: - self._availableUDs.SetStringSelection(currentSelection) diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/VectorWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/VectorWidget.py deleted file mode 100644 index fe40b30ee4..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/VectorWidget.py +++ /dev/null @@ -1,69 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/VectorWidget.py -# @brief Implements module/class/test VectorWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx - -from MDANSE import REGISTRY -from MDANSE.Framework.Configurable import ConfigurationError - -from MDANSE.GUI.Widgets.IWidget import IWidget - - -class VectorWidget(IWidget): - def add_widgets(self): - sizer = wx.BoxSizer(wx.HORIZONTAL) - - gbSizer = wx.GridBagSizer(5, 5) - - xLabel = wx.StaticText(self._widgetPanel, wx.ID_ANY, label="x-component") - yLabel = wx.StaticText(self._widgetPanel, wx.ID_ANY, label="y-component") - zLabel = wx.StaticText(self._widgetPanel, wx.ID_ANY, label="z-component") - - self._x = wx.TextCtrl(self._widgetPanel, wx.ID_ANY) - self._y = wx.TextCtrl(self._widgetPanel, wx.ID_ANY) - self._z = wx.TextCtrl(self._widgetPanel, wx.ID_ANY) - - cfg = self._configurator - - self._x.SetValue(str(cfg.default[0])) - self._y.SetValue(str(cfg.default[1])) - self._z.SetValue(str(cfg.default[2])) - - gbSizer.Add(xLabel, (0, 0), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer.Add(yLabel, (0, 3), flag=wx.ALIGN_CENTER_VERTICAL) - gbSizer.Add(zLabel, (0, 6), flag=wx.ALIGN_CENTER_VERTICAL) - - gbSizer.Add(self._x, (0, 1), flag=wx.EXPAND) - gbSizer.Add(self._y, (0, 4), flag=wx.EXPAND) - gbSizer.Add(self._z, (0, 7), flag=wx.EXPAND) - - sizer.Add(gbSizer, 1, wx.ALL | wx.EXPAND, 5) - - return sizer - - def get_widget_value(self): - try: - val = ( - self._configurator.valueType(self._x.GetValue()), - self._configurator.valueType(self._y.GetValue()), - self._configurator.valueType(self._z.GetValue()), - ) - except ValueError: - raise ConfigurationError("Invalid value for %r entry" % self.name) - else: - return val - - -REGISTRY["vector"] = VectorWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/WeightsWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/WeightsWidget.py deleted file mode 100644 index 97388d00a1..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/WeightsWidget.py +++ /dev/null @@ -1,25 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/WeightsWidget.py -# @brief Implements module/class/test WeightsWidget -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -from MDANSE import REGISTRY - -from MDANSE.GUI.Widgets.SingleChoiceWidget import SingleChoiceWidget - - -class WeightsWidget(SingleChoiceWidget): - pass - - -REGISTRY["weights"] = WeightsWidget diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/__init__.py deleted file mode 100644 index 7dae10137f..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Widgets/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/Widgets/__init__.py -# @brief Implements module/class/test __init__ -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/WorkingPanel.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/WorkingPanel.py deleted file mode 100644 index af40ce94f8..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/WorkingPanel.py +++ /dev/null @@ -1,124 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/WorkingPanel.py -# @brief Implements module/class/test WorkingPanel -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import wx -import wx.aui as wxaui - -from MDANSE import REGISTRY - -from MDANSE.GUI import PUBLISHER -from MDANSE.GUI.DataController import DATA_CONTROLLER -from MDANSE.GUI.Plugins.IPlugin import uninit_aui_managers - - -class DropTarget(wx.TextDropTarget): - def __init__(self, targetPanel): - wx.TextDropTarget.__init__(self) - self._targetPanel = targetPanel - - def OnDropText(self, x, y, pluginName): - self._targetPanel.drop(pluginName) - - @property - def target_panel(self): - return self._targetPanel - - -class WorkingPanel(wx.Panel): - def __init__(self, parent): - wx.Panel.__init__(self, parent, wx.ID_ANY) - - self._data = None - - self.build_panel() - - self.SetDropTarget(DropTarget(self)) - - self._notebook.Bind( - wxaui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.on_close_page, self._notebook - ) - self._notebook.Bind(wxaui.EVT_AUINOTEBOOK_PAGE_CHANGED, self.on_changing_page) - self._notebook.Bind(wx.EVT_CHILD_FOCUS, self.on_changing_page) - - @property - def active_page(self): - return self._notebook.GetPage(self._notebook.GetSelection()) - - def build_panel(self): - self._notebook = wxaui.AuiNotebook(self) - - sizer = wx.BoxSizer(wx.VERTICAL) - - sizer.Add(self._notebook, 1, wx.EXPAND, 0) - - self.SetSizer(sizer) - - def drop(self, filename): - data = DATA_CONTROLLER.get(filename, None) - - if data is None: - return - - container = REGISTRY["plugin"].get(data._type, None) - - if container is None: - return - - container = container(self, filename) - - self._notebook.AddPage(container, data.shortname) - - self._notebook.SetFocus() - - self._notebook.SetSelection(self._notebook.GetPageCount() - 1) - - def add_empty_data(self): - container = REGISTRY["plugin"].get("empty_data") - - container = container(self, "empty_data") - - self._notebook.AddPage(container, "Empty data") - - self._notebook.SetFocus() - - def on_changing_page(self, event=None): - if self._notebook.GetPageCount() == 0: - return - - dataPlugin = self._notebook.GetPage(self._notebook.GetSelection()) - - PUBLISHER.sendMessage("msg_set_plugins_tree", message=dataPlugin) - - def on_close_page(self, event): - d = wx.MessageDialog( - None, - "Closing this data will also close all the other plugins 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: - event.Veto() - return - - if self._notebook.GetPageCount() == 1: - PUBLISHER.sendMessage("msg_set_plugins_tree", message=None) - - currentPage = self._notebook.GetCurrentPage() - - uninit_aui_managers(currentPage._mgr) - - @property - def notebook(self): - return self._notebook diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/GUI/__init__.py deleted file mode 100644 index 7357690345..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/GUI/__init__.py +++ /dev/null @@ -1,68 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/GUI/__init__.py -# @brief Implements module/class/test __init__ -# -# @homepage https://www.isis.stfc.ac.uk/Pages/MDANSEproject.aspx -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Scientific Computing Group at ILL (see AUTHORS) -# -# ************************************************************************** - -import glob -import os - -import distro - -import wx - -from MDANSE import PLATFORM -from MDANSE.Externals.pubsub import pub as PUBLISHER - -# Hack for the (in)famous "(python:865): LIBDBUSMENU-GLIB-WARNING **: Trying to remove a child that doesn't believe we're it's parent." -try: - if distro.linux_distribution()[0].lower() == "ubuntu": - os.environ["UBUNTU_MENUPROXY"] = "0" -except: - pass - -if PLATFORM.name == "macos": - wx.SystemOptions.SetOption("osx.openfiledialog.always-show-types", "1") - -from MDANSE import REGISTRY -from MDANSE.GUI.Plugins.DataPlugin import DataPlugin -from MDANSE.GUI.Plugins.JobPlugin import JobPlugin - -REGISTRY.update(os.path.join(os.path.dirname(__file__), "Handlers")) -REGISTRY.update(os.path.join(os.path.dirname(__file__), "Plugins")) -REGISTRY.update(os.path.join(os.path.dirname(__file__), "Widgets")) - -for job in list(REGISTRY["job"].values()): - if not hasattr(job, "_type"): - continue - - attrs = { - "_type": job._type, - "ancestor": getattr(job, "ancestor", job.ancestor), - "category": getattr(job, "category", ("Miscellaneous",)), - "label": getattr(job, "label", job.__name__), - } - - kls = type("%sPlugin" % job.__name__, (JobPlugin,), attrs) - REGISTRY[job._type] = kls - -for data in list(REGISTRY["input_data"].values()): - if not hasattr(data, "_type"): - continue - - attrs = { - "_type": data._type, - "label": " ".join("".split("_")).capitalize(), - "ancestor": ["empty_data"], - } - kls = type("%sPlugin" % data.__name__, (DataPlugin,), attrs) - REGISTRY[data._type] = kls diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/Icons/__init__.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/__init__.py rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/__init__.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/about.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/about.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/about.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/about.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/api.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/api.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/api.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/api.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/atom.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/atom.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/atom.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/atom.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/bug.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/bug.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/bug.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/bug.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/clock.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/clock.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/clock.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/clock.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/element.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/element.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/element.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/element.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/empty_data.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/empty_data.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/empty_data.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/empty_data.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/first.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/first.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/first.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/first.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/help.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/help.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/help.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/help.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/hourglass.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/hourglass.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/hourglass.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/hourglass.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/last.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/last.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/last.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/last.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/load.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/load.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/load.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/load.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/log.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/log.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/log.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/log.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/logfile.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/logfile.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/logfile.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/logfile.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/mdanse.icns b/MDANSE_GUI/Src/MDANSE_GUI/Icons/mdanse.icns similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/mdanse.icns rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/mdanse.icns diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/minus.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/minus.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/minus.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/minus.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/old_mdanse.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/old_mdanse.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/old_mdanse.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/old_mdanse.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/pause.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/pause.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/pause.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/pause.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/periodic_table.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/periodic_table.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/periodic_table.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/periodic_table.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/play.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/play.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/play.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/play.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/plot.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/plot.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/plot.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/plot.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/plus.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/plus.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/plus.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/plus.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/preferences.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/preferences.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/preferences.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/preferences.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/quit.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/quit.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/quit.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/quit.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/registry.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/registry.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/registry.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/registry.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/run.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/run.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/run.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/run.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/shell.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/shell.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/shell.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/shell.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/stop.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/stop.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/stop.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/stop.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/template.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/template.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/template.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/template.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/units.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/units.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/units.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/units.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/user.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/user.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/user.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/user.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/user_definitions.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/user_definitions.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/user_definitions.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/user_definitions.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/web.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/web.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/web.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/web.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/working_directory.png b/MDANSE_GUI/Src/MDANSE_GUI/Icons/working_directory.png similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/GUI/Icons/working_directory.png rename to MDANSE_GUI/Src/MDANSE_GUI/Icons/working_directory.png diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/AtomSelectionWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/AtomSelectionWidget.py similarity index 94% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/AtomSelectionWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/AtomSelectionWidget.py index 3b51d62ac0..3067dbf1f5 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/AtomSelectionWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/AtomSelectionWidget.py @@ -22,7 +22,7 @@ from qtpy.QtCore import Qt, Slot from qtpy.QtGui import QStandardItemModel, QStandardItem -from MDANSE_GUI.PyQtGUI.InputWidgets.WidgetBase import WidgetBase +from MDANSE_GUI.InputWidgets.WidgetBase import WidgetBase class SelectionDialog(QDialog): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/AtomTransmutationWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/AtomTransmutationWidget.py similarity index 90% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/AtomTransmutationWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/AtomTransmutationWidget.py index 340f450658..442047710b 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/AtomTransmutationWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/AtomTransmutationWidget.py @@ -23,8 +23,8 @@ from qtpy.QtCore import Qt, Slot from qtpy.QtGui import QStandardItemModel, QStandardItem -from MDANSE_GUI.PyQtGUI.InputWidgets.WidgetBase import WidgetBase -from MDANSE_GUI.PyQtGUI.InputWidgets.AtomSelectionWidget import AtomSelectionWidget +from MDANSE_GUI.InputWidgets.WidgetBase import WidgetBase +from MDANSE_GUI.InputWidgets.AtomSelectionWidget import AtomSelectionWidget class AtomTransmutationWidget(WidgetBase): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/BackupWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/BackupWidget.py similarity index 95% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/BackupWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/BackupWidget.py index 9df3742d3e..6c4569e0e8 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/BackupWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/BackupWidget.py @@ -17,7 +17,7 @@ from qtpy.QtWidgets import QLineEdit from qtpy.QtCore import Slot, Signal -from MDANSE_GUI.PyQtGUI.InputWidgets.WidgetBase import WidgetBase +from MDANSE_GUI.InputWidgets.WidgetBase import WidgetBase class BackupWidget(WidgetBase): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/BooleanWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/BooleanWidget.py similarity index 93% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/BooleanWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/BooleanWidget.py index d6502bd885..49c79d0e50 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/BooleanWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/BooleanWidget.py @@ -16,7 +16,7 @@ from qtpy.QtWidgets import QCheckBox from qtpy.QtCore import Slot, Qt -from MDANSE_GUI.PyQtGUI.InputWidgets.WidgetBase import WidgetBase +from MDANSE_GUI.InputWidgets.WidgetBase import WidgetBase class BooleanWidget(WidgetBase): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/ComboWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/ComboWidget.py similarity index 94% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/ComboWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/ComboWidget.py index 81ad3376b7..cb5c09e684 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/ComboWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/ComboWidget.py @@ -16,7 +16,7 @@ from qtpy.QtWidgets import QComboBox from qtpy.QtCore import Slot -from MDANSE_GUI.PyQtGUI.InputWidgets.WidgetBase import WidgetBase +from MDANSE_GUI.InputWidgets.WidgetBase import WidgetBase class ComboWidget(WidgetBase): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/DummyWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/DummyWidget.py similarity index 96% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/DummyWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/DummyWidget.py index ddea512dba..34e0144a48 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/DummyWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/DummyWidget.py @@ -18,7 +18,7 @@ from qtpy.QtGui import QIntValidator from MDANSE.Framework.InputData.HDFTrajectoryInputData import HDFTrajectoryInputData -from MDANSE_GUI.PyQtGUI.InputWidgets.WidgetBase import WidgetBase +from MDANSE_GUI.InputWidgets.WidgetBase import WidgetBase class DummyWidget(WidgetBase): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/FloatWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/FloatWidget.py similarity index 95% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/FloatWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/FloatWidget.py index 45726f7024..44c1d42c4a 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/FloatWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/FloatWidget.py @@ -17,7 +17,7 @@ from qtpy.QtCore import Slot, Signal from qtpy.QtGui import QDoubleValidator -from MDANSE_GUI.PyQtGUI.InputWidgets.WidgetBase import WidgetBase +from MDANSE_GUI.InputWidgets.WidgetBase import WidgetBase class FloatWidget(WidgetBase): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/FramesWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/FramesWidget.py similarity index 95% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/FramesWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/FramesWidget.py index f78e2335f2..d6ce918e21 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/FramesWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/FramesWidget.py @@ -17,7 +17,7 @@ from qtpy.QtCore import Slot, Signal from qtpy.QtGui import QIntValidator -from MDANSE_GUI.PyQtGUI.InputWidgets.WidgetBase import WidgetBase +from MDANSE_GUI.InputWidgets.WidgetBase import WidgetBase class FramesWidget(WidgetBase): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/HDFTrajectoryWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/HDFTrajectoryWidget.py similarity index 94% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/HDFTrajectoryWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/HDFTrajectoryWidget.py index abdfa32c8d..4b605faa69 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/HDFTrajectoryWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/HDFTrajectoryWidget.py @@ -18,7 +18,7 @@ from qtpy.QtGui import QIntValidator from MDANSE.Framework.InputData.HDFTrajectoryInputData import HDFTrajectoryInputData -from MDANSE_GUI.PyQtGUI.InputWidgets.WidgetBase import WidgetBase +from MDANSE_GUI.InputWidgets.WidgetBase import WidgetBase class HDFTrajectoryWidget(WidgetBase): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/IWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/IWidget.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/IWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/IWidget.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/InputDirectoryWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/InputDirectoryWidget.py similarity index 89% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/InputDirectoryWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/InputDirectoryWidget.py index 26cc644224..25696701bd 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/InputDirectoryWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/InputDirectoryWidget.py @@ -15,7 +15,7 @@ from qtpy.QtWidgets import QFileDialog -from MDANSE_GUI.PyQtGUI.InputWidgets.InputFileWidget import InputFileWidget +from MDANSE_GUI.InputWidgets.InputFileWidget import InputFileWidget class InputDirectoryWidget(InputFileWidget): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/InputFileWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/InputFileWidget.py similarity index 92% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/InputFileWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/InputFileWidget.py index 408413dd6c..5d69921adb 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/InputFileWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/InputFileWidget.py @@ -16,8 +16,8 @@ from qtpy.QtWidgets import QLineEdit, QPushButton, QFileDialog from qtpy.QtCore import Slot -from MDANSE_GUI.PyQtGUI.InputWidgets.WidgetBase import WidgetBase -from MDANSE_GUI.PyQtGUI.Widgets.GeneralWidgets import translate_file_associations +from MDANSE_GUI.InputWidgets.WidgetBase import WidgetBase +from MDANSE_GUI.Widgets.GeneralWidgets import translate_file_associations class InputFileWidget(WidgetBase): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/InstrumentResolutionWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/InstrumentResolutionWidget.py similarity index 95% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/InstrumentResolutionWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/InstrumentResolutionWidget.py index 36167ccc0f..50d89e2844 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/InstrumentResolutionWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/InstrumentResolutionWidget.py @@ -25,7 +25,7 @@ from qtpy.QtCore import Qt, Slot from qtpy.QtGui import QDoubleValidator -from MDANSE_GUI.PyQtGUI.InputWidgets.WidgetBase import WidgetBase +from MDANSE_GUI.InputWidgets.WidgetBase import WidgetBase init_parameters = { diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/IntegerWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/IntegerWidget.py similarity index 95% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/IntegerWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/IntegerWidget.py index 284ec92efa..95751c9f08 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/IntegerWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/IntegerWidget.py @@ -18,7 +18,7 @@ from qtpy.QtCore import Slot, Signal from qtpy.QtGui import QIntValidator -from MDANSE_GUI.PyQtGUI.InputWidgets.WidgetBase import WidgetBase +from MDANSE_GUI.InputWidgets.WidgetBase import WidgetBase class IntegerWidget(WidgetBase): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/InterpolationOrderWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/InterpolationOrderWidget.py similarity index 94% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/InterpolationOrderWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/InterpolationOrderWidget.py index d3abc6b15b..6f52768ab0 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/InterpolationOrderWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/InterpolationOrderWidget.py @@ -17,7 +17,7 @@ from qtpy.QtCore import Slot, Signal from qtpy.QtGui import QIntValidator -from MDANSE_GUI.PyQtGUI.InputWidgets.WidgetBase import WidgetBase +from MDANSE_GUI.InputWidgets.WidgetBase import WidgetBase suffix_dict = { diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/OutputDirectoryWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/OutputDirectoryWidget.py similarity index 92% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/OutputDirectoryWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/OutputDirectoryWidget.py index 272d140fcb..f2c06250d5 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/OutputDirectoryWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/OutputDirectoryWidget.py @@ -16,7 +16,7 @@ from qtpy.QtWidgets import QFileDialog -from MDANSE_GUI.PyQtGUI.InputWidgets.InputFileWidget import InputFileWidget +from MDANSE_GUI.InputWidgets.InputFileWidget import InputFileWidget class OutputDirectoryWidget(InputFileWidget): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/OutputFilesWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/OutputFilesWidget.py similarity index 96% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/OutputFilesWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/OutputFilesWidget.py index 74415fc0e7..0f7271e2d8 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/OutputFilesWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/OutputFilesWidget.py @@ -22,7 +22,7 @@ from qtpy.QtCore import Qt, Slot from qtpy.QtGui import QStandardItemModel, QStandardItem -from MDANSE_GUI.PyQtGUI.InputWidgets.WidgetBase import WidgetBase +from MDANSE_GUI.InputWidgets.WidgetBase import WidgetBase class CheckableComboBox(QComboBox): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/ProjectionWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/ProjectionWidget.py similarity index 95% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/ProjectionWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/ProjectionWidget.py index 2ab587269a..2bdb69eb56 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/ProjectionWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/ProjectionWidget.py @@ -16,7 +16,7 @@ from qtpy.QtWidgets import QLineEdit, QRadioButton, QButtonGroup, QLabel, QHBoxLayout from qtpy.QtCore import Slot, Signal -from MDANSE_GUI.PyQtGUI.InputWidgets.WidgetBase import WidgetBase +from MDANSE_GUI.InputWidgets.WidgetBase import WidgetBase class ProjectionWidget(WidgetBase): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/QVectorsWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/QVectorsWidget.py similarity index 95% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/QVectorsWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/QVectorsWidget.py index 024dfe4503..7c214b3f51 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/QVectorsWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/QVectorsWidget.py @@ -19,7 +19,7 @@ from MDANSE.Framework.QVectors.IQVectors import IQVectors -from MDANSE_GUI.PyQtGUI.InputWidgets.WidgetBase import WidgetBase +from MDANSE_GUI.InputWidgets.WidgetBase import WidgetBase class VectorModel(QStandardItemModel): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/RangeWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/RangeWidget.py similarity index 97% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/RangeWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/RangeWidget.py index f354f5cf6e..9a3c2eeedf 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/RangeWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/RangeWidget.py @@ -17,7 +17,7 @@ from qtpy.QtCore import Slot, Signal from qtpy.QtGui import QDoubleValidator, QIntValidator -from MDANSE_GUI.PyQtGUI.InputWidgets.WidgetBase import WidgetBase +from MDANSE_GUI.InputWidgets.WidgetBase import WidgetBase class RangeWidget(WidgetBase): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/RunningModeWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/RunningModeWidget.py similarity index 94% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/RunningModeWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/RunningModeWidget.py index 696f2c8a2a..874badcb74 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/RunningModeWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/RunningModeWidget.py @@ -18,7 +18,7 @@ from qtpy.QtWidgets import QComboBox, QSpinBox from qtpy.QtCore import Qt, Slot -from MDANSE_GUI.PyQtGUI.InputWidgets.WidgetBase import WidgetBase +from MDANSE_GUI.InputWidgets.WidgetBase import WidgetBase class RunningModeWidget(WidgetBase): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/SingleChoiceWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/SingleChoiceWidget.py similarity index 94% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/SingleChoiceWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/SingleChoiceWidget.py index 8e4d0870bc..4ae99df689 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/SingleChoiceWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/SingleChoiceWidget.py @@ -16,7 +16,7 @@ from qtpy.QtWidgets import QComboBox from qtpy.QtCore import Slot -from MDANSE_GUI.PyQtGUI.InputWidgets.WidgetBase import WidgetBase +from MDANSE_GUI.InputWidgets.WidgetBase import WidgetBase class ComboWidget(WidgetBase): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/StringWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/StringWidget.py similarity index 93% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/StringWidget.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/StringWidget.py index f166a890f7..1ee0d563c0 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/StringWidget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/StringWidget.py @@ -16,7 +16,7 @@ from qtpy.QtWidgets import QLineEdit from qtpy.QtCore import Slot -from MDANSE_GUI.PyQtGUI.InputWidgets.WidgetBase import WidgetBase +from MDANSE_GUI.InputWidgets.WidgetBase import WidgetBase class StringWidget(WidgetBase): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/WidgetBase.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/WidgetBase.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/WidgetBase.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/WidgetBase.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/__init__.py similarity index 98% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/__init__.py rename to MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/__init__.py index 5219b11004..b362fb7c6a 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/InputWidgets/__init__.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/__init__.py @@ -55,7 +55,7 @@ if name in ["__init__"]: continue try: - tempmod = importlib.import_module("." + name, "MDANSE_GUI.PyQtGUI.InputWidgets") + tempmod = importlib.import_module("." + name, "MDANSE_GUI.InputWidgets") except ModuleNotFoundError: continue tempobject = getattr(tempmod, name) diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MainWindow.py b/MDANSE_GUI/Src/MDANSE_GUI/MainWindow.py similarity index 89% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MainWindow.py rename to MDANSE_GUI/Src/MDANSE_GUI/MainWindow.py index 8a31b6e79c..02eabbdc75 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MainWindow.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/MainWindow.py @@ -19,54 +19,35 @@ from icecream import ic from qtpy.QtCore import ( Slot, - QSize, - QMetaObject, - QLocale, - QObject, - QThread, - QMutex, - QSortFilterProxyModel, Qt, QTimer, QPoint, Signal, ) -from qtpy.QtGui import QFont, QAction, QEnterEvent +from qtpy.QtGui import QAction from qtpy.QtWidgets import ( - QFrame, - QTabWidget, - QSizePolicy, - QApplication, QMainWindow, QToolButton, - QVBoxLayout, - QWidget, - QLineEdit, - QHBoxLayout, - QAbstractItemView, QFileDialog, - QLabel, QToolBar, QMenu, - QWidgetAction, QTreeView, ) -from MDANSE_GUI.PyQtGUI.BackEnd import BackEnd -from MDANSE_GUI.PyQtGUI.DataViewModel.TrajectoryHolder import DataTreeItem -from MDANSE_GUI.PyQtGUI.Widgets.Generator import WidgetGenerator -from MDANSE_GUI.PyQtGUI.Widgets.ConvertDialog import ConverterDialog -from MDANSE_GUI.PyQtGUI.Widgets.ActionDialog import ActionDialog -from MDANSE_GUI.PyQtGUI.Widgets.ActionsTree import ActionsTree -from MDANSE_GUI.PyQtGUI.Resources import Resources -from MDANSE_GUI.PyQtGUI.UnitsEditor import UnitsEditor -from MDANSE_GUI.PyQtGUI.PeriodicTableViewer import PeriodicTableViewer -from MDANSE_GUI.PyQtGUI.ElementsDatabaseEditor import ElementsDatabaseEditor -from MDANSE_GUI.PyQtGUI.Widgets.TrajectoryViewer import TrajectoryViewer -from MDANSE_GUI.PyQtGUI.MolecularViewer.MolecularViewer import MolecularViewer -from MDANSE_GUI.PyQtGUI.MolecularViewer.Controls import ViewerControls -from MDANSE_GUI.PyQtGUI.Widgets.StyleDialog import StyleDialog, StyleDatabase -from MDANSE_GUI.PyQtGUI.pygenplot.widgets.main_window import MainWindow +from MDANSE_GUI.DataViewModel.TrajectoryHolder import DataTreeItem +from MDANSE_GUI.Widgets.Generator import WidgetGenerator +from MDANSE_GUI.Widgets.ConvertDialog import ConverterDialog +from MDANSE_GUI.Widgets.ActionDialog import ActionDialog +from MDANSE_GUI.Widgets.ActionsTree import ActionsTree +from MDANSE_GUI.Resources import Resources +from MDANSE_GUI.UnitsEditor import UnitsEditor +from MDANSE_GUI.PeriodicTableViewer import PeriodicTableViewer +from MDANSE_GUI.ElementsDatabaseEditor import ElementsDatabaseEditor +from MDANSE_GUI.Widgets.TrajectoryViewer import TrajectoryViewer +from MDANSE_GUI.MolecularViewer.MolecularViewer import MolecularViewer +from MDANSE_GUI.MolecularViewer.Controls import ViewerControls +from MDANSE_GUI.Widgets.StyleDialog import StyleDialog, StyleDatabase +from MDANSE_GUI.pygenplot.widgets.main_window import MainWindow class LoaderButton(QToolButton): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/AtomProperties.py b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/AtomProperties.py similarity index 98% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/AtomProperties.py rename to MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/AtomProperties.py index 32e6d657d3..8ae13ac6c0 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/AtomProperties.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/AtomProperties.py @@ -132,7 +132,7 @@ def initialise_from_database( Keyword Arguments: element_database -- a dictionary containing RGB values for chemical elements, - typically the MDANSE_GUI.PyQtGUI.MolecularViewer.database.CHEMICAL_ELEMENTS + typically the MDANSE_GUI.MolecularViewer.database.CHEMICAL_ELEMENTS Returns: list[int] -- a list of indices of colours, with one numbed per atom. diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/ColourManager.py b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/ColourManager.py similarity index 97% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/ColourManager.py rename to MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/ColourManager.py index d9b708ebf0..0c15360566 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/ColourManager.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/ColourManager.py @@ -79,7 +79,7 @@ def initialise_from_database( Keyword Arguments: element_database -- a dictionary containing RGB values for chemical elements, - typically the MDANSE_GUI.PyQtGUI.MolecularViewer.database.CHEMICAL_ELEMENTS + typically the MDANSE_GUI.MolecularViewer.database.CHEMICAL_ELEMENTS Returns: list[int] -- a list of indices of colours, with one numbed per atom. diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/Contents.py b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/Contents.py similarity index 94% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/Contents.py rename to MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/Contents.py index fdc51a3893..bbeaf443b9 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/Contents.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/Contents.py @@ -16,8 +16,7 @@ from qtpy.QtGui import QStandardItemModel, QStandardItem from qtpy.QtWidgets import QTableView, QColorDialog -from MDANSE.Chemistry.ChemicalEntity import ChemicalSystem -from MDANSE_GUI.PyQtGUI.MolecularViewer.readers.i_reader import IReader +from MDANSE_GUI.MolecularViewer.readers.i_reader import IReader class TrajectoryAtomData(QStandardItemModel): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/Controls.py b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/Controls.py similarity index 98% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/Controls.py rename to MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/Controls.py index ced35f4731..7cd32bbdf0 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/Controls.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/Controls.py @@ -38,8 +38,8 @@ QColor, ) -from MDANSE_GUI.PyQtGUI.MolecularViewer.MolecularViewer import MolecularViewer -from MDANSE_GUI.PyQtGUI.MolecularViewer.Contents import TrajectoryAtomData +from MDANSE_GUI.MolecularViewer.MolecularViewer import MolecularViewer +from MDANSE_GUI.MolecularViewer.Contents import TrajectoryAtomData button_lookup = { "start": QStyle.StandardPixmap.SP_MediaSkipBackward, diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/Dummy.py b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/Dummy.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/Dummy.py rename to MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/Dummy.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/MolecularViewer.py b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/MolecularViewer.py similarity index 97% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/MolecularViewer.py rename to MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/MolecularViewer.py index ef4af87986..1ec1401897 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/MolecularViewer.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/MolecularViewer.py @@ -27,13 +27,13 @@ from MDANSE.Framework.InputData.HDFTrajectoryInputData import HDFTrajectoryInputData from MDANSE.Chemistry import ATOMS_DATABASE as CHEMICAL_ELEMENTS -# from MDANSE_GUI.PyQtGUI.MolecularViewer.database import CHEMICAL_ELEMENTS -from MDANSE_GUI.PyQtGUI.MolecularViewer.readers import hdf5wrapper -from MDANSE_GUI.PyQtGUI.MolecularViewer.Dummy import PyConnectivity -from MDANSE_GUI.PyQtGUI.MolecularViewer.Contents import TrajectoryAtomData +# from MDANSE_GUI.MolecularViewer.database import CHEMICAL_ELEMENTS +from MDANSE_GUI.MolecularViewer.readers import hdf5wrapper +from MDANSE_GUI.MolecularViewer.Dummy import PyConnectivity +from MDANSE_GUI.MolecularViewer.Contents import TrajectoryAtomData -# from MDANSE_GUI.PyQtGUI.MolecularViewer.ColourManager import ColourManager -from MDANSE_GUI.PyQtGUI.MolecularViewer.AtomProperties import ( +# from MDANSE_GUI.MolecularViewer.ColourManager import ColourManager +from MDANSE_GUI.MolecularViewer.AtomProperties import ( AtomProperties, ndarray_to_vtkarray, ) diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/__init__.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/__init__.py rename to MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/__init__.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/database/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/database/__init__.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/database/__init__.py rename to MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/database/__init__.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/database/chemical_elements.yml b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/database/chemical_elements.yml similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/database/chemical_elements.yml rename to MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/database/chemical_elements.yml diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/database/residues.yml b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/database/residues.yml similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/database/residues.yml rename to MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/database/residues.yml diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/readers/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/readers/__init__.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/readers/__init__.py rename to MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/readers/__init__.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/readers/hdf5wrapper.py b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/readers/hdf5wrapper.py similarity index 95% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/readers/hdf5wrapper.py rename to MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/readers/hdf5wrapper.py index c8999cbb6a..463f4c1a92 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/readers/hdf5wrapper.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/readers/hdf5wrapper.py @@ -14,7 +14,7 @@ import numpy as np -from MDANSE_GUI.PyQtGUI.MolecularViewer.readers.i_reader import IReader +from MDANSE_GUI.MolecularViewer.readers.i_reader import IReader class HDF5Wrapper(IReader): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/readers/i_reader.py b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/readers/i_reader.py similarity index 99% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/readers/i_reader.py rename to MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/readers/i_reader.py index 3f53b52eb4..6b3631db74 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/readers/i_reader.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/readers/i_reader.py @@ -21,7 +21,7 @@ import numpy as np -from MDANSE_GUI.PyQtGUI.MolecularViewer.database import ( +from MDANSE_GUI.MolecularViewer.database import ( CHEMICAL_ELEMENTS, STANDARD_RESIDUES, ) diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/readers/reader_registry.py b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/readers/reader_registry.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/MolecularViewer/readers/reader_registry.py rename to MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/readers/reader_registry.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/PeriodicTableViewer.py b/MDANSE_GUI/Src/MDANSE_GUI/PeriodicTableViewer.py similarity index 98% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/PeriodicTableViewer.py rename to MDANSE_GUI/Src/MDANSE_GUI/PeriodicTableViewer.py index 33bece4282..138903991b 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/PeriodicTableViewer.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/PeriodicTableViewer.py @@ -24,10 +24,9 @@ QApplication, QSizePolicy, QMenu, - QTextEdit, ) -from qtpy.QtCore import Signal, Slot, Qt, QPoint, QSize -from qtpy.QtGui import QFont, QEnterEvent, QFontDatabase +from qtpy.QtCore import Signal, Slot, Qt, QPoint +from qtpy.QtGui import QEnterEvent from MDANSE.Chemistry import ATOMS_DATABASE diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/about.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/about.png deleted file mode 100644 index 7598894e11..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/about.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/api.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/api.png deleted file mode 100644 index 7a6fba20be..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/api.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/atom.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/atom.png deleted file mode 100644 index 3cd2a54dea..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/atom.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/bug.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/bug.png deleted file mode 100644 index b73166e199..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/bug.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/clock.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/clock.png deleted file mode 100644 index 886b86e99b..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/clock.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/element.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/element.png deleted file mode 100644 index 72ea158a95..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/element.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/empty_data.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/empty_data.png deleted file mode 100644 index d1d6c244bc..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/empty_data.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/first.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/first.png deleted file mode 100644 index 9a2132a28c..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/first.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/help.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/help.png deleted file mode 100644 index 22d753afd4..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/help.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/hourglass.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/hourglass.png deleted file mode 100644 index 5fd6daa3f5..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/hourglass.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/last.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/last.png deleted file mode 100644 index 9f1deb3feb..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/last.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/load.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/load.png deleted file mode 100644 index 3740c9dfa9..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/load.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/log.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/log.png deleted file mode 100644 index 05dae878c7..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/log.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/logfile.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/logfile.png deleted file mode 100644 index 41a9f77556..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/logfile.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/mdanse.icns b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/mdanse.icns deleted file mode 100644 index 8766d3c7a4..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/mdanse.icns and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/minus.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/minus.png deleted file mode 100644 index df28893ff5..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/minus.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/pause.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/pause.png deleted file mode 100644 index 22a5679d75..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/pause.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/periodic_table.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/periodic_table.png deleted file mode 100644 index d78f49f91d..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/periodic_table.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/play.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/play.png deleted file mode 100644 index 435a83ae49..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/play.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/plot.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/plot.png deleted file mode 100644 index f438f207c9..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/plot.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/plus.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/plus.png deleted file mode 100644 index fbe8a1d68c..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/plus.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/preferences.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/preferences.png deleted file mode 100644 index c761b9012f..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/preferences.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/quit.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/quit.png deleted file mode 100644 index cd9fc1d0c1..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/quit.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/registry.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/registry.png deleted file mode 100644 index 344eb97933..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/registry.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/run.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/run.png deleted file mode 100644 index c143c1dd66..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/run.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/shell.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/shell.png deleted file mode 100644 index 7e6885d9a1..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/shell.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/stop.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/stop.png deleted file mode 100644 index b85e545b2c..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/stop.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/template.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/template.png deleted file mode 100644 index cd8c85da90..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/template.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/units.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/units.png deleted file mode 100644 index 3721a79c89..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/units.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/user.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/user.png deleted file mode 100644 index 4b1a78932a..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/user.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/user_definitions.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/user_definitions.png deleted file mode 100644 index 4ed05715c8..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/user_definitions.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/web.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/web.png deleted file mode 100644 index 3e82aa465d..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/web.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/working_directory.png b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/working_directory.png deleted file mode 100644 index 8156ca8fc4..0000000000 Binary files a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Icons/working_directory.png and /dev/null differ diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/__init__.py deleted file mode 100644 index 3bb9651b36..0000000000 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -# ************************************************************************** -# -# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments -# -# @file Src/PyQtGUI/main.py -# @brief Starts the QApplication instance -# -# @homepage https://mdanse.org -# @license GNU General Public License v3 or higher (see LICENSE) -# @copyright Institut Laue Langevin 2013-now -# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now -# @authors Research Software Group at ISIS (see AUTHORS) -# -# ************************************************************************** diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/RegistryViewer.py b/MDANSE_GUI/Src/MDANSE_GUI/RegistryViewer.py similarity index 98% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/RegistryViewer.py rename to MDANSE_GUI/Src/MDANSE_GUI/RegistryViewer.py index 41b065b325..9544b066ea 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/RegistryViewer.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/RegistryViewer.py @@ -21,23 +21,16 @@ MDANSE IJob interface. """ -import os - -from MDANSE import PLATFORM from MDANSE.Framework.Jobs.IJob import IJob from qtpy.QtGui import QStandardItemModel, QStandardItem -from qtpy.QtCore import QObject, Slot, Signal, QSortFilterProxyModel, QModelIndex +from qtpy.QtCore import Slot, Signal, QSortFilterProxyModel, QModelIndex from qtpy.QtWidgets import ( QDialog, QTreeView, QGridLayout, - QVBoxLayout, - QWidget, QLabel, QApplication, - QSizePolicy, - QMenu, QLineEdit, QTextEdit, ) diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Resources.py b/MDANSE_GUI/Src/MDANSE_GUI/Resources.py similarity index 94% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Resources.py rename to MDANSE_GUI/Src/MDANSE_GUI/Resources.py index c120a1ab10..741608cdb7 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Resources.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/Resources.py @@ -14,7 +14,7 @@ # ************************************************************************** from qtpy.QtCore import QDir, QSize -from qtpy.QtGui import QIcon, QImage, QPixmap +from qtpy.QtGui import QIcon, QPixmap class Resources: @@ -26,7 +26,7 @@ def __init__(self): def load_icons(self): from importlib.resources import files - temp = files("MDANSE_GUI.PyQtGUI") + temp = files("MDANSE_GUI") # print(f"I got {temp} from the importlib.resources") res_dir = QDir(str(temp.joinpath("Icons"))) print(f"Resources are in {res_dir.absolutePath()}") diff --git a/MDANSE_GUI/Src/MDANSE_GUI/Scripts/mdanse_elements_database.py b/MDANSE_GUI/Src/MDANSE_GUI/Scripts/mdanse_elements_database.py index 0b605b432a..70a400d7d1 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/Scripts/mdanse_elements_database.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/Scripts/mdanse_elements_database.py @@ -15,7 +15,7 @@ def main(): - from MDANSE_GUI.PyQtGUI.ElementsDatabaseEditor import ( + from MDANSE_GUI.ElementsDatabaseEditor import ( ElementsDatabaseEditor, QApplication, ) diff --git a/MDANSE_GUI/Src/MDANSE_GUI/Scripts/mdanse_gui.py b/MDANSE_GUI/Src/MDANSE_GUI/Scripts/mdanse_gui.py index 327597c9c6..5544de81ee 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/Scripts/mdanse_gui.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/Scripts/mdanse_gui.py @@ -17,7 +17,7 @@ def main(): - from MDANSE_GUI.PyQtGUI.main import startGUI + from MDANSE_GUI.main import startGUI startGUI(sys.argv) diff --git a/MDANSE_GUI/Src/MDANSE_GUI/Scripts/mdanse_periodic_table.py b/MDANSE_GUI/Src/MDANSE_GUI/Scripts/mdanse_periodic_table.py index 24d6932842..0e9d1cdfe4 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/Scripts/mdanse_periodic_table.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/Scripts/mdanse_periodic_table.py @@ -15,7 +15,7 @@ def main(): - from MDANSE_GUI.PyQtGUI.PeriodicTableViewer import PeriodicTableViewer, QApplication + from MDANSE_GUI.PeriodicTableViewer import PeriodicTableViewer, QApplication import sys app = QApplication(sys.argv) diff --git a/MDANSE_GUI/Src/MDANSE_GUI/Scripts/mdanse_units_editor.py b/MDANSE_GUI/Src/MDANSE_GUI/Scripts/mdanse_units_editor.py index bf5549218e..4001b117d9 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/Scripts/mdanse_units_editor.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/Scripts/mdanse_units_editor.py @@ -15,7 +15,7 @@ def main(): - from MDANSE_GUI.PyQtGUI.UnitsEditor import UnitsEditor, QApplication + from MDANSE_GUI.UnitsEditor import UnitsEditor, QApplication import sys app = QApplication(sys.argv) diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/SubclassViewer.py b/MDANSE_GUI/Src/MDANSE_GUI/SubclassViewer.py similarity index 98% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/SubclassViewer.py rename to MDANSE_GUI/Src/MDANSE_GUI/SubclassViewer.py index 132d383017..66a34482bf 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/SubclassViewer.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/SubclassViewer.py @@ -24,17 +24,13 @@ from MDANSE.Framework.Jobs.IJob import IJob from qtpy.QtGui import QStandardItemModel, QStandardItem -from qtpy.QtCore import QObject, Slot, Signal, QSortFilterProxyModel, QModelIndex +from qtpy.QtCore import Slot, Signal, QSortFilterProxyModel, QModelIndex from qtpy.QtWidgets import ( QDialog, QTreeView, QGridLayout, - QVBoxLayout, - QWidget, QLabel, QApplication, - QSizePolicy, - QMenu, QLineEdit, QTextEdit, ) diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/UnitsEditor.py b/MDANSE_GUI/Src/MDANSE_GUI/UnitsEditor.py similarity index 95% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/UnitsEditor.py rename to MDANSE_GUI/Src/MDANSE_GUI/UnitsEditor.py index 578d1a33da..9ea437ff3d 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/UnitsEditor.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/UnitsEditor.py @@ -13,7 +13,6 @@ # # ************************************************************************** -import collections import copy from qtpy.QtWidgets import ( @@ -21,36 +20,25 @@ QPushButton, QFrame, QGridLayout, - QVBoxLayout, - QWidget, QLabel, QApplication, - QSizePolicy, - QMenu, QLineEdit, QListView, ) from qtpy.QtCore import ( Signal, Slot, - Qt, - QPoint, - QSize, - QSortFilterProxyModel, QModelIndex, ) from qtpy.QtGui import ( - QFont, - QEnterEvent, QStandardItem, QStandardItemModel, QDoubleValidator, ) -from MDANSE import LOGGER from MDANSE.Framework.Units import _UNAMES, UNITS_MANAGER -from MDANSE_GUI.PyQtGUI.Widgets.GeneralWidgets import InputVariable, InputDialog +from MDANSE_GUI.Widgets.GeneralWidgets import InputVariable, InputDialog class UnitVisualiser(QFrame): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/ActionDialog.py b/MDANSE_GUI/Src/MDANSE_GUI/Widgets/ActionDialog.py similarity index 97% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/ActionDialog.py rename to MDANSE_GUI/Src/MDANSE_GUI/Widgets/ActionDialog.py index 0a741af079..beab80bbe7 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/ActionDialog.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/Widgets/ActionDialog.py @@ -49,11 +49,11 @@ ) from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE_GUI.PyQtGUI.Widgets.GeneralWidgets import InputFactory -from MDANSE_GUI.PyQtGUI.InputWidgets import * +from MDANSE_GUI.Widgets.GeneralWidgets import InputFactory +from MDANSE_GUI.InputWidgets import * -widget_lookup = { # these all come from MDANSE_GUI.PyQtGUI.InputWidgets +widget_lookup = { # these all come from MDANSE_GUI.InputWidgets "FloatConfigurator": FloatWidget, "BooleanConfigurator": BooleanWidget, "StringConfigurator": StringWidget, diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/ActionsTree.py b/MDANSE_GUI/Src/MDANSE_GUI/Widgets/ActionsTree.py similarity index 93% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/ActionsTree.py rename to MDANSE_GUI/Src/MDANSE_GUI/Widgets/ActionsTree.py index cfe49584f4..20075ec92b 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/ActionsTree.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/Widgets/ActionsTree.py @@ -20,9 +20,9 @@ from qtpy.QtCore import Signal, Slot, QModelIndex, Qt, QMimeData from qtpy.QtGui import QContextMenuEvent, QMouseEvent, QDrag, QStandardItem -from MDANSE_GUI.PyQtGUI.DataViewModel.TrajectoryHolder import DataTreeItem -from MDANSE_GUI.PyQtGUI.DataViewModel.ActionsHolder import ActionsHolder -from MDANSE_GUI.PyQtGUI.Widgets.ActionDialog import ActionDialog +from MDANSE_GUI.DataViewModel.TrajectoryHolder import DataTreeItem +from MDANSE_GUI.DataViewModel.ActionsHolder import ActionsHolder +from MDANSE_GUI.Widgets.ActionDialog import ActionDialog class ActionsTree(QTreeView): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/ConvertDialog.py b/MDANSE_GUI/Src/MDANSE_GUI/Widgets/ConvertDialog.py similarity index 98% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/ConvertDialog.py rename to MDANSE_GUI/Src/MDANSE_GUI/Widgets/ConvertDialog.py index dfe59f5729..e85244d764 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/ConvertDialog.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/Widgets/ConvertDialog.py @@ -47,7 +47,7 @@ ) from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE_GUI.PyQtGUI.Widgets.GeneralWidgets import InputFactory +from MDANSE_GUI.Widgets.GeneralWidgets import InputFactory class ConverterDialog(QDialog): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/ConvertWizard.py b/MDANSE_GUI/Src/MDANSE_GUI/Widgets/ConvertWizard.py similarity index 98% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/ConvertWizard.py rename to MDANSE_GUI/Src/MDANSE_GUI/Widgets/ConvertWizard.py index 326f122990..e3e839c601 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/ConvertWizard.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/Widgets/ConvertWizard.py @@ -53,7 +53,7 @@ from MDANSE.Framework.Jobs.IJob import IJob # from MDANSE.Framework.Jobs.Converter import InteractiveConverter -from MDANSE_GUI.PyQtGUI.Widgets.GeneralWidgets import GeneralInput, InputFactory +from MDANSE_GUI.Widgets.GeneralWidgets import GeneralInput, InputFactory # I think that a Trajectory Converter should, in general, # create a Wizard and not a single Dialog. @@ -433,9 +433,9 @@ def validatePage(self) -> bool: from qtpy.QtWidgets import QApplication, QMainWindow, QPushButton from qtpy.QtCore import QSettings, QThread, Qt -from MDANSE_GUI.PyQtGUI.MainWindow import Main -from MDANSE_GUI.PyQtGUI.BackEnd import BackEnd -from MDANSE_GUI.PyQtGUI.Widgets.Generator import WidgetGenerator +from MDANSE_GUI.MainWindow import Main +from MDANSE_GUI.BackEnd import BackEnd +from MDANSE_GUI.Widgets.Generator import WidgetGenerator from MDANSE.Framework.Jobs.Converter import InteractiveConverter diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/GeneralWidgets.py b/MDANSE_GUI/Src/MDANSE_GUI/Widgets/GeneralWidgets.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/GeneralWidgets.py rename to MDANSE_GUI/Src/MDANSE_GUI/Widgets/GeneralWidgets.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/Generator.py b/MDANSE_GUI/Src/MDANSE_GUI/Widgets/Generator.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/Generator.py rename to MDANSE_GUI/Src/MDANSE_GUI/Widgets/Generator.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/Oscillator.py b/MDANSE_GUI/Src/MDANSE_GUI/Widgets/Oscillator.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/Oscillator.py rename to MDANSE_GUI/Src/MDANSE_GUI/Widgets/Oscillator.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/StyleDialog.py b/MDANSE_GUI/Src/MDANSE_GUI/Widgets/StyleDialog.py similarity index 98% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/StyleDialog.py rename to MDANSE_GUI/Src/MDANSE_GUI/Widgets/StyleDialog.py index 705cb5fb16..475fd9849a 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/StyleDialog.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/Widgets/StyleDialog.py @@ -48,7 +48,7 @@ ) from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE_GUI.PyQtGUI.Widgets.GeneralWidgets import InputFactory +from MDANSE_GUI.Widgets.GeneralWidgets import InputFactory sample_styles = { diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/TrajectoryViewer.py b/MDANSE_GUI/Src/MDANSE_GUI/Widgets/TrajectoryViewer.py similarity index 96% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/TrajectoryViewer.py rename to MDANSE_GUI/Src/MDANSE_GUI/Widgets/TrajectoryViewer.py index 5ccd3f2b58..f373c27c4f 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/TrajectoryViewer.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/Widgets/TrajectoryViewer.py @@ -20,7 +20,7 @@ from qtpy.QtCore import Signal, Slot, QModelIndex from qtpy.QtGui import QContextMenuEvent -from MDANSE_GUI.PyQtGUI.DataViewModel.TrajectoryHolder import DataTreeItem +from MDANSE_GUI.DataViewModel.TrajectoryHolder import DataTreeItem class TrajectoryViewer(QTreeView): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/Widgets/__init__.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/Widgets/__init__.py rename to MDANSE_GUI/Src/MDANSE_GUI/Widgets/__init__.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/main.py b/MDANSE_GUI/Src/MDANSE_GUI/main.py similarity index 93% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/main.py rename to MDANSE_GUI/Src/MDANSE_GUI/main.py index b224babeb6..dcf0d66138 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/main.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/main.py @@ -16,10 +16,10 @@ import sys from qtpy.QtWidgets import QApplication -from qtpy.QtCore import QSettings, QThread +from qtpy.QtCore import QSettings -from MDANSE_GUI.PyQtGUI.MainWindow import Main -from MDANSE_GUI.PyQtGUI.BackEnd import BackEnd +from MDANSE_GUI.MainWindow import Main +from MDANSE_GUI.BackEnd import BackEnd def startGUI(some_args): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/__init__.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/__init__.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/__init__.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/__init__.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/__init__.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/__init__.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/about_dialog.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/about_dialog.py similarity index 95% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/about_dialog.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/about_dialog.py index d19550ab1f..9c464647d4 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/about_dialog.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/about_dialog.py @@ -19,8 +19,8 @@ from qtpy import QtCore, QtWidgets -from MDANSE_GUI.PyQtGUI.pygenplot.__pkginfo__ import __version__ -from MDANSE_GUI.PyQtGUI.pygenplot.icons import ICONS +from MDANSE_GUI.pygenplot.__pkginfo__ import __version__ +from MDANSE_GUI.pygenplot.icons import ICONS class AboutDialog(QtWidgets.QDialog): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/cross_viewer_dialog.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/cross_viewer_dialog.py similarity index 98% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/cross_viewer_dialog.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/cross_viewer_dialog.py index 06854aeccd..be49c52ee7 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/cross_viewer_dialog.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/cross_viewer_dialog.py @@ -15,10 +15,10 @@ from qtpy import QtCore, QtGui, QtWidgets -from MDANSE_GUI.PyQtGUI.pygenplot.models.plot_1d_model import Plot1DModelError -from MDANSE_GUI.PyQtGUI.pygenplot.utils.numeric import smart_round -from MDANSE_GUI.PyQtGUI.pygenplot.widgets.plot_1d_widget import Plot1DWidget -from MDANSE_GUI.PyQtGUI.pygenplot.widgets.range_slider import RangeSlider +from MDANSE_GUI.pygenplot.models.plot_1d_model import Plot1DModelError +from MDANSE_GUI.pygenplot.utils.numeric import smart_round +from MDANSE_GUI.pygenplot.widgets.plot_1d_widget import Plot1DWidget +from MDANSE_GUI.pygenplot.widgets.range_slider import RangeSlider class CrossViewerDialog(QtWidgets.QDialog): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/data_viewer_1d_dialog.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/data_viewer_1d_dialog.py similarity index 98% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/data_viewer_1d_dialog.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/data_viewer_1d_dialog.py index 63233b0226..bb20eeb036 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/data_viewer_1d_dialog.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/data_viewer_1d_dialog.py @@ -14,7 +14,7 @@ from qtpy import QtCore, QtGui, QtWidgets -from MDANSE_GUI.PyQtGUI.pygenplot.views.table_views import QTableViewWithoutRightClick +from MDANSE_GUI.pygenplot.views.table_views import QTableViewWithoutRightClick class DataViewer1DDialog(QtWidgets.QDialog): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/data_viewer_nd_dialog.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/data_viewer_nd_dialog.py similarity index 98% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/data_viewer_nd_dialog.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/data_viewer_nd_dialog.py index ee57667bf3..4a7cb15d7d 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/data_viewer_nd_dialog.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/data_viewer_nd_dialog.py @@ -14,7 +14,7 @@ from qtpy import QtCore, QtGui, QtWidgets -from MDANSE_GUI.PyQtGUI.pygenplot.views.table_views import QTableViewWithoutRightClick +from MDANSE_GUI.pygenplot.views.table_views import QTableViewWithoutRightClick class DataViewerNDDialog(QtWidgets.QDialog): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/inspect_data_dialog.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/inspect_data_dialog.py similarity index 99% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/inspect_data_dialog.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/inspect_data_dialog.py index 46849754ce..8effd69f10 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/inspect_data_dialog.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/inspect_data_dialog.py @@ -16,8 +16,8 @@ from qtpy import QtCore, QtGui, QtWidgets -from MDANSE_GUI.PyQtGUI.pygenplot.views.table_views import QTableViewWithoutRightClick -from MDANSE_GUI.PyQtGUI.pygenplot.widgets.range_slider import RangeSlider +from MDANSE_GUI.pygenplot.views.table_views import QTableViewWithoutRightClick +from MDANSE_GUI.pygenplot.widgets.range_slider import RangeSlider class InspectDataDialog(QtWidgets.QDialog): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_1d_axis_settings_dialog.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_1d_axis_settings_dialog.py similarity index 99% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_1d_axis_settings_dialog.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_1d_axis_settings_dialog.py index 7696c8f5a9..3b3007cb1b 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_1d_axis_settings_dialog.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_1d_axis_settings_dialog.py @@ -17,7 +17,7 @@ from qtpy import QtWidgets -from MDANSE_GUI.PyQtGUI.pygenplot.models.plot_1d_model import ( +from MDANSE_GUI.pygenplot.models.plot_1d_model import ( Plot1DModel, Plot1DModelError, ) diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_1d_general_settings_dialog.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_1d_general_settings_dialog.py similarity index 99% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_1d_general_settings_dialog.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_1d_general_settings_dialog.py index 201288bc4d..71708ab0de 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_1d_general_settings_dialog.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_1d_general_settings_dialog.py @@ -14,7 +14,7 @@ from qtpy import QtCore, QtWidgets -from MDANSE_GUI.PyQtGUI.pygenplot.models.plot_1d_model import Plot1DModel +from MDANSE_GUI.pygenplot.models.plot_1d_model import Plot1DModel class Plot1DGeneralSettingsDialog(QtWidgets.QDialog): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_1d_lines_settings_dialog.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_1d_lines_settings_dialog.py similarity index 99% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_1d_lines_settings_dialog.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_1d_lines_settings_dialog.py index f8d9609045..c909696632 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_1d_lines_settings_dialog.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_1d_lines_settings_dialog.py @@ -16,7 +16,7 @@ from qtpy import QtCore, QtWidgets -from MDANSE_GUI.PyQtGUI.pygenplot.models.plot_1d_model import Plot1DModel +from MDANSE_GUI.pygenplot.models.plot_1d_model import Plot1DModel class Plot1DLinesSettingsDialog(QtWidgets.QDialog): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_2d_general_settings_dialog.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_2d_general_settings_dialog.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_2d_general_settings_dialog.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_2d_general_settings_dialog.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_2d_image_settings_dialog.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_2d_image_settings_dialog.py similarity index 99% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_2d_image_settings_dialog.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_2d_image_settings_dialog.py index c916518422..a295774abb 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_2d_image_settings_dialog.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_2d_image_settings_dialog.py @@ -15,7 +15,7 @@ from PyQt6 import QtWidgets -from MDANSE_GUI.PyQtGUI.pygenplot.models.plot_2d_model import ( +from MDANSE_GUI.pygenplot.models.plot_2d_model import ( Plot2DModel, Plot2DModelError, ) diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_nd_axis_settings_dialog.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_nd_axis_settings_dialog.py similarity index 99% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_nd_axis_settings_dialog.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_nd_axis_settings_dialog.py index 97eaae0eb4..0a6c10abf2 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_nd_axis_settings_dialog.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_nd_axis_settings_dialog.py @@ -17,7 +17,7 @@ from qtpy import QtWidgets -from MDANSE_GUI.PyQtGUI.pygenplot.models.plot_nd_model import ( +from MDANSE_GUI.pygenplot.models.plot_nd_model import ( PlotNDModel, PlotNDModelError, ) diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_nd_general_settings_dialog.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_nd_general_settings_dialog.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_nd_general_settings_dialog.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_nd_general_settings_dialog.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_nd_image_settings_dialog.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_nd_image_settings_dialog.py similarity index 98% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_nd_image_settings_dialog.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_nd_image_settings_dialog.py index 6914ae00ae..8ac2f0fc4f 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/plot_nd_image_settings_dialog.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/plot_nd_image_settings_dialog.py @@ -14,7 +14,7 @@ from qtpy import QtWidgets -from MDANSE_GUI.PyQtGUI.pygenplot.models.plot_nd_model import PlotNDModel +from MDANSE_GUI.pygenplot.models.plot_nd_model import PlotNDModel class PlotNDImageSettingsDialog(QtWidgets.QDialog): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/slice_viewer_dialog.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/slice_viewer_dialog.py similarity index 99% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/slice_viewer_dialog.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/slice_viewer_dialog.py index 43ebd4b823..1bf4ecc72b 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/slice_viewer_dialog.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/slice_viewer_dialog.py @@ -14,7 +14,7 @@ from qtpy import QtCore, QtWidgets -from MDANSE_GUI.PyQtGUI.pygenplot.widgets.range_slider import RangeSlider +from MDANSE_GUI.pygenplot.widgets.range_slider import RangeSlider class SliceViewerDialog(QtWidgets.QDialog): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/units_editor_dialog.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/units_editor_dialog.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/units_editor_dialog.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/units_editor_dialog.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/viewer_1d_dialog.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/viewer_1d_dialog.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/dialogs/viewer_1d_dialog.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/dialogs/viewer_1d_dialog.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/handlers/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/handlers/__init__.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/handlers/__init__.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/handlers/__init__.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/handlers/logger_popup.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/handlers/logger_popup.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/handlers/logger_popup.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/handlers/logger_popup.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/handlers/logger_widget.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/handlers/logger_widget.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/handlers/logger_widget.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/handlers/logger_widget.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/models/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/models/__init__.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/models/__init__.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/models/__init__.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/models/data_list_model.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/models/data_list_model.py similarity index 97% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/models/data_list_model.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/models/data_list_model.py index 7bfc346caf..2d693b29d1 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/models/data_list_model.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/models/data_list_model.py @@ -16,7 +16,7 @@ from qtpy import QtCore -from MDANSE_GUI.PyQtGUI.pygenplot.models.data_tree_model import DATA_MODELS +from MDANSE_GUI.pygenplot.models.data_tree_model import DATA_MODELS class DataListModel(QtCore.QAbstractListModel): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/models/data_tree_model.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/models/data_tree_model.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/models/data_tree_model.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/models/data_tree_model.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/models/plot_1d_model.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/models/plot_1d_model.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/models/plot_1d_model.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/models/plot_1d_model.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/models/plot_2d_model.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/models/plot_2d_model.py similarity index 99% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/models/plot_2d_model.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/models/plot_2d_model.py index 3a7c251062..c316d627b9 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/models/plot_2d_model.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/models/plot_2d_model.py @@ -21,7 +21,7 @@ from MDANSE.Framework.Units import measure, UnitError -from MDANSE_GUI.PyQtGUI.pygenplot.utils.numeric import smart_round +from MDANSE_GUI.pygenplot.utils.numeric import smart_round class Plot2DModelError(Exception): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/models/plot_nd_model.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/models/plot_nd_model.py similarity index 99% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/models/plot_nd_model.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/models/plot_nd_model.py index a2de4a2ad9..8b676e3340 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/models/plot_nd_model.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/models/plot_nd_model.py @@ -22,7 +22,7 @@ from MDANSE.Framework.Units import measure, UnitError -from MDANSE_GUI.PyQtGUI.pygenplot.utils.numeric import smart_round +from MDANSE_GUI.pygenplot.utils.numeric import smart_round class PlotNDModelError(Exception): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/utils/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/utils/__init__.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/utils/__init__.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/utils/__init__.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/utils/numeric.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/utils/numeric.py similarity index 99% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/utils/numeric.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/utils/numeric.py index 6af242bf3f..d7b84221a5 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/utils/numeric.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/utils/numeric.py @@ -21,7 +21,7 @@ import numbers import warnings -from MDANSE_GUI.PyQtGUI.pygenplot.utils.sorted_dict import SortedDict +from MDANSE_GUI.pygenplot.utils.sorted_dict import SortedDict _manual_settings = {} _default_settings = { diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/utils/sorted_dict.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/utils/sorted_dict.py similarity index 99% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/utils/sorted_dict.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/utils/sorted_dict.py index 9466fe3e09..f4e5b9e88d 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/utils/sorted_dict.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/utils/sorted_dict.py @@ -37,8 +37,8 @@ from itertools import chain -from MDANSE_GUI.PyQtGUI.pygenplot.utils.sorted_list import SortedList, recursive_repr -from MDANSE_GUI.PyQtGUI.pygenplot.utils.sorted_set import SortedSet +from MDANSE_GUI.pygenplot.utils.sorted_list import SortedList, recursive_repr +from MDANSE_GUI.pygenplot.utils.sorted_set import SortedSet ############################################################################### # BEGIN Python 2/3 Shims diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/utils/sorted_list.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/utils/sorted_list.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/utils/sorted_list.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/utils/sorted_list.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/utils/sorted_set.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/utils/sorted_set.py similarity index 99% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/utils/sorted_set.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/utils/sorted_set.py index a979340635..c18a166e06 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/utils/sorted_set.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/utils/sorted_set.py @@ -33,7 +33,7 @@ from operator import eq, ne, gt, ge, lt, le from textwrap import dedent -from MDANSE_GUI.PyQtGUI.pygenplot.utils.sorted_list import SortedList, recursive_repr +from MDANSE_GUI.pygenplot.utils.sorted_list import SortedList, recursive_repr ############################################################################### # BEGIN Python 2/3 Shims diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/views/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/views/__init__.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/views/__init__.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/views/__init__.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/views/table_views.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/views/table_views.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/views/table_views.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/views/table_views.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/__init__.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/__init__.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/__init__.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/__init__.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/actions_widget.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/actions_widget.py similarity index 97% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/actions_widget.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/actions_widget.py index d0d05ede37..e0ab9ac2f1 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/actions_widget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/actions_widget.py @@ -14,7 +14,7 @@ from qtpy import QtCore, QtWidgets -from MDANSE_GUI.PyQtGUI.pygenplot.dialogs.units_editor_dialog import UnitsEditorDialog +from MDANSE_GUI.pygenplot.dialogs.units_editor_dialog import UnitsEditorDialog class ActionsWidget(QtWidgets.QWidget): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/data_widget.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/data_widget.py similarity index 96% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/data_widget.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/data_widget.py index 295bf183b8..08ae39614b 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/data_widget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/data_widget.py @@ -14,8 +14,8 @@ from qtpy import QtCore, QtWidgets -from MDANSE_GUI.PyQtGUI.pygenplot.dialogs.inspect_data_dialog import InspectDataDialog -from MDANSE_GUI.PyQtGUI.pygenplot.models.data_tree_model import DataItem, DataTreeModel +from MDANSE_GUI.pygenplot.dialogs.inspect_data_dialog import InspectDataDialog +from MDANSE_GUI.pygenplot.models.data_tree_model import DataItem, DataTreeModel class DataWidget(QtWidgets.QWidget): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/datasets_widget.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/datasets_widget.py similarity index 97% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/datasets_widget.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/datasets_widget.py index 1b23b26e63..a360e5b5d1 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/datasets_widget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/datasets_widget.py @@ -14,7 +14,7 @@ from qtpy import QtCore, QtWidgets -from MDANSE_GUI.PyQtGUI.pygenplot.models.data_tree_model import ( +from MDANSE_GUI.pygenplot.models.data_tree_model import ( DataTreeItem, DataTreeModel, ) diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/logger_widget.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/logger_widget.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/logger_widget.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/logger_widget.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/main_window.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/main_window.py similarity index 94% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/main_window.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/main_window.py index 8a69d7fa09..6942f00263 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/main_window.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/main_window.py @@ -17,16 +17,16 @@ from qtpy import QtCore, QtWidgets -from MDANSE_GUI.PyQtGUI.pygenplot.models.data_tree_model import ( +from MDANSE_GUI.pygenplot.models.data_tree_model import ( DATA_ITEMS, DataTreeModelError, ) -from MDANSE_GUI.PyQtGUI.pygenplot.models.plot_1d_model import Plot1DModelError -from MDANSE_GUI.PyQtGUI.pygenplot.widgets.data_widget import DataWidget -from MDANSE_GUI.PyQtGUI.pygenplot.widgets.actions_widget import ActionsWidget -from MDANSE_GUI.PyQtGUI.pygenplot.widgets.plot_1d_widget import Plot1DWidget -from MDANSE_GUI.PyQtGUI.pygenplot.widgets.plot_nd_widget import PlotNDWidget -from MDANSE_GUI.PyQtGUI.pygenplot.widgets.preview_widget import PreviewWidget +from MDANSE_GUI.pygenplot.models.plot_1d_model import Plot1DModelError +from MDANSE_GUI.pygenplot.widgets.data_widget import DataWidget +from MDANSE_GUI.pygenplot.widgets.actions_widget import ActionsWidget +from MDANSE_GUI.pygenplot.widgets.plot_1d_widget import Plot1DWidget +from MDANSE_GUI.pygenplot.widgets.plot_nd_widget import PlotNDWidget +from MDANSE_GUI.pygenplot.widgets.preview_widget import PreviewWidget class MainWindow(QtWidgets.QMainWindow): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/plot_1d_widget.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/plot_1d_widget.py similarity index 95% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/plot_1d_widget.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/plot_1d_widget.py index 5f1b2cbed8..9f82698411 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/plot_1d_widget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/plot_1d_widget.py @@ -17,19 +17,19 @@ from pylab import Figure from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT -from MDANSE_GUI.PyQtGUI.pygenplot.dialogs.data_viewer_1d_dialog import ( +from MDANSE_GUI.pygenplot.dialogs.data_viewer_1d_dialog import ( DataViewer1DDialog, ) -from MDANSE_GUI.PyQtGUI.pygenplot.dialogs.plot_1d_axis_settings_dialog import ( +from MDANSE_GUI.pygenplot.dialogs.plot_1d_axis_settings_dialog import ( Plot1DAxisSettingsDialog, ) -from MDANSE_GUI.PyQtGUI.pygenplot.dialogs.plot_1d_general_settings_dialog import ( +from MDANSE_GUI.pygenplot.dialogs.plot_1d_general_settings_dialog import ( Plot1DGeneralSettingsDialog, ) -from MDANSE_GUI.PyQtGUI.pygenplot.dialogs.plot_1d_lines_settings_dialog import ( +from MDANSE_GUI.pygenplot.dialogs.plot_1d_lines_settings_dialog import ( Plot1DLinesSettingsDialog, ) -from MDANSE_GUI.PyQtGUI.pygenplot.models.plot_1d_model import ( +from MDANSE_GUI.pygenplot.models.plot_1d_model import ( Plot1DModel, Plot1DModelError, ) diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/plot_2d_widget.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/plot_2d_widget.py similarity index 93% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/plot_2d_widget.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/plot_2d_widget.py index 59e4f28f01..73960eab31 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/plot_2d_widget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/plot_2d_widget.py @@ -19,17 +19,17 @@ from pylab import Figure from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT -from MDANSE_GUI.PyQtGUI.pygenplot.dialogs.plot_2d_general_settings_dialog import ( +from MDANSE_GUI.pygenplot.dialogs.plot_2d_general_settings_dialog import ( Plot2DGeneralSettingsDialog, ) -from MDANSE_GUI.PyQtGUI.pygenplot.dialogs.plot_2d_image_settings_dialog import ( +from MDANSE_GUI.pygenplot.dialogs.plot_2d_image_settings_dialog import ( Plot2DImageSettingsDialog, ) -from MDANSE_GUI.PyQtGUI.pygenplot.models.plot_2d_model import ( +from MDANSE_GUI.pygenplot.models.plot_2d_model import ( Plot2DModel, Plot2DModelError, ) -from MDANSE_GUI.PyQtGUI.pygenplot.dialogs.cross_viewer_dialog import CrossViewerDialog +from MDANSE_GUI.pygenplot.dialogs.cross_viewer_dialog import CrossViewerDialog class Plot2DWidget(QtWidgets.QWidget): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/plot_actions_widget.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/plot_actions_widget.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/plot_actions_widget.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/plot_actions_widget.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/plot_nd_widget.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/plot_nd_widget.py similarity index 92% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/plot_nd_widget.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/plot_nd_widget.py index 69a4b7ce8d..7363a4c0c2 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/plot_nd_widget.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/plot_nd_widget.py @@ -17,21 +17,21 @@ from pylab import Figure from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT -from MDANSE_GUI.PyQtGUI.pygenplot.dialogs.cross_viewer_dialog import CrossViewerDialog -from MDANSE_GUI.PyQtGUI.pygenplot.dialogs.data_viewer_nd_dialog import ( +from MDANSE_GUI.pygenplot.dialogs.cross_viewer_dialog import CrossViewerDialog +from MDANSE_GUI.pygenplot.dialogs.data_viewer_nd_dialog import ( DataViewerNDDialog, ) -from MDANSE_GUI.PyQtGUI.pygenplot.dialogs.slice_viewer_dialog import SliceViewerDialog -from MDANSE_GUI.PyQtGUI.pygenplot.dialogs.plot_nd_axis_settings_dialog import ( +from MDANSE_GUI.pygenplot.dialogs.slice_viewer_dialog import SliceViewerDialog +from MDANSE_GUI.pygenplot.dialogs.plot_nd_axis_settings_dialog import ( PlotNDAxisSettingsDialog, ) -from MDANSE_GUI.PyQtGUI.pygenplot.dialogs.plot_nd_general_settings_dialog import ( +from MDANSE_GUI.pygenplot.dialogs.plot_nd_general_settings_dialog import ( PlotNDGeneralSettingsDialog, ) -from MDANSE_GUI.PyQtGUI.pygenplot.dialogs.plot_nd_image_settings_dialog import ( +from MDANSE_GUI.pygenplot.dialogs.plot_nd_image_settings_dialog import ( PlotNDImageSettingsDialog, ) -from MDANSE_GUI.PyQtGUI.pygenplot.models.plot_nd_model import PlotNDModel +from MDANSE_GUI.pygenplot.models.plot_nd_model import PlotNDModel class PlotNDWidget(QtWidgets.QWidget): diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/preview_widget.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/preview_widget.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/preview_widget.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/preview_widget.py diff --git a/MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/range_slider.py b/MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/range_slider.py similarity index 100% rename from MDANSE_GUI/Src/MDANSE_GUI/PyQtGUI/pygenplot/widgets/range_slider.py rename to MDANSE_GUI/Src/MDANSE_GUI/pygenplot/widgets/range_slider.py diff --git a/MDANSE_GUI/Tests/UnitTests/PyQtGUI/test_ColourManager.py b/MDANSE_GUI/Tests/UnitTests/PyQtGUI/test_ColourManager.py index c2d601cf12..e48b8b70b3 100644 --- a/MDANSE_GUI/Tests/UnitTests/PyQtGUI/test_ColourManager.py +++ b/MDANSE_GUI/Tests/UnitTests/PyQtGUI/test_ColourManager.py @@ -3,8 +3,8 @@ import numpy as np -from MDANSE_GUI.PyQtGUI.MolecularViewer.ColourManager import ColourManager, RGB_COLOURS -from MDANSE_GUI.PyQtGUI.MolecularViewer.database import CHEMICAL_ELEMENTS +from MDANSE_GUI.MolecularViewer.ColourManager import ColourManager, RGB_COLOURS +from MDANSE_GUI.MolecularViewer.database import CHEMICAL_ELEMENTS @pytest.fixture(scope="function", params=[None, RGB_COLOURS]) diff --git a/MDANSE_GUI/Tests/UnitTests/PyQtGUI/test_FileObject.py b/MDANSE_GUI/Tests/UnitTests/PyQtGUI/test_FileObject.py index fb9476f228..ecf9ad7d1a 100644 --- a/MDANSE_GUI/Tests/UnitTests/PyQtGUI/test_FileObject.py +++ b/MDANSE_GUI/Tests/UnitTests/PyQtGUI/test_FileObject.py @@ -1,7 +1,7 @@ import pytest import tempfile -from MDANSE_GUI.PyQtGUI.DataViewModel.TrajectoryHolder import FileObject +from MDANSE_GUI.DataViewModel.TrajectoryHolder import FileObject reference_bytes = b"TeStCaSeFoRtHeCaChEfuNcTiOn" reference_hash = "7105425fa73f3e6a31b72ae2ee36235bcf1f4883b16e674b80a04d6587d995ec" diff --git a/MDANSE_GUI/Tests/UnitTests/PyQtGUI/test_hdf5wrapper.py b/MDANSE_GUI/Tests/UnitTests/PyQtGUI/test_hdf5wrapper.py index be3140920e..907750737f 100644 --- a/MDANSE_GUI/Tests/UnitTests/PyQtGUI/test_hdf5wrapper.py +++ b/MDANSE_GUI/Tests/UnitTests/PyQtGUI/test_hdf5wrapper.py @@ -56,7 +56,7 @@ from MDANSE.MolecularDynamics.Trajectory import Trajectory, TrajectoryWriter from MDANSE.Framework.InputData.HDFTrajectoryInputData import HDFTrajectoryInputData -from MDANSE_GUI.PyQtGUI.MolecularViewer.readers.hdf5wrapper import HDF5Wrapper +from MDANSE_GUI.MolecularViewer.readers.hdf5wrapper import HDF5Wrapper N_ATOMS = 4 N_TIMESTEPS = 150