diff --git a/AUTHORS.txt b/AUTHORS.txt index 1ea282b..cddf273 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -2,6 +2,6 @@ This code is developed by: Xiaohao Yang -This code was developed as part of the xPDFsuite project to create software -and tools for general researchers to use PDF in their work. For more +This code was developed as part of the xPDFsuite project to create software +and tools for general researchers to use PDF in their work. For more information on the DiffPy project email sb2896@columbia.edu diff --git a/README.rst b/README.rst index 40653f7..6cc2e20 100644 --- a/README.rst +++ b/README.rst @@ -26,13 +26,13 @@ INSTALLATION ------------------------------------------------------------------------ We are going to release conda package for all platform. For general user -please use the installation file and install software. For developor, +please use the installation file and install software. For developor, you can install dpx.srxplanargui using python setup.py install - -Note: the dependency is not specified in the setup.py. You need to install -them yourself. You can use Anaconda or other python enviroment. + +Note: the dependency is not specified in the setup.py. You need to install +them yourself. You can use Anaconda or other python enviroment. CONTACTS diff --git a/dpx/srxplanargui/calibration.py b/dpx/srxplanargui/calibration.py deleted file mode 100644 index 579babd..0000000 --- a/dpx/srxplanargui/calibration.py +++ /dev/null @@ -1,359 +0,0 @@ -#!/usr/bin/env python -############################################################################## -# -# dpx.pdfgetxgui by Simon J. L. Billinge group -# (c) 2012 Trustees of the Columbia University -# in the City of New York. All rights reserved. -# -# File coded by: Xiaohao Yang -# -# See AUTHORS.txt for a list of people who contributed. -# See LICENSE.txt for license information. -# -############################################################################## - -import numpy as np -import os -import sys -import re - -from traits.etsconfig.api import ETSConfig -ETSConfig.toolkit = 'qt4' - -from traits.api import \ - Dict, List, Enum, Bool, File, Float, Int, Array, Str, Range, Directory, CFloat, CInt, \ - HasTraits, Property, Instance, Event, Button, Any, \ - on_trait_change, DelegatesTo, cached_property, property_depends_on - -from traitsui.api import \ - Item, Group, View, Handler, Controller, spring, Action, \ - HGroup, VGroup, Tabbed, \ - RangeEditor, CheckListEditor, TextEditor, EnumEditor, ButtonEditor, \ - ArrayEditor, TitleEditor, TableEditor, HistoryEditor, InstanceEditor, ImageEditor -from traitsui.menu import ToolBar, OKButton, CancelButton, Menu, MenuBar, OKCancelButtons -from pyface.api import ImageResource, SplashScreen - -from dpx.srxplanargui.srxconfig import SrXconfig -from diffpy.srxplanar.srxplanar import SrXplanar -from diffpy.srxplanar.selfcalibrate import selfCalibrate -from diffpy.srxplanar.srxplanarconfig import checkMax - -from diffpy.srxconfutils.tools import module_exists_lower -if module_exists_lower('pyfai'): - import pyFAI - missingpyFAI = False -else: - missingpyFAI = True - -# determine option name for calibrant used in pyFAI-calib -# The current option is "-c", but it was "-S" in 0.9.3. -pyFAIcalib_opt_calibrant = '-c' -if not missingpyFAI: - from pkg_resources import parse_version - if parse_version(pyFAI.version) <= parse_version('0.9.3'): - pyFAIcalib_opt_calibrant = '-S' - del parse_version - - -class CalibrationHandler(Handler): - - def closed(self, info, is_ok): - ''' - notify main gui to delete current plot in plots list - ''' - if is_ok: - info.object.calibration() - return True - - -class Calibration(HasTraits): - image = File - dspacefile = File - srx = Instance(SrXplanar) - srxconfig = Instance(SrXconfig) - pythonbin = File - pyFAIdir = Directory - caliscript = File - missingpyFAI = Bool(False) - - xpixelsize = DelegatesTo('srxconfig') - ypixelsize = DelegatesTo('srxconfig') - wavelength = DelegatesTo('srxconfig') - xbeamcenter = DelegatesTo('srxconfig') - ybeamcenter = DelegatesTo('srxconfig') - xdimension = DelegatesTo('srxconfig') - ydimension = DelegatesTo('srxconfig') - distance = DelegatesTo('srxconfig') - rotationd = DelegatesTo('srxconfig') - tiltd = DelegatesTo('srxconfig') - configmode = DelegatesTo('srxconfig') - xpixelsizetem = DelegatesTo('srxconfig') - ypixelsizetem = DelegatesTo('srxconfig') - - def __init__(self, *args, **kwargs): - super(Calibration, self).__init__(*args, **kwargs) - self.locatePyFAI() - self.missingpyFAI = missingpyFAI - return - - def locatePyFAI(self): - pythonbin = sys.executable - if sys.platform == 'win32': - pyFAIdir = os.path.join(sys.exec_prefix, 'Scripts') - elif sys.platform == 'linux2': - pyFAIdir = os.path.join(sys.exec_prefix, 'bin') - else: - pyFAIdir = os.path.join(sys.exec_prefix, 'bin') - self.pythonbin = pythonbin - self.pyFAIdir = pyFAIdir - return - - @on_trait_change('pyFAIdir') - def _pyFAIdirChanged(self): - if sys.platform == 'win32': - caliscript = os.path.join(self.pyFAIdir, 'pyFAI-calib.py') - intescript = os.path.join(self.pyFAIdir, 'pyFAI-waxs.py') - elif sys.platform == 'linux2': - caliscript = os.path.join(self.pyFAIdir, 'pyFAI-calib') - intescript = os.path.join(self.pyFAIdir, 'pyFAI-waxs') - else: - caliscript = os.path.join(self.pyFAIdir, 'pyFAI-calib') - intescript = os.path.join(self.pyFAIdir, 'pyFAI-waxs') - self.caliscript = caliscript - self.intescript = intescript - return - - def callPyFAICalibration(self, image=None, dspacefile=None): - if image == None: - image = self.image - else: - self.image = image - if dspacefile == None: - dspacefile = self.dspacefile - else: - self.dspacefile = dspacefile - - flag = False - if os.path.exists(image) and os.path.isfile(image): - if os.path.exists(dspacefile) and os.path.isfile(dspacefile): - flag = True - - if flag: - image = os.path.abspath(image) - dspacefile = os.path.abspath(dspacefile) - - # remove .npt and .azim - for f in [os.path.splitext(image)[0] + '.npt', - os.path.splitext(image)[0] + '.azim']: - if os.path.exists(f): - os.remove(f) - - ps = [self.xpixelsize * 1000, self.ypixelsize * 1000] - - calicmd = [self.pythonbin, self.caliscript] - calicmd.extend(['-w', str(self.wavelength)]) - calicmd.extend([pyFAIcalib_opt_calibrant, str(dspacefile)]) - calicmd.extend(['-p', str(ps[0]) + ',' + str(ps[1])]) - calicmd.extend([str(image)]) - - import subprocess - try: - os.environ.pop('QT_API') - except: - pass - subprocess.call(calicmd) - - # integrate image - ponifile = os.path.splitext(str(image))[0] + '.poni' - intecmd = [ - self.pythonbin, self.intescript, '-p', ponifile, str(image)] - subprocess.call(intecmd) - self.parsePyFAIoutput(image) - print 'Calibration finished!' - return - - def parsePyFAIoutput(self, image=None): - if image == None: - image = self.image - - filename = os.path.splitext(image)[0] + '.xy' - if os.path.exists(filename): - f = open(filename, 'r') - lines = f.readlines() - f.close() - else: - raise ValueError('pyFAI results file does not exist.') - for line in lines: - if re.search('# Distance Sample-beamCenter', line): - distance = findFloat(line)[0] - elif re.search('# Center', line): - x, y = findFloat(line) - elif re.search('# Tilt', line): - tiltd, rotationd = findFloat(line) - - self.distance = distance - self.xbeamcenter = x # - 0.5 - self.ybeamcenter = y # - y - 0.5 - self.tiltd = tiltd - self.rotationd = rotationd # + 180 - self.srxconfig.flipvertical = False - self.srxconfig.fliphorizontal = False - return - - def selfCalibration(self, image=None): - # self.addfiles.selected[0].fullname - if image == None: - image = self.image - - if os.path.exists(image) and os.path.isfile(image): - for mode, showresults in zip(['x', 'y', 'x', 'y'], [False, False, False, True]): - selfCalibrate(self.srx, image, mode=mode, cropedges=self.slice, - showresults=showresults, xywidth=self.xywidth) - return - - slice = Enum(['auto', 'x', 'y', 'box', 'full']) - calibrationmode = Enum(['self', 'calibrant']) - - def calibration(self, image=None, dspacefile=None): - if self.calibrationmode == 'calibrant': - self.callPyFAICalibration(image, dspacefile) - elif self.calibrationmode == 'self': - self.selfCalibration(image) - else: - raise ValueError('calibration mode error') - return - - xywidth = Int(6) - qmincali = Float(0.5) - qmaxcali = Float(10.0) - - @on_trait_change('srxconfig.[xpixelsize, ypixelsize, distance, wavelength, xdimension, ydimension]') - def _qmaxChanged(self): - tthmax, qmax = checkMax(self.srxconfig) - self.qmincali = min(1.25, qmax / 10) - self.qmaxcali = qmax / 2 - return - - inst1 = Str( - 'Please install pyFAI and FabIO to use the calibration function (refer to help).') - inst2 = Str( - '(http://github.com/kif/pyFAI, https://forge.epn-campus.eu/projects/azimuthal/files)') - main_View = \ - View( - # Item('calibrationmode', style='custom', label='Calibration mode'), - Item('image', label='Image file'), - - Group( - Item('inst1', style='readonly'), - Item('inst2', style='readonly'), - visible_when='missingpyFAI and calibrationmode=="calibrant"', - show_border=True, - show_labels=False, - ), - Group( - Item('dspacefile', label='D-space file'), - Item('pyFAIdir', label='pyFAI dir.'), - show_border=True, - visible_when='calibrationmode=="calibrant"', - enabled_when='not missingpyFAI', - label='Please specify the d-space file and the location of pyFAI executable' - ), - HGroup( - Item('xpixelsize', label='Pixel size x (mm)', - visible_when='configmode == "normal"'), - Item('xpixelsizetem', label='Pixel size x (A^-1)', - visible_when='configmode == "TEM"'), - Item('ypixelsize', label='Pixel size y (mm)', - visible_when='configmode == "normal"'), - Item('ypixelsizetem', label='Pixel size y (A^-1)', - visible_when='configmode == "TEM"'), - visible_when='calibrationmode=="calibrant"', - enabled_when='not missingpyFAI', - show_border=True, - label='Please specify the size of pixel' - ), - HGroup( - Item('wavelength', label='Wavelength (A)'), - visible_when='calibrationmode=="calibrant"', - enabled_when='not missingpyFAI', - show_border=True, - label='Please specify the wavelength' - ), - HGroup( - Item('wavelength', visible_when='integrationspace == "qspace"', - label='Wavelength(Angstrom)'), - Item('distance', label='Distance(mm)', - visible_when='configmode == "normal"'), - Item('distance', label='Camera Length(mm)', - visible_when='configmode == "TEM"'), - label='Please specify the wavelength and distance between sample and detector:', - show_border=True, - visible_when='calibrationmode=="self"' - ), - HGroup( - VGroup( - Item('xbeamcenter', label='x beamcenter (pixel)'), - Item('rotationd', label='Rotation (degree)'), - ), - VGroup( - Item('ybeamcenter', label='y beamcenter (pixel)'), - Item('tiltd', label='Tilt rotation (degree)') - ), - show_border=True, - label='Plasee specify the initial value of following parameters:', - visible_when='calibrationmode=="self"' - ), - HGroup( - VGroup( - Item('xdimension', label='x dimension (pixel)'), - Item('xpixelsize', label='Pixel size x (mm)', - visible_when='configmode == "normal"'), - Item('xpixelsizetem', label='Pixel size x (A^-1)', - visible_when='configmode == "TEM"'), - ), - - VGroup( - Item('ydimension', label='y dimension (pixel)'), - Item('ypixelsize', label='Pixel size y (mm)', - visible_when='configmode == "normal"'), - Item('ypixelsizetem', label='Pixel size y (A^-1)', - visible_when='configmode == "TEM"'), - ), - show_border=True, - label='Plasee specify the dimension of detector and size of pixel:', - visible_when='calibrationmode=="self"' - ), - HGroup( - VGroup( - Item('xywidth', label='(x,y) center searching range, +/-'), - Item('slice', label='Refining using slab along'), - ), - VGroup( - Item('qmincali', label='Qmin in calibration'), - Item('qmaxcali', label='Qmax in calibration') - ), - show_border=True, - label='Others', - visible_when='calibrationmode=="self"', - ), - - title='Calibration', - width=600, - height=450, - resizable=True, - buttons=[OKButton, CancelButton], - handler=CalibrationHandler(), - icon=ImageResource('icon.png'), - ) - - -def findFloat(line): - temp = re.findall('[-+]?\d*\.\d+|[-+]?\d+', line) - return map(float, temp) - -if __name__ == '__main__': - srxconfig = SrXconfig() - cali = Calibration(srxconfig=srxconfig) - # cali.callPyFAICalibration('ceo2.tif', 'ceo2.d') - # cali.parsePyFAIoutput() - cali.configure_traits(view='main_View') diff --git a/dpx/srxplanargui/live.py b/dpx/srxplanargui/live.py deleted file mode 100644 index f3b165f..0000000 --- a/dpx/srxplanargui/live.py +++ /dev/null @@ -1,161 +0,0 @@ -#!/usr/bin/env python -############################################################################## -# -# dpx.pdfgetxgui by Simon J. L. Billinge group -# (c) 2012 Trustees of the Columbia University -# in the City of New York. All rights reserved. -# -# File coded by: Xiaohao Yang -# -# See AUTHORS.txt for a list of people who contributed. -# See LICENSE.txt for license information. -# -############################################################################## - -'''provide UI for srxplanar -''' - -import numpy as np -import re -import os -import sys -from functools import partial -import threading -import time - -from traits.etsconfig.api import ETSConfig -ETSConfig.toolkit = 'qt4' - -from traits.api import \ - Dict, List, Enum, Bool, File, Float, Int, Array, Str, Range, Directory, CFloat, CInt, \ - HasTraits, Property, Instance, Event, Button, Any, \ - on_trait_change, DelegatesTo, cached_property, property_depends_on - -from traitsui.api import \ - Item, Group, View, Handler, Controller, spring, Action, \ - HGroup, VGroup, Tabbed, \ - RangeEditor, CheckListEditor, TextEditor, EnumEditor, ButtonEditor, \ - ArrayEditor, TitleEditor, TableEditor, HistoryEditor, InstanceEditor, ImageEditor -from traitsui.menu import ToolBar, OKButton, CancelButton, Menu, MenuBar, OKCancelButtons -from pyface.api import ImageResource, GUI, SplashScreen - -from dpx.srxplanargui.selectfiles import AddFiles -from dpx.srxplanargui.srxconfig import SrXconfig -from dpx.srxplanargui.srxgui import SrXgui, SrXguiHandler, SaveHandler, LoadHandler -from diffpy.srxplanar.srxplanar import SrXplanar -from dpx.srxplanargui.help import SrXguiHelp -from dpx.srxplanargui.calibration import Calibration - -from diffpy.srxconfutils.tools import checkFileVal - -class SrXguiLive(SrXgui): - - getxgui = Any - - def __init__(self, configfile=None, args=None, **kwargs): - - # init the object, createt the notifications - - self.splash = SplashScreen(image=ImageResource('01.png'), show_log_messages=False) - self.splash.open() - - super(SrXgui, self).__init__(**kwargs) - configfile = self.detectConfigfile(configfile) - if not os.path.exists(configfile): - configfile = self.detectConfigfile('default') - self.configfile = configfile - - if not kwargs.has_key('srxconfig'): - self.srxconfig = SrXconfig(filename=configfile, args=args, **kwargs) - - self.addfiles = AddFiles(srxconfig=self.srxconfig) - self.srx = SrXplanar(self.srxconfig) - self.addfiles.srx = self.srx - self.help = SrXguiHelp() - self.calibration = Calibration(srx=self.srx, srxconfig=self.srxconfig) - self.splash.close() - return - - @on_trait_change('srxconfig.savedirectory') - def _changedir(self): - newdir = self.srxconfig.savedirectory - if os.path.exists(newdir): - self.getxgui.getxconfig.inputdir = os.path.abspath(newdir) - self.getxgui.getxconfig.savedir = os.path.abspath(newdir) - else: - self.getxgui.getxconfig.inputdir = os.path.abspath(os.path.curdir) - self.getxgui.getxconfig.savedir = os.path.abspath(os.path.curdir) - return - - def processSelected(self, summation=False): - if self.addfiles.selected: - self.srx.updateConfig() - filelist = [f.fullname for f in self.addfiles.selected] - self.srx.prepareCalculation(filelist) - rvlist = self.srx.integrateFilelist(filelist, summation=summation) - newchifilelist = [rv['filename'] for rv in rvlist] - GUI.invoke_later(self.addNewImagesToGetXgui, newchifilelist) - return - - def addNewImagesToGetXgui(self, filelist): - ''' - add new images to getxgui, if images are already there, refresh them - - :param filelist: list of full path of new images - ''' - self.addfiles.refreshdatalist = True - newdatacontainers = self.getxgui.selectfiles.addFiles(filelist) - self.getxgui.createNewPlot(newdatacontainers) - return - - helpbutton_action = \ - Action(name='Help ', - action='_helpView') - saveconfig_action = \ - Action(name='Save Config', - action='_saveconfigView', - enabled_when='not capturing') - loadconfig_action = \ - Action(name='Load Config', - action='_loadconfigView', - enabled_when='not capturing') - - traits_view = \ - View( - HGroup( - Item('addfiles', editor=InstanceEditor(view='traits_view'), - style='custom', label='Files', width=0.4), - VGroup( - Group(Item('srxconfig', editor=InstanceEditor(view='main_view'), - style='custom', label='Basic', show_label=False), - springy=True, - ), - HGroup(spring, - Item('selfcalibratebb', enabled_when='not capturing'), - Item('integratbb', enabled_when='not capturing'), - spring, - show_labels=False, - ), - ), - layout='split', - springy=True, - dock='tab', - show_labels=False - ), - resizable=True, - title='SrXgui', - width=700, - height=650, - kind='live', - icon=ImageResource('icon.png'), - handler=SrXguiHandler(), - buttons=[helpbutton_action, saveconfig_action, loadconfig_action, OKButton], - ) - -def main(): - gui = SrXguiLive() - gui.configure_traits(view='traits_view') - return - -if __name__ == '__main__': - sys.exit(main()) diff --git a/dpx/srxplanargui/srxconfig.py b/dpx/srxplanargui/srxconfig.py deleted file mode 100644 index 4782ddb..0000000 --- a/dpx/srxplanargui/srxconfig.py +++ /dev/null @@ -1,234 +0,0 @@ -#!/usr/bin/env python -############################################################################## -# -# diffpy.srxplanar by DANSE Diffraction group -# Simon J. L. Billinge -# (c) 2010 Trustees of the Columbia University -# in the City of New York. All rights reserved. -# -# File coded by: Xiaohao Yang -# -# See AUTHORS.txt for a list of people who contributed. -# See LICENSENOTICE.txt for license information. -# -############################################################################## - -import numpy as np -import configparser -import re, os, sys -from functools import partial -import argparse - -from traits.etsconfig.api import ETSConfig -ETSConfig.toolkit = 'qt4' - -from traits.api import \ - Dict, List, Enum, Bool, File, Float, Int, Array, Str, Range, Directory, CFloat, CInt, \ - HasTraits, Property, Instance, Event, Button, Any, \ - on_trait_change, DelegatesTo, cached_property, property_depends_on - -from traitsui.api import \ - Item, Group, View, Handler, Controller, spring, Action, \ - HGroup, VGroup, Tabbed, \ - RangeEditor, CheckListEditor, TextEditor, EnumEditor, ButtonEditor, \ - ArrayEditor, TitleEditor, TableEditor, HistoryEditor, InstanceEditor, BooleanEditor -from traitsui.menu import ToolBar, OKButton, CancelButton, Menu, MenuBar, OKCancelButtons -from pyface.api import ImageResource - -from diffpy.srxconfutils.configtraits import ConfigBaseTraits -from diffpy.srxconfutils.tools import _configPropertyRad, _configPropertyR, _configPropertyRW -from diffpy.srxplanar.srxplanarconfig import _description, _epilog, _optdatalist, \ - _defaultdata, checkMax - -_optdatalist.append( - ['xpixelsizetem', {'sec':'Beamline', - 'h':'detector pixel size in x axis, in A^-1', - 'd':0.02, }] - ) -_optdatalist.append( - ['ypixelsizetem', {'sec':'Beamline', - 'h':'detector pixel size in y axis, in A^-1', - 'd':0.02, }] - ) - -for i in _optdatalist: - if i[0] == 'polcorrectionenable': - i[1] = {'sec':'Others', 'args':'n', 'config':'n', 'header':'n', - 's':'polarcorr', - 'h':'enable polarization correction', - 'n':'?', - 'co':False, - 'd':False, } - elif i[0] == 'polcorrectf': - i[1] = {'sec':'Others', 'args':'n', 'config':'n', 'header':'n', - 's':'polarf', - 'h':'polarization correction factor', - 'd':0.99, } - elif i[0] == 'xpixelsize': - i[1] = {'sec':'Beamline', 'args':'n', 'config':'n', 'header':'n', - 's':'xp', - 'h':'detector pixel size in x axis, in mm', - 'd':0.2, } - elif i[0] == 'ypixelsize': - i[1] = {'sec':'Beamline', 'args':'n', 'config':'n', 'header':'n', - 's':'yp', - 'h':'detector pixel size in y axis, in mm', - 'd':0.2, } - - -class SrXconfig(ConfigBaseTraits): - ''' - config class, based on ConfigBase class in diffpy.confutils - ''' - - # Text to display before the argument help - _description = _description - - # Text to display after the argument help - _epilog = _epilog - - _optdatalist = _optdatalist - - _defaultdata = {'configfile': [], - 'headertitle': 'SrXgui configration' - } - - rotation = Property(depends_on='rotationd', fget=lambda self: np.radians(self.rotationd)) - tilt = Property(depends_on='tiltd', fget=lambda self: np.radians(self.tiltd)) - tthstep = Property(depends_on='tthstepd', fget=lambda self: np.radians(self.tthstepd)) - tthmax = Property(depends_on='tthmaxd', fget=lambda self: np.radians(self.tthmaxd)) - - tthorqmax = Property(depends_on='integrationspace, tthmaxd, qmax', - fget=lambda self: self.tthmax if self.integrationspace == 'twotheta' else self.qmax) - tthorqstep = Property(depends_on='integrationspace, tthmaxd, qmax', - fget=lambda self: self.tthstep if self.integrationspace == 'twotheta' else self.qstep) - - def _preUpdateSelf(self, **kwargs): - ''' - additional process called in self._updateSelf, this method is called - before self._copySelftoConfig(), i.e. before copy options value to - self.config (config file) - - check the tthmaxd and qmax, and set tthorqmax, tthorqstep according to integration space - - :param kwargs: optional kwargs - ''' - self.tthmaxd, self.qmax = checkMax(self) - '''addmask = [b for b in self.addmask if not (b in ['brightpixel', 'darkpixel'])] - if len(addmask) > 0: - self.maskfile = addmask[0]''' - return - - def _opendirectory_changed(self): - if os.path.exists(self.opendirectory): - self.savedirectory = os.path.abspath(self.opendirectory) - else: - self.opendirectory = os.path.abspath(os.curdir) - self.savedirectory = os.path.abspath(os.curdir) - return - - def _savedirectory_changed(self): - if not os.path.exists(self.savedirectory): - self.savedirectory = os.path.abspath(os.curdir) - return - - configmode = Enum(['TEM', 'normal']) - - @on_trait_change('distance, wavelength, xpixelsizetem, ypixelsizetem') - def _refreshPSsize(self, obj, name, new): - self.updateConfig(xpixelsize=self.xpixelsizetem * self.wavelength * self.distance, - ypixelsize=self.ypixelsizetem * self.wavelength * self.distance) - return - - directory_group = \ - Group(Item('opendirectory', label='Input dir.', help='directory of 2D images'), - Item('savedirectory', label='Output dir.', help='directory of saved files'), - show_border=True, - label='Files', - ) - mask_group = \ - Group(Item('maskfile', label='Mask file'), - show_border=True, - label='Masks', - ) - - geometry_visible = Bool(False) - geometry_group = \ - Group(Item('integrationspace', label='Integration grid'), - Item('wavelength', visible_when='integrationspace == "qspace"', label='Wavelength',), - Item('xbeamcenter', label='X beamcenter'), - Item('ybeamcenter', label='Y beamcenter'), - Item('distance', label='Camera length', visible_when='configmode == "TEM"'), - Item('distance', label='Distance', visible_when='configmode == "normal"'), - Item('rotationd', label='Rotation'), - Item('tiltd', label='Tilt rotation'), - Item('tthstepd', label='Integration step', visible_when='integrationspace == "twotheta"'), - Item('qstep', label='Integration step', visible_when='integrationspace == "qspace"'), - - show_border=True, - # label='Geometry parameters', - visible_when='geometry_visible', - ) - - correction_visible = Bool(False) - correction_group = \ - Group(Item('uncertaintyenable', label='Uncertainty'), - Item('sacorrectionenable', label='solid angle corr.'), - # Item('polcorrectionenable', label='polarization corr.'), - # Item('polcorrectf', label='polarization factor'), - - # Item('brightpixelmask', label='Bright pixel mask'), - # Item('darkpixelmask', label='Dark pixel mask'), - # Item('avgmask', label='Average mask'), - # Item('cropedges', label='Crop edges', editor=ArrayEditor(width=-50)), - - show_border=True, - # label='Corrections' - visible_when='correction_visible' - ) - - detector_visible = Bool(False) - detector_group = \ - Group(Item('fliphorizontal', label='Flip horizontally'), - Item('flipvertical', label='Flip vertically'), - Item('xdimension', label='x dimension'), - Item('ydimension', label='y dimension'), - Item('xpixelsizetem', label='x pixel size (A^-1)', tooltip='x pixel size, in A^-1', visible_when='configmode == "TEM"'), - Item('ypixelsizetem', label='y pixel size (A^-1)', tooltip='y pixel size, in A^-1', visible_when='configmode == "TEM"'), - - show_border=True, - # label='Detector parameters' - visible_when='detector_visible' - ), - - main_view = \ - View( - Group( - directory_group, - mask_group, - Group( - # Item('configmode'), - Group(Item('geometry_visible', label='Geometry parameters'), - geometry_group,), - Group(Item('correction_visible', label='Corrections'), - correction_group,), - Group(Item('detector_visible', label='Detector parameters'), - detector_group,), - # label = 'Basic' - show_border=True, - ), - ), - - resizable=True, - scrollable=True, - # handler = handler, - icon=ImageResource('icon.png'), - ) - - -SrXconfig.initConfigClass() - -if __name__ == '__main__': - a = SrXconfig() - # a.updateConfig() - a.configure_traits(view='main_view') diff --git a/dpx/srxplanargui/srxgui.py b/dpx/srxplanargui/srxgui.py deleted file mode 100644 index 5808087..0000000 --- a/dpx/srxplanargui/srxgui.py +++ /dev/null @@ -1,262 +0,0 @@ -#!/usr/bin/env python -############################################################################## -# -# dpx.pdfgetxgui by Simon J. L. Billinge group -# (c) 2012 Trustees of the Columbia University -# in the City of New York. All rights reserved. -# -# File coded by: Xiaohao Yang -# -# See AUTHORS.txt for a list of people who contributed. -# See LICENSE.txt for license information. -# -############################################################################## - -'''provide UI for srxplanar -''' - -import numpy as np -import os -import sys - -from traits.etsconfig.api import ETSConfig -ETSConfig.toolkit = 'qt4' - -from traits.api import \ - Dict, List, Enum, Bool, File, Float, Int, Array, Str, Range, Directory, CFloat, CInt, \ - HasTraits, Property, Instance, Event, Button, Any, \ - on_trait_change, DelegatesTo, cached_property, property_depends_on - -from traitsui.api import \ - Item, Group, View, Handler, Controller, spring, Action, \ - HGroup, VGroup, Tabbed, \ - RangeEditor, CheckListEditor, TextEditor, EnumEditor, ButtonEditor, \ - ArrayEditor, TitleEditor, TableEditor, HistoryEditor, InstanceEditor, ImageEditor -from traitsui.menu import ToolBar, OKButton, CancelButton, Menu, MenuBar, OKCancelButtons -from pyface.api import ImageResource, SplashScreen - -from dpx.srxplanargui.selectfiles import AddFiles -from dpx.srxplanargui.srxconfig import SrXconfig -from diffpy.srxplanar.srxplanar import SrXplanar -from dpx.srxplanargui.help import SrXguiHelp -from dpx.srxplanargui.calibration import Calibration - -class SrXguiHandler(Handler): - - def closed(self, info, is_ok): - ''' - notify main gui to delete current plot in plots list - ''' - configfile = info.object.detectConfigfile('default') - info.object.saveConfig(configfile) - return True - - def _saveconfigView(self, info): - info.object._saveconfigView() - return - - def _loadconfigView(self, info): - info.object._loadconfigView() - return - - def _helpView(self, info): - info.object._helpbb_changed() - return - -class SaveHandler(Handler): - - def closed(self, info, is_ok): - if is_ok: - info.object.saveConfig(info.object.configfile) - return True - -class LoadHandler(Handler): - def closed(self, info, is_ok): - if is_ok: - info.object.loadConfig(info.object.configfile) - return - -class SrXgui(HasTraits): - - addfiles = Instance(AddFiles) - srxconfig = Instance(SrXconfig) - help = Instance(SrXguiHelp) - splash = Any - calibration = Instance(Calibration) - - def __init__(self, configfile=None, args=None, **kwargs): - ''' - init the object, createt the notifications - ''' - super(SrXgui, self).__init__(**kwargs) - configfile = self.detectConfigfile(configfile) - if not os.path.exists(configfile): - configfile = self.detectConfigfile('default') - self.configfile = configfile - - if not kwargs.has_key('srxconfig'): - self.srxconfig = SrXconfig(filename=configfile, args=args, **kwargs) - - self.addfiles = AddFiles(srxconfig=self.srxconfig) - self.srx = SrXplanar(self.srxconfig) - self.addfiles.srx = self.srx - self.help = SrXguiHelp() - self.calibration = Calibration(srx=self.srx, srxconfig=self.srxconfig) - - # self.loadConfig(configfile) - self.splash.close() - return - - def saveConfig(self, filename=None): - ''' - save config - ''' - if filename == 'default': - filename = self.detectConfigfile(filename) - self.srxconfig.writeConfig(filename, mode='full') - self.configfile = filename - return - - def loadConfig(self, filename=None): - ''' - load config - ''' - configfile = self.detectConfigfile(filename) - if os.path.exists(configfile): - self.srxconfig.updateConfig(filename=configfile) - self.configfile = configfile - return - - def processSelected(self, summation=False): - if self.addfiles.selected: - self.srx.updateConfig() - filelist = [f.fullname for f in self.addfiles.selected] - self.srx.prepareCalculation(filelist) - self.srx.integrateFilelist(filelist, summation=summation) - return - - def detectConfigfile(self, filename): - ''' - current directory > home directory, if none, then return the curdir+filename - if 'default', then return home+filename - ''' - if filename == None: - configfile = os.path.join(os.path.curdir, 'srxconfig.cfg') - elif filename == 'default': - configfile = os.path.join(os.path.expanduser('~'), 'srxconfig.cfg') - else: - if os.path.abspath(filename): - if os.path.exists(filename): - configfile = filename - else: - filename = os.path.split(filename)[1] - configfile = os.path.join(os.path.curdir, filename) - else: - configfile = os.path.join(os.path.curdir, filename) - return configfile - - - ########################################################### - def _saveconfigView(self): - self.edit_traits(view='saveconfig_view') - return - def _loadconfigView(self): - self.edit_traits(view='loadconfig_view') - return - - configfile = File() - helpbutton_action = \ - Action(name='Help ', - action='_helpView') - saveconfig_action = \ - Action(name='Save Config', - action='_saveconfigView') - loadconfig_action = \ - Action(name='Load Config', - action='_loadconfigView') - - saveconfig_view = \ - View(Item('configfile'), - - resizable=True, - title='Save config', - width=500, - buttons=[OKButton, CancelButton], - handler=SaveHandler(), - icon=ImageResource('icon.png'), - ) - loadconfig_view = \ - View(Item('configfile'), - - resizable=True, - title='Load config', - width=500, - buttons=[OKButton, CancelButton], - handler=LoadHandler(), - icon=ImageResource('icon.png'), - ) - ############################################################# - - def _integratbb_changed(self): - self.processSelected(False) - return - - def _integratessbb_changed(self): - self.processSelected(True) - return - - def _helpbb_changed(self): - self.help.edit_traits(view='quickstart_view') - return - - def _selfcalibratebb_changed(self): - image = None - if self.addfiles.selected != None: - if len(self.addfiles.selected) == 1: - image = self.addfiles.selected[0].fullname - - if image != None: - self.calibration.image = image - self.calibration.edit_traits(view='main_View') - return - - integratbb = Button('Integrate') - integratessbb = Button('Sum and Integrate') - selfcalibratebb = Button('Calibrate') - helpbb = Button('Help') - - traits_view = \ - View( - HGroup( - Item('addfiles', editor=InstanceEditor(view='traits_view'), - style='custom', label='Files', width=0.4), - VGroup( - Group(Item('srxconfig', editor=InstanceEditor(view='main_view'), - style='custom', label='Basic', show_label=False), - springy=True, - ), - HGroup(spring, - Item('selfcalibratebb'), - Item('integratbb'), - spring, - show_labels=False, - ), - ), - - layout='split', - springy=True, - dock='tab', - show_labels=False - ), - resizable=True, - title='SrXgui', - width=700, - height=650, - kind='live', - buttons=[helpbutton_action, saveconfig_action, loadconfig_action, OKButton], - icon=ImageResource('icon.png'), - handler=SrXguiHandler(), - ) - -if __name__ == '__main__': - sys.exit() diff --git a/pyproject.toml b/pyproject.toml index 38f8c47..e21b5c8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,7 +33,7 @@ classifiers = [ ] [project.scripts] -srxgui = 'dpx.srxplanargui.srxguiapp:main' +srxgui = 'diffpy.srxplanargui.srxguiapp:main' [project.urls] Homepage = "https://github.com/diffpy/diffpy.srxplanargui/" @@ -46,7 +46,7 @@ dev_template = "{tag}" dirty_template = "{tag}" [tool.setuptools.packages.find] -where = ["dpx"] # list of folders that contain the packages (["."] by default) +where = ["src"] # list of folders that contain the packages (["."] by default) include = ["*"] # package names should match these glob patterns (["*"] by default) exclude = [] # exclude packages matching these glob patterns (empty by default) namespaces = false # to disable scanning PEP 420 namespaces (true by default) diff --git a/requirements/pip.txt b/requirements/pip.txt index 0af9d8c..eda5283 100644 --- a/requirements/pip.txt +++ b/requirements/pip.txt @@ -4,4 +4,4 @@ traitsui chaco pyface diffpy.srxplanar -configparser \ No newline at end of file +configparser diff --git a/dpx/__init__.py b/src/diffpy/__init__.py similarity index 85% rename from dpx/__init__.py rename to src/diffpy/__init__.py index 079d0fe..07795ce 100755 --- a/dpx/__init__.py +++ b/src/diffpy/__init__.py @@ -11,11 +11,8 @@ # See LICENSE.txt for license information. # ############################################################################## +"""Blank namespace package.""" -""" -Blank namespace package. -""" - -__import__('pkg_resources').declare_namespace(__name__) +__import__("pkg_resources").declare_namespace(__name__) # End of file diff --git a/dpx/srxplanargui/__init__.py b/src/diffpy/srxplanargui/__init__.py similarity index 91% rename from dpx/srxplanargui/__init__.py rename to src/diffpy/srxplanargui/__init__.py index 1985b91..e3c8752 100755 --- a/dpx/srxplanargui/__init__.py +++ b/src/diffpy/srxplanargui/__init__.py @@ -14,6 +14,6 @@ # obtain version information -from dpx.srxplanargui.version import __version__ +from diffpy.srxplanargui.version import __version__ # End of file diff --git a/src/diffpy/srxplanargui/calibration.py b/src/diffpy/srxplanargui/calibration.py new file mode 100644 index 0000000..939b348 --- /dev/null +++ b/src/diffpy/srxplanargui/calibration.py @@ -0,0 +1,455 @@ +#!/usr/bin/env python +############################################################################## +# +# dpx.pdfgetxgui by Simon J. L. Billinge group +# (c) 2012 Trustees of the Columbia University +# in the City of New York. All rights reserved. +# +# File coded by: Xiaohao Yang +# +# See AUTHORS.txt for a list of people who contributed. +# See LICENSE.txt for license information. +# +############################################################################## + +import os +import re +import sys + +import numpy as np +from traits.etsconfig.api import ETSConfig + +ETSConfig.toolkit = "qt4" + +from diffpy.srxconfutils.tools import module_exists_lower +from diffpy.srxplanar.selfcalibrate import selfCalibrate +from diffpy.srxplanar.srxplanar import SrXplanar +from diffpy.srxplanar.srxplanarconfig import checkMax +from pyface.api import ImageResource, SplashScreen +from traits.api import ( + Any, + Array, + Bool, + Button, + CFloat, + CInt, + DelegatesTo, + Dict, + Directory, + Enum, + Event, + File, + Float, + HasTraits, + Instance, + Int, + List, + Property, + Range, + Str, + cached_property, + on_trait_change, + property_depends_on, +) +from traitsui.api import ( + Action, + ArrayEditor, + ButtonEditor, + CheckListEditor, + Controller, + EnumEditor, + Group, + Handler, + HGroup, + HistoryEditor, + ImageEditor, + InstanceEditor, + Item, + RangeEditor, + Tabbed, + TableEditor, + TextEditor, + TitleEditor, + VGroup, + View, + spring, +) +from traitsui.menu import ( + CancelButton, + Menu, + MenuBar, + OKButton, + OKCancelButtons, + ToolBar, +) + +from diffpy.srxplanargui.srxconfig import SrXconfig + +if module_exists_lower("pyfai"): + import pyFAI + + missingpyFAI = False +else: + missingpyFAI = True + +# determine option name for calibrant used in pyFAI-calib +# The current option is "-c", but it was "-S" in 0.9.3. +pyFAIcalib_opt_calibrant = "-c" +if not missingpyFAI: + from pkg_resources import parse_version + + if parse_version(pyFAI.version) <= parse_version("0.9.3"): + pyFAIcalib_opt_calibrant = "-S" + del parse_version + + +class CalibrationHandler(Handler): + + def closed(self, info, is_ok): + """Notify main gui to delete current plot in plots list.""" + if is_ok: + info.object.calibration() + return True + + +class Calibration(HasTraits): + image = File + dspacefile = File + srx = Instance(SrXplanar) + srxconfig = Instance(SrXconfig) + pythonbin = File + pyFAIdir = Directory + caliscript = File + missingpyFAI = Bool(False) + + xpixelsize = DelegatesTo("srxconfig") + ypixelsize = DelegatesTo("srxconfig") + wavelength = DelegatesTo("srxconfig") + xbeamcenter = DelegatesTo("srxconfig") + ybeamcenter = DelegatesTo("srxconfig") + xdimension = DelegatesTo("srxconfig") + ydimension = DelegatesTo("srxconfig") + distance = DelegatesTo("srxconfig") + rotationd = DelegatesTo("srxconfig") + tiltd = DelegatesTo("srxconfig") + configmode = DelegatesTo("srxconfig") + xpixelsizetem = DelegatesTo("srxconfig") + ypixelsizetem = DelegatesTo("srxconfig") + + def __init__(self, *args, **kwargs): + super(Calibration, self).__init__(*args, **kwargs) + self.locatePyFAI() + self.missingpyFAI = missingpyFAI + return + + def locatePyFAI(self): + pythonbin = sys.executable + if sys.platform == "win32": + pyFAIdir = os.path.join(sys.exec_prefix, "Scripts") + elif sys.platform == "linux2": + pyFAIdir = os.path.join(sys.exec_prefix, "bin") + else: + pyFAIdir = os.path.join(sys.exec_prefix, "bin") + self.pythonbin = pythonbin + self.pyFAIdir = pyFAIdir + return + + @on_trait_change("pyFAIdir") + def _pyFAIdirChanged(self): + if sys.platform == "win32": + caliscript = os.path.join(self.pyFAIdir, "pyFAI-calib.py") + intescript = os.path.join(self.pyFAIdir, "pyFAI-waxs.py") + elif sys.platform == "linux2": + caliscript = os.path.join(self.pyFAIdir, "pyFAI-calib") + intescript = os.path.join(self.pyFAIdir, "pyFAI-waxs") + else: + caliscript = os.path.join(self.pyFAIdir, "pyFAI-calib") + intescript = os.path.join(self.pyFAIdir, "pyFAI-waxs") + self.caliscript = caliscript + self.intescript = intescript + return + + def callPyFAICalibration(self, image=None, dspacefile=None): + if image == None: + image = self.image + else: + self.image = image + if dspacefile == None: + dspacefile = self.dspacefile + else: + self.dspacefile = dspacefile + + flag = False + if os.path.exists(image) and os.path.isfile(image): + if os.path.exists(dspacefile) and os.path.isfile(dspacefile): + flag = True + + if flag: + image = os.path.abspath(image) + dspacefile = os.path.abspath(dspacefile) + + # remove .npt and .azim + for f in [ + os.path.splitext(image)[0] + ".npt", + os.path.splitext(image)[0] + ".azim", + ]: + if os.path.exists(f): + os.remove(f) + + ps = [self.xpixelsize * 1000, self.ypixelsize * 1000] + + calicmd = [self.pythonbin, self.caliscript] + calicmd.extend(["-w", str(self.wavelength)]) + calicmd.extend([pyFAIcalib_opt_calibrant, str(dspacefile)]) + calicmd.extend(["-p", str(ps[0]) + "," + str(ps[1])]) + calicmd.extend([str(image)]) + + import subprocess + + try: + os.environ.pop("QT_API") + except: + pass + subprocess.call(calicmd) + + # integrate image + ponifile = os.path.splitext(str(image))[0] + ".poni" + intecmd = [ + self.pythonbin, + self.intescript, + "-p", + ponifile, + str(image), + ] + subprocess.call(intecmd) + self.parsePyFAIoutput(image) + print("Calibration finished!") + return + + def parsePyFAIoutput(self, image=None): + if image == None: + image = self.image + + filename = os.path.splitext(image)[0] + ".xy" + if os.path.exists(filename): + f = open(filename, "r") + lines = f.readlines() + f.close() + else: + raise ValueError("pyFAI results file does not exist.") + for line in lines: + if re.search("# Distance Sample-beamCenter", line): + distance = findFloat(line)[0] + elif re.search("# Center", line): + x, y = findFloat(line) + elif re.search("# Tilt", line): + tiltd, rotationd = findFloat(line) + + self.distance = distance + self.xbeamcenter = x # - 0.5 + self.ybeamcenter = y # - y - 0.5 + self.tiltd = tiltd + self.rotationd = rotationd # + 180 + self.srxconfig.flipvertical = False + self.srxconfig.fliphorizontal = False + return + + def selfCalibration(self, image=None): + # self.addfiles.selected[0].fullname + if image == None: + image = self.image + + if os.path.exists(image) and os.path.isfile(image): + for mode, showresults in zip( + ["x", "y", "x", "y"], [False, False, False, True] + ): + selfCalibrate( + self.srx, + image, + mode=mode, + cropedges=self.slice, + showresults=showresults, + xywidth=self.xywidth, + ) + return + + slice = Enum(["auto", "x", "y", "box", "full"]) + calibrationmode = Enum(["self", "calibrant"]) + + def calibration(self, image=None, dspacefile=None): + if self.calibrationmode == "calibrant": + self.callPyFAICalibration(image, dspacefile) + elif self.calibrationmode == "self": + self.selfCalibration(image) + else: + raise ValueError("calibration mode error") + return + + xywidth = Int(6) + qmincali = Float(0.5) + qmaxcali = Float(10.0) + + @on_trait_change( + "srxconfig.[xpixelsize, ypixelsize, distance, wavelength, xdimension, ydimension]" + ) + def _qmaxChanged(self): + tthmax, qmax = checkMax(self.srxconfig) + self.qmincali = min(1.25, qmax / 10) + self.qmaxcali = qmax / 2 + return + + inst1 = Str( + "Please install pyFAI and FabIO to use the calibration function (refer to help)." + ) + inst2 = Str( + "(http://github.com/kif/pyFAI, https://forge.epn-campus.eu/projects/azimuthal/files)" + ) + main_View = View( + # Item('calibrationmode', style='custom', label='Calibration mode'), + Item("image", label="Image file"), + Group( + Item("inst1", style="readonly"), + Item("inst2", style="readonly"), + visible_when='missingpyFAI and calibrationmode=="calibrant"', + show_border=True, + show_labels=False, + ), + Group( + Item("dspacefile", label="D-space file"), + Item("pyFAIdir", label="pyFAI dir."), + show_border=True, + visible_when='calibrationmode=="calibrant"', + enabled_when="not missingpyFAI", + label="Please specify the d-space file and the location of pyFAI executable", + ), + HGroup( + Item( + "xpixelsize", + label="Pixel size x (mm)", + visible_when='configmode == "normal"', + ), + Item( + "xpixelsizetem", + label="Pixel size x (A^-1)", + visible_when='configmode == "TEM"', + ), + Item( + "ypixelsize", + label="Pixel size y (mm)", + visible_when='configmode == "normal"', + ), + Item( + "ypixelsizetem", + label="Pixel size y (A^-1)", + visible_when='configmode == "TEM"', + ), + visible_when='calibrationmode=="calibrant"', + enabled_when="not missingpyFAI", + show_border=True, + label="Please specify the size of pixel", + ), + HGroup( + Item("wavelength", label="Wavelength (A)"), + visible_when='calibrationmode=="calibrant"', + enabled_when="not missingpyFAI", + show_border=True, + label="Please specify the wavelength", + ), + HGroup( + Item( + "wavelength", + visible_when='integrationspace == "qspace"', + label="Wavelength(Angstrom)", + ), + Item( + "distance", + label="Distance(mm)", + visible_when='configmode == "normal"', + ), + Item( + "distance", + label="Camera Length(mm)", + visible_when='configmode == "TEM"', + ), + label="Please specify the wavelength and distance between sample and detector:", + show_border=True, + visible_when='calibrationmode=="self"', + ), + HGroup( + VGroup( + Item("xbeamcenter", label="x beamcenter (pixel)"), + Item("rotationd", label="Rotation (degree)"), + ), + VGroup( + Item("ybeamcenter", label="y beamcenter (pixel)"), + Item("tiltd", label="Tilt rotation (degree)"), + ), + show_border=True, + label="Plasee specify the initial value of following parameters:", + visible_when='calibrationmode=="self"', + ), + HGroup( + VGroup( + Item("xdimension", label="x dimension (pixel)"), + Item( + "xpixelsize", + label="Pixel size x (mm)", + visible_when='configmode == "normal"', + ), + Item( + "xpixelsizetem", + label="Pixel size x (A^-1)", + visible_when='configmode == "TEM"', + ), + ), + VGroup( + Item("ydimension", label="y dimension (pixel)"), + Item( + "ypixelsize", + label="Pixel size y (mm)", + visible_when='configmode == "normal"', + ), + Item( + "ypixelsizetem", + label="Pixel size y (A^-1)", + visible_when='configmode == "TEM"', + ), + ), + show_border=True, + label="Plasee specify the dimension of detector and size of pixel:", + visible_when='calibrationmode=="self"', + ), + HGroup( + VGroup( + Item("xywidth", label="(x,y) center searching range, +/-"), + Item("slice", label="Refining using slab along"), + ), + VGroup( + Item("qmincali", label="Qmin in calibration"), + Item("qmaxcali", label="Qmax in calibration"), + ), + show_border=True, + label="Others", + visible_when='calibrationmode=="self"', + ), + title="Calibration", + width=600, + height=450, + resizable=True, + buttons=[OKButton, CancelButton], + handler=CalibrationHandler(), + icon=ImageResource("icon.png"), + ) + + +def findFloat(line): + temp = re.findall("[-+]?\d*\.\d+|[-+]?\d+", line) + return map(float, temp) + + +if __name__ == "__main__": + srxconfig = SrXconfig() + cali = Calibration(srxconfig=srxconfig) + # cali.callPyFAICalibration('ceo2.tif', 'ceo2.d') + # cali.parsePyFAIoutput() + cali.configure_traits(view="main_View") diff --git a/dpx/srxplanargui/datacontainer.py b/src/diffpy/srxplanargui/datacontainer.py similarity index 62% rename from dpx/srxplanargui/datacontainer.py rename to src/diffpy/srxplanargui/datacontainer.py index d5476b9..16692cd 100644 --- a/dpx/srxplanargui/datacontainer.py +++ b/src/diffpy/srxplanargui/datacontainer.py @@ -13,23 +13,46 @@ ############################################################################## import os + import numpy as np +from traits.api import ( + Any, + Array, + Bool, + Button, + CFloat, + CInt, + DelegatesTo, + Dict, + Directory, + Enum, + Event, + File, + Float, + HasTraits, + Instance, + Int, + List, + Property, + Range, + Str, + cached_property, + on_trait_change, + property_depends_on, +) -from traits.api import \ - Dict, List, Enum, Bool, File, Float, Int, Array, Str, Range, Directory, CFloat, CInt, \ - HasTraits, Property, Instance, Event, Button, Any, \ - on_trait_change, DelegatesTo, cached_property, property_depends_on -class DataContainer (HasTraits): +class DataContainer(HasTraits): # The full path and file name of the file: fullname = File # The base file name of the source file: basename = Property # Str - @property_depends_on('fullname') - def _get_basename (self): + @property_depends_on("fullname") + def _get_basename(self): return os.path.basename(self.fullname) -if __name__ == '__main__': + +if __name__ == "__main__": test = DataContainer() diff --git a/dpx/srxplanargui/gitarchive.cfg b/src/diffpy/srxplanargui/gitarchive.cfg similarity index 76% rename from dpx/srxplanargui/gitarchive.cfg rename to src/diffpy/srxplanargui/gitarchive.cfg index 2f8fb70..43b349f 100644 --- a/dpx/srxplanargui/gitarchive.cfg +++ b/src/diffpy/srxplanargui/gitarchive.cfg @@ -2,4 +2,4 @@ commit = $Format:%H$ date = $Format:%ai$ timestamp = $Format:%at$ -refnames = $Format:%D$ \ No newline at end of file +refnames = $Format:%D$ diff --git a/dpx/srxplanargui/help.py b/src/diffpy/srxplanargui/help.py similarity index 55% rename from dpx/srxplanargui/help.py rename to src/diffpy/srxplanargui/help.py index e53f6c2..e0bb9b4 100644 --- a/dpx/srxplanargui/help.py +++ b/src/diffpy/srxplanargui/help.py @@ -11,28 +11,64 @@ # See LICENSE.txt for license information. # ############################################################################## +"""Provide help for SrXgui.""" -'''provide help for SrXgui -''' - -import numpy as np import os import sys -from traits.etsconfig.api import ETSConfig -from traits.api import \ - Dict, List, Enum, Bool, File, Float, Int, Array, Str, Range, Directory, CFloat, CInt, \ - HasTraits, Property, Instance, Event, Button, Any, \ - on_trait_change, DelegatesTo, cached_property, property_depends_on - -from traitsui.api import \ - Item, Group, View, Handler, Controller, spring, Action, \ - HGroup, VGroup, Tabbed, \ - RangeEditor, CheckListEditor, TextEditor, EnumEditor, ButtonEditor, \ - ArrayEditor, TitleEditor, TableEditor, HistoryEditor, InstanceEditor, \ - ImageEditor -from traitsui.menu import ToolBar, OKButton, CancelButton, Menu +import numpy as np from pyface.api import ImageResource +from traits.api import ( + Any, + Array, + Bool, + Button, + CFloat, + CInt, + DelegatesTo, + Dict, + Directory, + Enum, + Event, + File, + Float, + HasTraits, + Instance, + Int, + List, + Property, + Range, + Str, + cached_property, + on_trait_change, + property_depends_on, +) +from traits.etsconfig.api import ETSConfig +from traitsui.api import ( + Action, + ArrayEditor, + ButtonEditor, + CheckListEditor, + Controller, + EnumEditor, + Group, + Handler, + HGroup, + HistoryEditor, + ImageEditor, + InstanceEditor, + Item, + RangeEditor, + Tabbed, + TableEditor, + TextEditor, + TitleEditor, + VGroup, + View, + spring, +) +from traitsui.menu import CancelButton, Menu, OKButton, ToolBar + class HelpHandler(Handler): @@ -51,8 +87,8 @@ def _cpReftext(self, info): class SrXguiHelp(HasTraits): - if sys.platform.startswith('win'): - if ETSConfig.toolkit == 'qt4': + if sys.platform.startswith("win"): + if ETSConfig.toolkit == "qt4": hheight = 510 hwidth = 960 else: @@ -66,67 +102,69 @@ class SrXguiHelp(HasTraits): # quick start ####################### - imgs = [ImageResource('%02d.png' % i) for i in range(1, 23)] + imgs = [ImageResource("%02d.png" % i) for i in range(1, 23)] qslen = Int(len(imgs) - 1) - next_action = \ - Action(name='Next', - action='_qsnext', - enabled_when='object.qsindex 2: mask = points_in_polygon(self.pts, points) mask = mask.reshape(self.staticmask.shape) if remove: - self.staticmask = np.logical_and(self.staticmask, np.logical_not(mask)) + self.staticmask = np.logical_and( + self.staticmask, np.logical_not(mask) + ) else: self.staticmask = np.logical_or(self.staticmask, mask) self.refreshMask(staticmask=self.staticmask) return def addPointMask(self, ndx, remove=None): - ''' + """ :param ndx: (x,y) float - ''' + """ x, y = ndx r = self.pts - np.array((x, y)) - r = np.sum(r ** 2, axis=1) + r = np.sum(r**2, axis=1) mask = r < ((self.pointmaskradius + 1) ** 2) mask = mask.reshape(self.staticmask.shape) if remove: - self.staticmask = np.logical_and(self.staticmask, np.logical_not(mask)) + self.staticmask = np.logical_and( + self.staticmask, np.logical_not(mask) + ) else: self.staticmask = np.logical_or(self.staticmask, mask) self.refreshMask(self.staticmask) @@ -187,16 +265,22 @@ def clearMask(self): self.staticmask = self.staticmask * 0 self.refreshMask(self.staticmask) return - + def invertMask(self): self.staticmask = np.logical_not(self.staticmask) self.refreshMask(self.staticmask) return - + def refreshMask(self, staticmask=None, draw=True): - self.staticmask = self.srx.mask.staticMask() if staticmask == None else staticmask - self.dynamicmask = self.srx.mask.dynamicMask(self.imageorg, dymask=self.staticmask) - self.dynamicmask = np.logical_or(self.dynamicmask, self.srx.mask.edgeMask()) + self.staticmask = ( + self.srx.mask.staticMask() if staticmask == None else staticmask + ) + self.dynamicmask = self.srx.mask.dynamicMask( + self.imageorg, dymask=self.staticmask + ) + self.dynamicmask = np.logical_or( + self.dynamicmask, self.srx.mask.edgeMask() + ) self.mask = np.logical_or(self.staticmask, self.dynamicmask) if draw: self.refreshImage() @@ -218,11 +302,10 @@ def maskbelow(self): return def _appendTools(self): - ''' - append xy position, zoom, pan tools to plot + """Append xy position, zoom, pan tools to plot. :param plot: the plot object to append on - ''' + """ plot = self.plot img_plot = self.img_plot @@ -234,8 +317,12 @@ def _appendTools(self): # self.lstool.imageplot = self img_plot.tools.append(self.xyseltool) - overlay = ImageInspectorOverlay(component=img_plot, image_inspector=self.xyseltool, - bgcolor="white", border_visible=True) + overlay = ImageInspectorOverlay( + component=img_plot, + image_inspector=self.xyseltool, + bgcolor="white", + border_visible=True, + ) img_plot.overlays.append(overlay) plot.tools.append(self.pan) @@ -243,21 +330,17 @@ def _appendTools(self): return def _enableMaskEditing(self): - ''' - enable mask tool and disable pan tool - ''' + """Enable mask tool and disable pan tool.""" self.maskediting = True for i in range(self.plot.tools.count(self.pan)): self.plot.tools.remove(self.pan) self.plot.overlays.append(self.lstool) self.titlebak = self.plot.title - self.plot.title = 'Click: add a vertex; +Click: remove a vertex; \n : finish the selection' + self.plot.title = "Click: add a vertex; +Click: remove a vertex; \n : finish the selection" return def _disableMaskEditing(self): - ''' - disable mask tool and enable pan tool - ''' + """Disable mask tool and enable pan tool.""" self.plot.overlays.remove(self.lstool) self.plot.tools.append(self.pan) self.plot.title = self.titlebak @@ -269,7 +352,9 @@ def _enablePointMaskEditing(self): for i in range(self.plot.tools.count(self.pan)): self.plot.tools.remove(self.pan) self.titlebak = self.plot.title - self.plot.title = 'Click: add a point; : exit the point selection' + self.plot.title = ( + "Click: add a point; : exit the point selection" + ) return def _disablePointMaskEditing(self): @@ -277,11 +362,10 @@ def _disablePointMaskEditing(self): self.plot.title = self.titlebak self.maskediting = False return - + def refreshImage(self, mask=None, draw=True): - ''' - recalculate the image using self.mask or mask and refresh display - ''' + """Recalculate the image using self.mask or mask and refresh + display.""" mask = self.mask if mask == None else mask image = self.applyScale() image = image * np.logical_not(mask) + image.max() * mask @@ -289,22 +373,20 @@ def refreshImage(self, mask=None, draw=True): if draw: self.plot.invalidate_draw() return - - scalemode = Enum('linear', ['linear', 'log'], desc='Scale the image') - scalepowder = Float(0.5, desc='gamma value to control the contrast') - + + scalemode = Enum("linear", ["linear", "log"], desc="Scale the image") + scalepowder = Float(0.5, desc="gamma value to control the contrast") + def applyScale(self, image=None): - ''' - apply the scale to increase/decrease contrast - ''' - if self.scalemode == 'linear': + """Apply the scale to increase/decrease contrast.""" + if self.scalemode == "linear": if image == None: image = self.imageorg intmax = self.imageorgmax else: image = image intmax = image.max() - elif self.scalemode == 'log': + elif self.scalemode == "log": if image == None: image = self.imageorglog intmax = self.imageorglogmax @@ -315,222 +397,258 @@ def applyScale(self, image=None): else: image = image intmax = image.max() - + image = intmax * ((image / intmax) ** self.scalepowder) return image - + splb = Float(0.0) - spub = Float(1.0) + spub = Float(1.0) + def _scalemode_changed(self): - if self.scalemode == 'linear': + if self.scalemode == "linear": self.scalepowder = 0.5 self.splb = 0.0 self.spub = 1.0 - elif self.scalemode == 'log': + elif self.scalemode == "log": self.scalepowder = 1.0 self.splb = 0.0 self.spub = 4.0 self.refreshImage() return - + def _scalepowder_changed(self, old, new): if np.round(old, 1) != np.round(new, 1): self.refreshImage() return def _add_notifications(self): - self.on_trait_change(self.refreshMaskFile, 'srxconfig.maskfile') + self.on_trait_change(self.refreshMaskFile, "srxconfig.maskfile") return def _del_notifications(self): - self.on_trait_change(self.refreshMaskFile, 'srxconfig.maskfile', remove=True) - return - - addpolygon_bb = Button('Add polygon mask') - removepolygon_bb = Button('Remove polygon mask') - addpoint_bb = Button('Add point mask') - clearmask_bb = Button('Clear mask', desc='Clear mask') - invertmask_bb = Button('Invert mask', desc='Invert mask') - advancedmask_bb = Button('Dynamic mask', desc='The dynamic mask is dynamically generated for each image.') - maskabove_bb = Button('Mask intensity above') - maskbelow_bb = Button('Mask intensity below') - loadmaskfile_bb = Button('Load mask') - savemaskfile_bb = Button('Save mask') + self.on_trait_change( + self.refreshMaskFile, "srxconfig.maskfile", remove=True + ) + return + + addpolygon_bb = Button("Add polygon mask") + removepolygon_bb = Button("Remove polygon mask") + addpoint_bb = Button("Add point mask") + clearmask_bb = Button("Clear mask", desc="Clear mask") + invertmask_bb = Button("Invert mask", desc="Invert mask") + advancedmask_bb = Button( + "Dynamic mask", + desc="The dynamic mask is dynamically generated for each image.", + ) + maskabove_bb = Button("Mask intensity above") + maskbelow_bb = Button("Mask intensity below") + loadmaskfile_bb = Button("Load mask") + savemaskfile_bb = Button("Save mask") def _addpolygon_bb_fired(self): self.removepolygonmask = False self._enableMaskEditing() return + def _removepolygon_bb_fired(self): self.removepolygonmask = True self._enableMaskEditing() return + def _addpoint_bb_fired(self): self._enablePointMaskEditing() self.xyseltool.enablemaskselect = True return + def _clearmask_bb_fired(self): self.clearMask() return + def _invertmask_bb_fired(self): self.invertMask() return + def _advancedmask_bb_fired(self): - self.edit_traits('advancedmask_view') + self.edit_traits("advancedmask_view") # if not hasattr(self, 'advhint'): # self.advhint = AdvHint() # self.advhint.edit_traits('advhint_view') return + def _maskabove_bb_fired(self): self.maskabove() return + def _maskbelow_bb_fired(self): self.maskbelow() return + def _loadmaskfile_bb_fired(self): - self.edit_traits('loadmaskfile_view') + self.edit_traits("loadmaskfile_view") return + def _savemaskfile_bb_fired(self): - if self.maskfile == '': - self.maskfile = os.path.join(self.srxconfig.savedirectory, 'mask.npy') + if self.maskfile == "": + self.maskfile = os.path.join( + self.srxconfig.savedirectory, "mask.npy" + ) else: - self.maskfile = os.path.splitext(self.maskfile)[0] + '.npy' - self.edit_traits('savemaskfile_view') + self.maskfile = os.path.splitext(self.maskfile)[0] + ".npy" + self.edit_traits("savemaskfile_view") return def __init__(self, **kwargs): - ''' - init the object and create notification - ''' + """Init the object and create notification.""" HasTraits.__init__(self, **kwargs) self.createPlot() # self._loadMaskPar() self._add_notifications() return - hinttext = Str('Zoom: ; Reset: ; Pan: ; Toggle XY coordinates:

') + hinttext = Str( + "Zoom: ; Reset: ; Pan: ; Toggle XY coordinates:

" + ) traits_view = View( - Group( - Item('plot', editor=ComponentEditor(size=(550, 550)), - show_label=False), - HGroup( - spring, - Item('scalemode', label='Scale mode'), - Item('scalepowder', label='Gamma', - editor=RangeEditor(auto_set=False, low_name='splb', high_name='spub', format='%.1f')), - spring, - ), - VGroup( - HGroup( - Item('addpolygon_bb', enabled_when='not maskediting'), - Item('removepolygon_bb', enabled_when='not maskediting'), - spring, - Item('maskabove_bb', enabled_when='not maskediting'), - Item('maskaboveint', enabled_when='not maskediting'), - show_labels=False, - ), - HGroup( - Item('addpoint_bb', enabled_when='not maskediting'), - Item('pointmaskradius', label='Size:', show_label=True), - spring, - Item('maskbelow_bb', enabled_when='not maskediting'), - Item('maskbelowint', enabled_when='not maskediting'), - show_labels=False, - ), - HGroup( - Item('clearmask_bb', enabled_when='not maskediting'), - Item('invertmask_bb', enabled_when='not maskediting'), - Item('advancedmask_bb', enabled_when='not maskediting'), - spring, - Item('loadmaskfile_bb'), - Item('savemaskfile_bb'), - show_labels=False, - ), - show_labels=False, - show_border=True, - label='Mask' - ), - orientation="vertical"), - resizable=True, - title='2D image', - statusbar=['hinttext'], - width=600, - height=700, - icon=ImageResource('icon.png'), - ) - - savemaskfile_action = \ - Action(name='OK ', - action='_save') - loadmaskfile_action = \ - Action(name='OK ', - action='_load') - applydymask_action = \ - Action(name='Apply ', - action='_applyDymask') - - savemaskfile_view = \ - View(Item('maskfile'), - buttons=[savemaskfile_action, CancelButton], - title='Save mask file', - width=500, - resizable=True, - handler=SaveLoadMaskHandler(), - icon=ImageResource('icon.png'), - ) - - loadmaskfile_view = \ - View(Item('maskfile'), - buttons=[loadmaskfile_action, CancelButton], - title='Load mask file', - width=500, - resizable=True, - handler=SaveLoadMaskHandler(), - icon=ImageResource('icon.png'), - ) - - - advancedmask_view = \ - View( - Group( - VGroup( - Item('cropedges', label='Mask edges', editor=ArrayEditor(width=-50)), - label='Edge mask', - show_border=True, - ), - VGroup( - Item('darkpixelmask', label='Enable'), - Item('darkpixelr', label='Threshold', enabled_when='darkpixelmask'), - label='Dark pixel mask', - show_border=True, - ), - VGroup( - Item('brightpixelmask', label='Enable'), - Item('brightpixelsize', label='Testing size', enabled_when='brightpixelmask'), - Item('brightpixelr', label='Threshold', enabled_when='brightpixelmask'), - label='Bright pixel mask', - show_border=True, - ), - VGroup( - Item('avgmask', label='Enable'), - Item('avgmaskhigh', label='High', enabled_when='avgmask'), - Item('avgmasklow', label='Low', enabled_when='avgmask'), - label='Average mask', - show_border=True, + Group( + Item( + "plot", + editor=ComponentEditor(size=(550, 550)), + show_label=False, + ), + HGroup( + spring, + Item("scalemode", label="Scale mode"), + Item( + "scalepowder", + label="Gamma", + editor=RangeEditor( + auto_set=False, + low_name="splb", + high_name="spub", + format="%.1f", ), ), + spring, + ), + VGroup( + HGroup( + Item("addpolygon_bb", enabled_when="not maskediting"), + Item("removepolygon_bb", enabled_when="not maskediting"), + spring, + Item("maskabove_bb", enabled_when="not maskediting"), + Item("maskaboveint", enabled_when="not maskediting"), + show_labels=False, + ), + HGroup( + Item("addpoint_bb", enabled_when="not maskediting"), + Item("pointmaskradius", label="Size:", show_label=True), + spring, + Item("maskbelow_bb", enabled_when="not maskediting"), + Item("maskbelowint", enabled_when="not maskediting"), + show_labels=False, + ), + HGroup( + Item("clearmask_bb", enabled_when="not maskediting"), + Item("invertmask_bb", enabled_when="not maskediting"), + Item("advancedmask_bb", enabled_when="not maskediting"), + spring, + Item("loadmaskfile_bb"), + Item("savemaskfile_bb"), + show_labels=False, + ), + show_labels=False, + show_border=True, + label="Mask", + ), + orientation="vertical", + ), + resizable=True, + title="2D image", + statusbar=["hinttext"], + width=600, + height=700, + icon=ImageResource("icon.png"), + ) + + savemaskfile_action = Action(name="OK ", action="_save") + loadmaskfile_action = Action(name="OK ", action="_load") + applydymask_action = Action(name="Apply ", action="_applyDymask") + + savemaskfile_view = View( + Item("maskfile"), + buttons=[savemaskfile_action, CancelButton], + title="Save mask file", + width=500, + resizable=True, + handler=SaveLoadMaskHandler(), + icon=ImageResource("icon.png"), + ) + + loadmaskfile_view = View( + Item("maskfile"), + buttons=[loadmaskfile_action, CancelButton], + title="Load mask file", + width=500, + resizable=True, + handler=SaveLoadMaskHandler(), + icon=ImageResource("icon.png"), + ) + + advancedmask_view = View( + Group( + VGroup( + Item( + "cropedges", + label="Mask edges", + editor=ArrayEditor(width=-50), + ), + label="Edge mask", + show_border=True, + ), + VGroup( + Item("darkpixelmask", label="Enable"), + Item( + "darkpixelr", + label="Threshold", + enabled_when="darkpixelmask", + ), + label="Dark pixel mask", + show_border=True, + ), + VGroup( + Item("brightpixelmask", label="Enable"), + Item( + "brightpixelsize", + label="Testing size", + enabled_when="brightpixelmask", + ), + Item( + "brightpixelr", + label="Threshold", + enabled_when="brightpixelmask", + ), + label="Bright pixel mask", + show_border=True, + ), + VGroup( + Item("avgmask", label="Enable"), + Item("avgmaskhigh", label="High", enabled_when="avgmask"), + Item("avgmasklow", label="Low", enabled_when="avgmask"), + label="Average mask", + show_border=True, + ), + ), + title="Dynamic mask", + width=320, + handler=AdvMaskHandler(), + resizable=True, + buttons=[applydymask_action, OKButton, CancelButton], + icon=ImageResource("icon.png"), + ) - title='Dynamic mask', - width=320, - handler=AdvMaskHandler(), - resizable=True, - buttons=[applydymask_action, OKButton, CancelButton], - icon=ImageResource('icon.png'), - ) class MasklineDrawer(LineSegmentTool): - """ - """ + """""" imageplot = Any @@ -545,9 +663,10 @@ def __init__(self, *args, **kwargs): self.line.vertex_color = "white" return + class MaskPointInspector(ImageInspectorTool): - exitmask_key = KeySpec('Enter') + exitmask_key = KeySpec("Enter") imageplot = Any enablemaskselect = Bool(False) @@ -566,28 +685,28 @@ def normal_left_down(self, event): self.imageplot.addPointMask(ndx) return + class AdvHint(HasTraits): advhinttext = str( -'''Notes: Advanced Masks are generated during the integration and refreshed for each image. + """Notes: Advanced Masks are generated during the integration and refreshed for each image. You can preview the masks here or apply the current masks to the static mask permanently. Edge mask: mask the pixels around the image edge. (left, right, top, bottom) Dark pixel mask: mask the pixels too dark compared to their local environment Bright pixel mask: mask the pixels too bright compared to their local environment Average mask: Mask the pixels too bright or too dark compared to the average intensity - at the similar diffraction angle. Currect calibration information is required.''') - - advhint_view = \ - View( - Group( - Item('advhinttext', style='readonly', show_label=False), - show_border=True, - ), - - title='Advanced mask hints', - width=640, - resizable=False, - buttons=[OKButton], - icon=ImageResource('icon.png'), - ) + at the similar diffraction angle. Currect calibration information is required.""" + ) + + advhint_view = View( + Group( + Item("advhinttext", style="readonly", show_label=False), + show_border=True, + ), + title="Advanced mask hints", + width=640, + resizable=False, + buttons=[OKButton], + icon=ImageResource("icon.png"), + ) diff --git a/dpx/srxplanargui/images/01.png b/src/diffpy/srxplanargui/images/01.png similarity index 100% rename from dpx/srxplanargui/images/01.png rename to src/diffpy/srxplanargui/images/01.png diff --git a/dpx/srxplanargui/images/02.png b/src/diffpy/srxplanargui/images/02.png similarity index 100% rename from dpx/srxplanargui/images/02.png rename to src/diffpy/srxplanargui/images/02.png diff --git a/dpx/srxplanargui/images/03.png b/src/diffpy/srxplanargui/images/03.png similarity index 100% rename from dpx/srxplanargui/images/03.png rename to src/diffpy/srxplanargui/images/03.png diff --git a/dpx/srxplanargui/images/04.png b/src/diffpy/srxplanargui/images/04.png similarity index 100% rename from dpx/srxplanargui/images/04.png rename to src/diffpy/srxplanargui/images/04.png diff --git a/dpx/srxplanargui/images/05.png b/src/diffpy/srxplanargui/images/05.png similarity index 100% rename from dpx/srxplanargui/images/05.png rename to src/diffpy/srxplanargui/images/05.png diff --git a/dpx/srxplanargui/images/06.png b/src/diffpy/srxplanargui/images/06.png similarity index 100% rename from dpx/srxplanargui/images/06.png rename to src/diffpy/srxplanargui/images/06.png diff --git a/dpx/srxplanargui/images/07.png b/src/diffpy/srxplanargui/images/07.png similarity index 100% rename from dpx/srxplanargui/images/07.png rename to src/diffpy/srxplanargui/images/07.png diff --git a/dpx/srxplanargui/images/08.png b/src/diffpy/srxplanargui/images/08.png similarity index 100% rename from dpx/srxplanargui/images/08.png rename to src/diffpy/srxplanargui/images/08.png diff --git a/dpx/srxplanargui/images/09.png b/src/diffpy/srxplanargui/images/09.png similarity index 100% rename from dpx/srxplanargui/images/09.png rename to src/diffpy/srxplanargui/images/09.png diff --git a/dpx/srxplanargui/images/10.png b/src/diffpy/srxplanargui/images/10.png similarity index 100% rename from dpx/srxplanargui/images/10.png rename to src/diffpy/srxplanargui/images/10.png diff --git a/dpx/srxplanargui/images/11.png b/src/diffpy/srxplanargui/images/11.png similarity index 100% rename from dpx/srxplanargui/images/11.png rename to src/diffpy/srxplanargui/images/11.png diff --git a/dpx/srxplanargui/images/12.png b/src/diffpy/srxplanargui/images/12.png similarity index 100% rename from dpx/srxplanargui/images/12.png rename to src/diffpy/srxplanargui/images/12.png diff --git a/dpx/srxplanargui/images/13.png b/src/diffpy/srxplanargui/images/13.png similarity index 100% rename from dpx/srxplanargui/images/13.png rename to src/diffpy/srxplanargui/images/13.png diff --git a/dpx/srxplanargui/images/14.png b/src/diffpy/srxplanargui/images/14.png similarity index 100% rename from dpx/srxplanargui/images/14.png rename to src/diffpy/srxplanargui/images/14.png diff --git a/dpx/srxplanargui/images/15.png b/src/diffpy/srxplanargui/images/15.png similarity index 100% rename from dpx/srxplanargui/images/15.png rename to src/diffpy/srxplanargui/images/15.png diff --git a/dpx/srxplanargui/images/16.png b/src/diffpy/srxplanargui/images/16.png similarity index 100% rename from dpx/srxplanargui/images/16.png rename to src/diffpy/srxplanargui/images/16.png diff --git a/dpx/srxplanargui/images/17.png b/src/diffpy/srxplanargui/images/17.png similarity index 100% rename from dpx/srxplanargui/images/17.png rename to src/diffpy/srxplanargui/images/17.png diff --git a/dpx/srxplanargui/images/18.png b/src/diffpy/srxplanargui/images/18.png similarity index 100% rename from dpx/srxplanargui/images/18.png rename to src/diffpy/srxplanargui/images/18.png diff --git a/dpx/srxplanargui/images/19.png b/src/diffpy/srxplanargui/images/19.png similarity index 100% rename from dpx/srxplanargui/images/19.png rename to src/diffpy/srxplanargui/images/19.png diff --git a/dpx/srxplanargui/images/20.png b/src/diffpy/srxplanargui/images/20.png similarity index 100% rename from dpx/srxplanargui/images/20.png rename to src/diffpy/srxplanargui/images/20.png diff --git a/dpx/srxplanargui/images/21.png b/src/diffpy/srxplanargui/images/21.png similarity index 100% rename from dpx/srxplanargui/images/21.png rename to src/diffpy/srxplanargui/images/21.png diff --git a/dpx/srxplanargui/images/22.png b/src/diffpy/srxplanargui/images/22.png similarity index 100% rename from dpx/srxplanargui/images/22.png rename to src/diffpy/srxplanargui/images/22.png diff --git a/dpx/srxplanargui/images/gitarchive.cfg b/src/diffpy/srxplanargui/images/gitarchive.cfg similarity index 76% rename from dpx/srxplanargui/images/gitarchive.cfg rename to src/diffpy/srxplanargui/images/gitarchive.cfg index 2f8fb70..43b349f 100644 --- a/dpx/srxplanargui/images/gitarchive.cfg +++ b/src/diffpy/srxplanargui/images/gitarchive.cfg @@ -2,4 +2,4 @@ commit = $Format:%H$ date = $Format:%ai$ timestamp = $Format:%at$ -refnames = $Format:%D$ \ No newline at end of file +refnames = $Format:%D$ diff --git a/dpx/srxplanargui/images/icon.ico b/src/diffpy/srxplanargui/images/icon.ico similarity index 100% rename from dpx/srxplanargui/images/icon.ico rename to src/diffpy/srxplanargui/images/icon.ico diff --git a/dpx/srxplanargui/images/icon.png b/src/diffpy/srxplanargui/images/icon.png similarity index 100% rename from dpx/srxplanargui/images/icon.png rename to src/diffpy/srxplanargui/images/icon.png diff --git a/src/diffpy/srxplanargui/live.py b/src/diffpy/srxplanargui/live.py new file mode 100644 index 0000000..a3b84b3 --- /dev/null +++ b/src/diffpy/srxplanargui/live.py @@ -0,0 +1,227 @@ +#!/usr/bin/env python +############################################################################## +# +# dpx.pdfgetxgui by Simon J. L. Billinge group +# (c) 2012 Trustees of the Columbia University +# in the City of New York. All rights reserved. +# +# File coded by: Xiaohao Yang +# +# See AUTHORS.txt for a list of people who contributed. +# See LICENSE.txt for license information. +# +############################################################################## +"""Provide UI for srxplanar.""" + +import os +import re +import sys +import threading +import time +from functools import partial + +import numpy as np +from traits.etsconfig.api import ETSConfig + +ETSConfig.toolkit = "qt4" + +from diffpy.srxconfutils.tools import checkFileVal +from diffpy.srxplanar.srxplanar import SrXplanar +from pyface.api import GUI, ImageResource, SplashScreen +from traits.api import ( + Any, + Array, + Bool, + Button, + CFloat, + CInt, + DelegatesTo, + Dict, + Directory, + Enum, + Event, + File, + Float, + HasTraits, + Instance, + Int, + List, + Property, + Range, + Str, + cached_property, + on_trait_change, + property_depends_on, +) +from traitsui.api import ( + Action, + ArrayEditor, + ButtonEditor, + CheckListEditor, + Controller, + EnumEditor, + Group, + Handler, + HGroup, + HistoryEditor, + ImageEditor, + InstanceEditor, + Item, + RangeEditor, + Tabbed, + TableEditor, + TextEditor, + TitleEditor, + VGroup, + View, + spring, +) +from traitsui.menu import ( + CancelButton, + Menu, + MenuBar, + OKButton, + OKCancelButtons, + ToolBar, +) + +from diffpy.srxplanargui.calibration import Calibration +from diffpy.srxplanargui.help import SrXguiHelp +from diffpy.srxplanargui.selectfiles import AddFiles +from diffpy.srxplanargui.srxconfig import SrXconfig +from diffpy.srxplanargui.srxgui import LoadHandler, SaveHandler, SrXgui, SrXguiHandler + + +class SrXguiLive(SrXgui): + + getxgui = Any + + def __init__(self, configfile=None, args=None, **kwargs): + + # init the object, createt the notifications + + self.splash = SplashScreen( + image=ImageResource("01.png"), show_log_messages=False + ) + self.splash.open() + + super(SrXgui, self).__init__(**kwargs) + configfile = self.detectConfigfile(configfile) + if not os.path.exists(configfile): + configfile = self.detectConfigfile("default") + self.configfile = configfile + + if not kwargs.has_key("srxconfig"): + self.srxconfig = SrXconfig( + filename=configfile, args=args, **kwargs + ) + + self.addfiles = AddFiles(srxconfig=self.srxconfig) + self.srx = SrXplanar(self.srxconfig) + self.addfiles.srx = self.srx + self.help = SrXguiHelp() + self.calibration = Calibration(srx=self.srx, srxconfig=self.srxconfig) + self.splash.close() + return + + @on_trait_change("srxconfig.savedirectory") + def _changedir(self): + newdir = self.srxconfig.savedirectory + if os.path.exists(newdir): + self.getxgui.getxconfig.inputdir = os.path.abspath(newdir) + self.getxgui.getxconfig.savedir = os.path.abspath(newdir) + else: + self.getxgui.getxconfig.inputdir = os.path.abspath(os.path.curdir) + self.getxgui.getxconfig.savedir = os.path.abspath(os.path.curdir) + return + + def processSelected(self, summation=False): + if self.addfiles.selected: + self.srx.updateConfig() + filelist = [f.fullname for f in self.addfiles.selected] + self.srx.prepareCalculation(filelist) + rvlist = self.srx.integrateFilelist(filelist, summation=summation) + newchifilelist = [rv["filename"] for rv in rvlist] + GUI.invoke_later(self.addNewImagesToGetXgui, newchifilelist) + return + + def addNewImagesToGetXgui(self, filelist): + """Add new images to getxgui, if images are already there, + refresh them. + + :param filelist: list of full path of new images + """ + self.addfiles.refreshdatalist = True + newdatacontainers = self.getxgui.selectfiles.addFiles(filelist) + self.getxgui.createNewPlot(newdatacontainers) + return + + helpbutton_action = Action(name="Help ", action="_helpView") + saveconfig_action = Action( + name="Save Config", + action="_saveconfigView", + enabled_when="not capturing", + ) + loadconfig_action = Action( + name="Load Config", + action="_loadconfigView", + enabled_when="not capturing", + ) + + traits_view = View( + HGroup( + Item( + "addfiles", + editor=InstanceEditor(view="traits_view"), + style="custom", + label="Files", + width=0.4, + ), + VGroup( + Group( + Item( + "srxconfig", + editor=InstanceEditor(view="main_view"), + style="custom", + label="Basic", + show_label=False, + ), + springy=True, + ), + HGroup( + spring, + Item("selfcalibratebb", enabled_when="not capturing"), + Item("integratbb", enabled_when="not capturing"), + spring, + show_labels=False, + ), + ), + layout="split", + springy=True, + dock="tab", + show_labels=False, + ), + resizable=True, + title="SrXgui", + width=700, + height=650, + kind="live", + icon=ImageResource("icon.png"), + handler=SrXguiHandler(), + buttons=[ + helpbutton_action, + saveconfig_action, + loadconfig_action, + OKButton, + ], + ) + + +def main(): + gui = SrXguiLive() + gui.configure_traits(view="traits_view") + return + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/dpx/srxplanargui/selectfiles.py b/src/diffpy/srxplanargui/selectfiles.py similarity index 58% rename from dpx/srxplanargui/selectfiles.py rename to src/diffpy/srxplanargui/selectfiles.py index bb63137..2ef6304 100644 --- a/dpx/srxplanargui/selectfiles.py +++ b/src/diffpy/srxplanargui/selectfiles.py @@ -12,53 +12,90 @@ # ############################################################################## -import os -import sys import fnmatch import functools +import os import re +import sys from collections import OrderedDict -from traits.etsconfig.api import ETSConfig +from pyface.api import ImageResource +from traits.api import ( + Any, + Array, + Bool, + Button, + CFloat, + CInt, + DelegatesTo, + Dict, + Directory, + Enum, + Event, + File, + Float, + HasTraits, + Instance, + Int, + List, + Property, + Range, + Str, + cached_property, + on_trait_change, + property_depends_on, +) +from traits.etsconfig.api import ETSConfig +from traitsui.api import ( + Action, + ArrayEditor, + ButtonEditor, + CheckListEditor, + EnumEditor, + Group, + Handler, + HGroup, + HistoryEditor, + Item, + RangeEditor, + Tabbed, + TableEditor, + TextEditor, + TitleEditor, + VGroup, + View, + spring, +) +from traitsui.menu import CancelButton, Menu, OKButton, OKCancelButtons, ToolBar from traitsui.qt4.table_editor import TableEditor as TableEditorBE -from traits.api import \ - Dict, List, Enum, Bool, File, Float, Int, Array, Str, Range, Directory, CFloat, CInt, \ - HasTraits, Property, Instance, Event, Button, Any, \ - on_trait_change, DelegatesTo, cached_property, property_depends_on - -from traitsui.api import \ - Item, Group, View, Handler, spring, Action, \ - HGroup, VGroup, Tabbed, \ - RangeEditor, CheckListEditor, TextEditor, EnumEditor, ButtonEditor, \ - ArrayEditor, TitleEditor, TableEditor, HistoryEditor -from traitsui.menu import ToolBar, OKButton, CancelButton, Menu, OKCancelButtons from traitsui.table_column import ObjectColumn -from pyface.api import ImageResource try: from diffpy.pdfgetx.functs import sortKeyNumericString except: from diffpy.pdfgete.functs import sortKeyNumericString -from dpx.srxplanargui.datacontainer import DataContainer -from dpx.srxplanargui.srxconfig import SrXconfig -from dpx.srxplanargui.imageplot import ImagePlot + from diffpy.srxplanar.loadimage import openImage, saveImage -#-- The Live Search table editor definition ------------------------------ +from diffpy.srxplanargui.datacontainer import DataContainer +from diffpy.srxplanargui.imageplot import ImagePlot +from diffpy.srxplanargui.srxconfig import SrXconfig + +# -- The Live Search table editor definition ------------------------------ class AddFilesHandler(Handler): def object_selectallbb_changed(self, info): - ''' - select all files - ''' + """Select all files.""" # FIXME try: editor = [ - aa for aa in info.ui._editors if isinstance(aa, TableEditorBE)][0] - info.object.selected = [info.object.datafiles[i] - for i in editor.filtered_indices] + aa for aa in info.ui._editors if isinstance(aa, TableEditorBE) + ][0] + info.object.selected = [ + info.object.datafiles[i] for i in editor.filtered_indices + ] editor.refresh() except: pass @@ -87,10 +124,11 @@ class AddFiles(HasTraits): def _inputdir_default(self): return self.srxconfig.opendirectory + # Should sub directories be included in the search: recursive = Bool(False) # The file types to include in the search: - filetype = Enum('tif', 'npy', 'all') + filetype = Enum("tif", "npy", "all") # The current search string: search = Str # Is the search case sensitive? @@ -105,28 +143,27 @@ def _inputdir_default(self): # Summary of current number of files: summary = Property # Str # some meta data - _filetypedict = {'tif': ['.tif', '.tiff', '.tif.bz2'], - 'npy': ['.npy'], - 'all': 'all', - } + _filetypedict = { + "tif": [".tif", ".tiff", ".tif.bz2"], + "npy": [".npy"], + "all": "all", + } - #-- Property Implementations --------------------------------------------- + # -- Property Implementations --------------------------------------------- - @property_depends_on('search, casesensitive') + @property_depends_on("search, casesensitive") def _get_filter(self): - '''get filename filter - ''' + """Get filename filter.""" return _createFileNameFilter(self.search, self.casesensitive) refreshdatalist = Event - @property_depends_on('inputdir, recursive, filetype, refreshdatalist') + @property_depends_on("inputdir, recursive, filetype, refreshdatalist") def _get_datafiles(self): - ''' - create a datacontainer list, all files under inputdir is filtered using filetype - ''' + """Create a datacontainer list, all files under inputdir is + filtered using filetype.""" inputdir = self.inputdir - if inputdir == '': + if inputdir == "": inputdir = os.getcwd() if not os.path.exists(inputdir): self.srxconfig.opendirectory = os.getcwd() @@ -137,34 +174,37 @@ def _get_datafiles(self): rv = [] for dirpath, dirnames, filenames in os.walk(inputdir): for filename in filenames: - if (os.path.splitext(filename)[1] in filetypes)or (filetypes == 'all'): + if (os.path.splitext(filename)[1] in filetypes) or ( + filetypes == "all" + ): rv.append(os.path.join(dirpath, filename)) else: - rv = [os.path.join(inputdir, filename) - for filename in os.listdir(inputdir) - if (os.path.splitext(filename)[1] in filetypes) or (filetypes == 'all')] + rv = [ + os.path.join(inputdir, filename) + for filename in os.listdir(inputdir) + if (os.path.splitext(filename)[1] in filetypes) + or (filetypes == "all") + ] rv.sort(key=sortKeyNumericString) rvlist = [DataContainer(fullname=fn) for fn in rv] return rvlist - @property_depends_on('datafiles, search, casesensitive, selected') + @property_depends_on("datafiles, search, casesensitive, selected") def _get_summary(self): - ''' - get summary of file - ''' + """Get summary of file.""" if self.selected and self.datafiles: - rv = '%d files selected in a total of %d files.' % ( - len(self.selected), len(self.datafiles)) + rv = "%d files selected in a total of %d files." % ( + len(self.selected), + len(self.datafiles), + ) else: - rv = '0 files selected in a total of 0 files.' + rv = "0 files selected in a total of 0 files." return rv - @on_trait_change('srxconfig.opendirectory') + @on_trait_change("srxconfig.opendirectory") def _changeInputdir(self): - ''' - change inputdir of getxconfig - ''' + """Change inputdir of getxconfig.""" self.inputdir = self.srxconfig.opendirectory return @@ -176,7 +216,8 @@ def _plotbb_fired(self): if imagefile != None: if os.path.exists(imagefile): imageplot = ImagePlot( - imagefile=imagefile, srx=self.srx, srxconfig=self.srxconfig) + imagefile=imagefile, srx=self.srx, srxconfig=self.srxconfig + ) # imageplot.createPlot() imageplot.edit_traits() return @@ -188,9 +229,10 @@ def _refreshbb_fired(self): sumname = Str def _sumbb_fired(self): - self.sumname = os.path.splitext( - self.selected[0].fullname)[0] + '_sum.tif' - self.edit_traits(view='saveimage_view') + self.sumname = ( + os.path.splitext(self.selected[0].fullname)[0] + "_sum.tif" + ) + self.edit_traits(view="saveimage_view") return def _sumImgs(self): @@ -206,67 +248,73 @@ def _sumImgs(self): saveimage_view = View( Group( - Item('sumname', springy=True, label='File name'), + Item("sumname", springy=True, label="File name"), ), buttons=[OKButton, CancelButton], - title='Save image', + title="Save image", width=500, # height = 400, resizable=True, handler=SaveImageHandler(), - icon=ImageResource('icon.png'), + icon=ImageResource("icon.png"), ) - #-- Traits UI Views ------------------------------------------------------ + # -- Traits UI Views ------------------------------------------------------ tableeditor = TableEditor( columns=[ - ObjectColumn(name='basename', - label='Name', - # width=0.70, - editable=False, - ), + ObjectColumn( + name="basename", + label="Name", + # width=0.70, + editable=False, + ), ], auto_size=True, # show_toolbar = True, deletable=True, # reorderable = True, edit_on_first_click=False, - filter_name='filter', - selection_mode='rows', - selected='selected', - dclick='dclick', - label_bg_color='(244, 243, 238)', - cell_bg_color='(234, 233, 228)', + filter_name="filter", + selection_mode="rows", + selected="selected", + dclick="dclick", + label_bg_color="(244, 243, 238)", + cell_bg_color="(234, 233, 228)", ) - selectallbb = Button('Select all') - refreshbb = Button('Refresh') - plotbb = Button('Mask') - sumbb = Button('Sum') + selectallbb = Button("Select all") + refreshbb = Button("Refresh") + plotbb = Button("Mask") + sumbb = Button("Sum") traits_view = View( VGroup( VGroup( HGroup( - Item('search', id='search', springy=True, - editor=TextEditor(auto_set=False)), + Item( + "search", + id="search", + springy=True, + editor=TextEditor(auto_set=False), + ), + ), + HGroup( + spring, + Item("selectallbb", show_label=False), + Item("refreshbb", show_label=False), + spring, + Item("filetype", label="Type"), + ), + Item("datafiles", id="datafiles", editor=tableeditor), + Item("summary", editor=TitleEditor()), + HGroup( + spring, + Item("plotbb", show_label=False), + Item("sumbb", show_label=False), + spring, ), - HGroup(spring, - Item('selectallbb', show_label=False), - Item('refreshbb', show_label=False), - spring, - Item('filetype', label='Type'), - ), - Item('datafiles', id='datafiles', editor=tableeditor), - Item('summary', editor=TitleEditor()), - - HGroup(spring, - Item('plotbb', show_label=False), - Item('sumbb', show_label=False), - spring, - ), - dock='horizontal', - show_labels=False + dock="horizontal", + show_labels=False, ), ), # title = 'Add files', @@ -278,13 +326,13 @@ def _sumImgs(self): def _createFileNameFilter(pattern, casesensitive): - '''Build function that returns True for matching files. + """Build function that returns True for matching files. pattern -- string pattern to be matched casesensitive -- flag for case-sensitive file matching Return callable object. - ''' + """ try: from diffpy.pdfgetx.multipattern import MultiPattern except: @@ -303,6 +351,6 @@ def _createFileNameFilter(pattern, casesensitive): # Run the demo (if invoked from the command line): -if __name__ == '__main__': +if __name__ == "__main__": addfiles = AddFiles() addfiles.configure_traits() diff --git a/src/diffpy/srxplanargui/srxconfig.py b/src/diffpy/srxplanargui/srxconfig.py new file mode 100644 index 0000000..0dd3d57 --- /dev/null +++ b/src/diffpy/srxplanargui/srxconfig.py @@ -0,0 +1,372 @@ +#!/usr/bin/env python +############################################################################## +# +# diffpy.srxplanar by DANSE Diffraction group +# Simon J. L. Billinge +# (c) 2010 Trustees of the Columbia University +# in the City of New York. All rights reserved. +# +# File coded by: Xiaohao Yang +# +# See AUTHORS.txt for a list of people who contributed. +# See LICENSENOTICE.txt for license information. +# +############################################################################## + +import argparse +import configparser +import os +import re +import sys +from functools import partial + +import numpy as np +from traits.etsconfig.api import ETSConfig + +ETSConfig.toolkit = "qt4" + +from diffpy.srxconfutils.configtraits import ConfigBaseTraits +from diffpy.srxconfutils.tools import ( + _configPropertyR, + _configPropertyRad, + _configPropertyRW, +) +from diffpy.srxplanar.srxplanarconfig import ( + _defaultdata, + _description, + _epilog, + _optdatalist, + checkMax, +) +from pyface.api import ImageResource +from traits.api import ( + Any, + Array, + Bool, + Button, + CFloat, + CInt, + DelegatesTo, + Dict, + Directory, + Enum, + Event, + File, + Float, + HasTraits, + Instance, + Int, + List, + Property, + Range, + Str, + cached_property, + on_trait_change, + property_depends_on, +) +from traitsui.api import ( + Action, + ArrayEditor, + BooleanEditor, + ButtonEditor, + CheckListEditor, + Controller, + EnumEditor, + Group, + Handler, + HGroup, + HistoryEditor, + InstanceEditor, + Item, + RangeEditor, + Tabbed, + TableEditor, + TextEditor, + TitleEditor, + VGroup, + View, + spring, +) +from traitsui.menu import ( + CancelButton, + Menu, + MenuBar, + OKButton, + OKCancelButtons, + ToolBar, +) + +_optdatalist.append( + [ + "xpixelsizetem", + { + "sec": "Beamline", + "h": "detector pixel size in x axis, in A^-1", + "d": 0.02, + }, + ] +) +_optdatalist.append( + [ + "ypixelsizetem", + { + "sec": "Beamline", + "h": "detector pixel size in y axis, in A^-1", + "d": 0.02, + }, + ] +) + +for i in _optdatalist: + if i[0] == "polcorrectionenable": + i[1] = { + "sec": "Others", + "args": "n", + "config": "n", + "header": "n", + "s": "polarcorr", + "h": "enable polarization correction", + "n": "?", + "co": False, + "d": False, + } + elif i[0] == "polcorrectf": + i[1] = { + "sec": "Others", + "args": "n", + "config": "n", + "header": "n", + "s": "polarf", + "h": "polarization correction factor", + "d": 0.99, + } + elif i[0] == "xpixelsize": + i[1] = { + "sec": "Beamline", + "args": "n", + "config": "n", + "header": "n", + "s": "xp", + "h": "detector pixel size in x axis, in mm", + "d": 0.2, + } + elif i[0] == "ypixelsize": + i[1] = { + "sec": "Beamline", + "args": "n", + "config": "n", + "header": "n", + "s": "yp", + "h": "detector pixel size in y axis, in mm", + "d": 0.2, + } + + +class SrXconfig(ConfigBaseTraits): + """Config class, based on ConfigBase class in diffpy.confutils.""" + + # Text to display before the argument help + _description = _description + + # Text to display after the argument help + _epilog = _epilog + + _optdatalist = _optdatalist + + _defaultdata = {"configfile": [], "headertitle": "SrXgui configration"} + + rotation = Property( + depends_on="rotationd", fget=lambda self: np.radians(self.rotationd) + ) + tilt = Property( + depends_on="tiltd", fget=lambda self: np.radians(self.tiltd) + ) + tthstep = Property( + depends_on="tthstepd", fget=lambda self: np.radians(self.tthstepd) + ) + tthmax = Property( + depends_on="tthmaxd", fget=lambda self: np.radians(self.tthmaxd) + ) + + tthorqmax = Property( + depends_on="integrationspace, tthmaxd, qmax", + fget=lambda self: ( + self.tthmax if self.integrationspace == "twotheta" else self.qmax + ), + ) + tthorqstep = Property( + depends_on="integrationspace, tthmaxd, qmax", + fget=lambda self: ( + self.tthstep if self.integrationspace == "twotheta" else self.qstep + ), + ) + + def _preUpdateSelf(self, **kwargs): + """Additional process called in self._updateSelf, this method is + called before self._copySelftoConfig(), i.e. before copy options + value to self.config (config file) + + check the tthmaxd and qmax, and set tthorqmax, tthorqstep + according to integration space + + :param kwargs: optional kwargs + """ + self.tthmaxd, self.qmax = checkMax(self) + """Addmask = [b for b in self.addmask if not (b in + ['brightpixel', 'darkpixel'])] if len(addmask) > 0: + + self.maskfile = addmask[0] + """ + return + + def _opendirectory_changed(self): + if os.path.exists(self.opendirectory): + self.savedirectory = os.path.abspath(self.opendirectory) + else: + self.opendirectory = os.path.abspath(os.curdir) + self.savedirectory = os.path.abspath(os.curdir) + return + + def _savedirectory_changed(self): + if not os.path.exists(self.savedirectory): + self.savedirectory = os.path.abspath(os.curdir) + return + + configmode = Enum(["TEM", "normal"]) + + @on_trait_change("distance, wavelength, xpixelsizetem, ypixelsizetem") + def _refreshPSsize(self, obj, name, new): + self.updateConfig( + xpixelsize=self.xpixelsizetem * self.wavelength * self.distance, + ypixelsize=self.ypixelsizetem * self.wavelength * self.distance, + ) + return + + directory_group = Group( + Item( + "opendirectory", label="Input dir.", help="directory of 2D images" + ), + Item( + "savedirectory", + label="Output dir.", + help="directory of saved files", + ), + show_border=True, + label="Files", + ) + mask_group = Group( + Item("maskfile", label="Mask file"), + show_border=True, + label="Masks", + ) + + geometry_visible = Bool(False) + geometry_group = Group( + Item("integrationspace", label="Integration grid"), + Item( + "wavelength", + visible_when='integrationspace == "qspace"', + label="Wavelength", + ), + Item("xbeamcenter", label="X beamcenter"), + Item("ybeamcenter", label="Y beamcenter"), + Item( + "distance", + label="Camera length", + visible_when='configmode == "TEM"', + ), + Item( + "distance", label="Distance", visible_when='configmode == "normal"' + ), + Item("rotationd", label="Rotation"), + Item("tiltd", label="Tilt rotation"), + Item( + "tthstepd", + label="Integration step", + visible_when='integrationspace == "twotheta"', + ), + Item( + "qstep", + label="Integration step", + visible_when='integrationspace == "qspace"', + ), + show_border=True, + # label='Geometry parameters', + visible_when="geometry_visible", + ) + + correction_visible = Bool(False) + correction_group = Group( + Item("uncertaintyenable", label="Uncertainty"), + Item("sacorrectionenable", label="solid angle corr."), + # Item('polcorrectionenable', label='polarization corr.'), + # Item('polcorrectf', label='polarization factor'), + # Item('brightpixelmask', label='Bright pixel mask'), + # Item('darkpixelmask', label='Dark pixel mask'), + # Item('avgmask', label='Average mask'), + # Item('cropedges', label='Crop edges', editor=ArrayEditor(width=-50)), + show_border=True, + # label='Corrections' + visible_when="correction_visible", + ) + + detector_visible = Bool(False) + detector_group = ( + Group( + Item("fliphorizontal", label="Flip horizontally"), + Item("flipvertical", label="Flip vertically"), + Item("xdimension", label="x dimension"), + Item("ydimension", label="y dimension"), + Item( + "xpixelsizetem", + label="x pixel size (A^-1)", + tooltip="x pixel size, in A^-1", + visible_when='configmode == "TEM"', + ), + Item( + "ypixelsizetem", + label="y pixel size (A^-1)", + tooltip="y pixel size, in A^-1", + visible_when='configmode == "TEM"', + ), + show_border=True, + # label='Detector parameters' + visible_when="detector_visible", + ), + ) + + main_view = View( + Group( + directory_group, + mask_group, + Group( + # Item('configmode'), + Group( + Item("geometry_visible", label="Geometry parameters"), + geometry_group, + ), + Group( + Item("correction_visible", label="Corrections"), + correction_group, + ), + Group( + Item("detector_visible", label="Detector parameters"), + detector_group, + ), + # label = 'Basic' + show_border=True, + ), + ), + resizable=True, + scrollable=True, + # handler = handler, + icon=ImageResource("icon.png"), + ) + + +SrXconfig.initConfigClass() + +if __name__ == "__main__": + a = SrXconfig() + # a.updateConfig() + a.configure_traits(view="main_view") diff --git a/src/diffpy/srxplanargui/srxgui.py b/src/diffpy/srxplanargui/srxgui.py new file mode 100644 index 0000000..1f54e0c --- /dev/null +++ b/src/diffpy/srxplanargui/srxgui.py @@ -0,0 +1,310 @@ +#!/usr/bin/env python +############################################################################## +# +# dpx.pdfgetxgui by Simon J. L. Billinge group +# (c) 2012 Trustees of the Columbia University +# in the City of New York. All rights reserved. +# +# File coded by: Xiaohao Yang +# +# See AUTHORS.txt for a list of people who contributed. +# See LICENSE.txt for license information. +# +############################################################################## +"""Provide UI for srxplanar.""" + +import os +import sys + +import numpy as np +from traits.etsconfig.api import ETSConfig + +ETSConfig.toolkit = "qt4" + +from diffpy.srxplanar.srxplanar import SrXplanar +from pyface.api import ImageResource, SplashScreen +from traits.api import ( + Any, + Array, + Bool, + Button, + CFloat, + CInt, + DelegatesTo, + Dict, + Directory, + Enum, + Event, + File, + Float, + HasTraits, + Instance, + Int, + List, + Property, + Range, + Str, + cached_property, + on_trait_change, + property_depends_on, +) +from traitsui.api import ( + Action, + ArrayEditor, + ButtonEditor, + CheckListEditor, + Controller, + EnumEditor, + Group, + Handler, + HGroup, + HistoryEditor, + ImageEditor, + InstanceEditor, + Item, + RangeEditor, + Tabbed, + TableEditor, + TextEditor, + TitleEditor, + VGroup, + View, + spring, +) +from traitsui.menu import ( + CancelButton, + Menu, + MenuBar, + OKButton, + OKCancelButtons, + ToolBar, +) + +from diffpy.srxplanargui.calibration import Calibration +from diffpy.srxplanargui.help import SrXguiHelp +from diffpy.srxplanargui.selectfiles import AddFiles +from diffpy.srxplanargui.srxconfig import SrXconfig + + +class SrXguiHandler(Handler): + + def closed(self, info, is_ok): + """Notify main gui to delete current plot in plots list.""" + configfile = info.object.detectConfigfile("default") + info.object.saveConfig(configfile) + return True + + def _saveconfigView(self, info): + info.object._saveconfigView() + return + + def _loadconfigView(self, info): + info.object._loadconfigView() + return + + def _helpView(self, info): + info.object._helpbb_changed() + return + + +class SaveHandler(Handler): + + def closed(self, info, is_ok): + if is_ok: + info.object.saveConfig(info.object.configfile) + return True + + +class LoadHandler(Handler): + def closed(self, info, is_ok): + if is_ok: + info.object.loadConfig(info.object.configfile) + return + + +class SrXgui(HasTraits): + + addfiles = Instance(AddFiles) + srxconfig = Instance(SrXconfig) + help = Instance(SrXguiHelp) + splash = Any + calibration = Instance(Calibration) + + def __init__(self, configfile=None, args=None, **kwargs): + """Init the object, createt the notifications.""" + super(SrXgui, self).__init__(**kwargs) + configfile = self.detectConfigfile(configfile) + if not os.path.exists(configfile): + configfile = self.detectConfigfile("default") + self.configfile = configfile + + if not kwargs.has_key("srxconfig"): + self.srxconfig = SrXconfig( + filename=configfile, args=args, **kwargs + ) + + self.addfiles = AddFiles(srxconfig=self.srxconfig) + self.srx = SrXplanar(self.srxconfig) + self.addfiles.srx = self.srx + self.help = SrXguiHelp() + self.calibration = Calibration(srx=self.srx, srxconfig=self.srxconfig) + + # self.loadConfig(configfile) + self.splash.close() + return + + def saveConfig(self, filename=None): + """Save config.""" + if filename == "default": + filename = self.detectConfigfile(filename) + self.srxconfig.writeConfig(filename, mode="full") + self.configfile = filename + return + + def loadConfig(self, filename=None): + """Load config.""" + configfile = self.detectConfigfile(filename) + if os.path.exists(configfile): + self.srxconfig.updateConfig(filename=configfile) + self.configfile = configfile + return + + def processSelected(self, summation=False): + if self.addfiles.selected: + self.srx.updateConfig() + filelist = [f.fullname for f in self.addfiles.selected] + self.srx.prepareCalculation(filelist) + self.srx.integrateFilelist(filelist, summation=summation) + return + + def detectConfigfile(self, filename): + """Current directory > home directory, if none, then return the + curdir+filename if 'default', then return home+filename.""" + if filename == None: + configfile = os.path.join(os.path.curdir, "srxconfig.cfg") + elif filename == "default": + configfile = os.path.join(os.path.expanduser("~"), "srxconfig.cfg") + else: + if os.path.abspath(filename): + if os.path.exists(filename): + configfile = filename + else: + filename = os.path.split(filename)[1] + configfile = os.path.join(os.path.curdir, filename) + else: + configfile = os.path.join(os.path.curdir, filename) + return configfile + + ########################################################### + def _saveconfigView(self): + self.edit_traits(view="saveconfig_view") + return + + def _loadconfigView(self): + self.edit_traits(view="loadconfig_view") + return + + configfile = File() + helpbutton_action = Action(name="Help ", action="_helpView") + saveconfig_action = Action(name="Save Config", action="_saveconfigView") + loadconfig_action = Action(name="Load Config", action="_loadconfigView") + + saveconfig_view = View( + Item("configfile"), + resizable=True, + title="Save config", + width=500, + buttons=[OKButton, CancelButton], + handler=SaveHandler(), + icon=ImageResource("icon.png"), + ) + loadconfig_view = View( + Item("configfile"), + resizable=True, + title="Load config", + width=500, + buttons=[OKButton, CancelButton], + handler=LoadHandler(), + icon=ImageResource("icon.png"), + ) + ############################################################# + + def _integratbb_changed(self): + self.processSelected(False) + return + + def _integratessbb_changed(self): + self.processSelected(True) + return + + def _helpbb_changed(self): + self.help.edit_traits(view="quickstart_view") + return + + def _selfcalibratebb_changed(self): + image = None + if self.addfiles.selected != None: + if len(self.addfiles.selected) == 1: + image = self.addfiles.selected[0].fullname + + if image != None: + self.calibration.image = image + self.calibration.edit_traits(view="main_View") + return + + integratbb = Button("Integrate") + integratessbb = Button("Sum and Integrate") + selfcalibratebb = Button("Calibrate") + helpbb = Button("Help") + + traits_view = View( + HGroup( + Item( + "addfiles", + editor=InstanceEditor(view="traits_view"), + style="custom", + label="Files", + width=0.4, + ), + VGroup( + Group( + Item( + "srxconfig", + editor=InstanceEditor(view="main_view"), + style="custom", + label="Basic", + show_label=False, + ), + springy=True, + ), + HGroup( + spring, + Item("selfcalibratebb"), + Item("integratbb"), + spring, + show_labels=False, + ), + ), + layout="split", + springy=True, + dock="tab", + show_labels=False, + ), + resizable=True, + title="SrXgui", + width=700, + height=650, + kind="live", + buttons=[ + helpbutton_action, + saveconfig_action, + loadconfig_action, + OKButton, + ], + icon=ImageResource("icon.png"), + handler=SrXguiHandler(), + ) + + +if __name__ == "__main__": + sys.exit() diff --git a/dpx/srxplanargui/srxguiapp.py b/src/diffpy/srxplanargui/srxguiapp.py similarity index 63% rename from dpx/srxplanargui/srxguiapp.py rename to src/diffpy/srxplanargui/srxguiapp.py index ae7981f..1107617 100644 --- a/dpx/srxplanargui/srxguiapp.py +++ b/src/diffpy/srxplanargui/srxguiapp.py @@ -11,42 +11,46 @@ # See LICENSE.txt for license information. # ############################################################################## +"""Provide UI for srxplanar.""" -'''provide UI for srxplanar -''' - -import numpy as np +import logging import os import sys - import warnings + +from pyface.api import ImageResource, SplashScreen +from traits.etsconfig.api import ETSConfig + +from diffpy.srxplanargui.srxgui import SrXgui + warnings.filterwarnings("ignore") -import logging -logging.disable('CRITICAL') + + +logging.disable("CRITICAL") # break if help passed to the args sysargv = sys.argv[1:] -if ('--help' in sysargv) or('-h' in sysargv): - from dpx.srxplanargui.srxconfig import SrXconfig +if ("--help" in sysargv) or ("-h" in sysargv): + from diffpy.srxplanargui.srxconfig import SrXconfig + SrXconfig(args=sysargv) -from traits.etsconfig.api import ETSConfig -os.environ['QT_API'] = 'pyside' -ETSConfig.toolkit = 'qt4' -from pyface.qt import QtGui, QtCore -from pyface.api import ImageResource, SplashScreen +os.environ["QT_API"] = "pyside" +ETSConfig.toolkit = "qt" + + # open splash screen -splash = SplashScreen(image=ImageResource('01.png'), show_log_messages=False) -if not any([aa == '-h' or aa == '--help' for aa in sysargv]): +splash = SplashScreen(image=ImageResource("01.png"), show_log_messages=False) +if not any([aa == "-h" or aa == "--help" for aa in sysargv]): splash.open() -from dpx.srxplanargui.srxgui import SrXgui def main(): gui = SrXgui(splash=splash) - gui.configure_traits(view='traits_view') + gui.configure_traits(view="traits_view") return -if __name__ == '__main__': + +if __name__ == "__main__": sys.exit(main()) diff --git a/dpx/srxplanargui/version.py b/src/diffpy/srxplanargui/version.py similarity index 79% rename from dpx/srxplanargui/version.py rename to src/diffpy/srxplanargui/version.py index eda8c87..ffac5d9 100644 --- a/dpx/srxplanargui/version.py +++ b/src/diffpy/srxplanargui/version.py @@ -12,17 +12,17 @@ # See LICENSENOTICE.txt for license information. # ############################################################################## - -"""Definition of __version__ and __date__ for this package. -""" +"""Definition of __version__ and __date__ for this package.""" # obtain version information from pkg_resources import get_distribution -_pkgname = __name__.rsplit('.', 1)[0] + +_pkgname = __name__.rsplit(".", 1)[0] __version__ = get_distribution(_pkgname).version # we assume that tag_date was used and __version__ ends in YYYYMMDD -__date__ = __version__[-8:-4] + '-' + \ - __version__[-4:-2] + '-' + __version__[-2:] +__date__ = ( + __version__[-8:-4] + "-" + __version__[-4:-2] + "-" + __version__[-2:] +) # End of file