orGUI 1.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- orGUI-1.0.1.dist-info/LICENSE +21 -0
- orGUI-1.0.1.dist-info/METADATA +147 -0
- orGUI-1.0.1.dist-info/RECORD +83 -0
- orGUI-1.0.1.dist-info/WHEEL +5 -0
- orGUI-1.0.1.dist-info/entry_points.txt +2 -0
- orGUI-1.0.1.dist-info/top_level.txt +1 -0
- orgui/__init__.py +36 -0
- orgui/app/ArrayTableDialog.py +433 -0
- orgui/app/QReflectionSelector.py +538 -0
- orgui/app/QScanSelector.py +692 -0
- orgui/app/QUBCalculator.py +1210 -0
- orgui/app/__init__.py +36 -0
- orgui/app/database.py +487 -0
- orgui/app/orGUI.py +2613 -0
- orgui/app/qutils.py +51 -0
- orgui/backend/__init__.py +32 -0
- orgui/backend/backends.py +157 -0
- orgui/backend/beamline/ID31DiffractLinTilt.py +77 -0
- orgui/backend/beamline/P212_tools.py +577 -0
- orgui/backend/beamline/__init__.py +36 -0
- orgui/backend/beamline/fio_reader.py +110 -0
- orgui/backend/beamline/id31_tools.py +651 -0
- orgui/backend/scans.py +95 -0
- orgui/backend/udefaults.py +163 -0
- orgui/backend/universalScanLoader.py +105 -0
- orgui/datautils/__init__.py +32 -0
- orgui/datautils/util.py +705 -0
- orgui/datautils/xrayutils/CTRcalc.py +3022 -0
- orgui/datautils/xrayutils/CTRopt.py +623 -0
- orgui/datautils/xrayutils/CTRplotutil.py +904 -0
- orgui/datautils/xrayutils/DetectorCalibration.py +685 -0
- orgui/datautils/xrayutils/HKLVlieg.py +1360 -0
- orgui/datautils/xrayutils/ReciprocalNavigation.py +401 -0
- orgui/datautils/xrayutils/_CTRcalc_accel.py +181 -0
- orgui/datautils/xrayutils/__init__.py +46 -0
- orgui/datautils/xrayutils/element_data.py +213 -0
- orgui/datautils/xrayutils/test/__init__.py +57 -0
- orgui/datautils/xrayutils/test/test_CTRcalc.py +152 -0
- orgui/datautils/xrayutils/test/test_DetectorCalibration.py +336 -0
- orgui/datautils/xrayutils/test/test_HKLcalc.py +88 -0
- orgui/datautils/xrayutils/unitcells/Fe3O4(100).bul +59 -0
- orgui/datautils/xrayutils/unitcells/Pt100.bul +7 -0
- orgui/datautils/xrayutils/unitcells/Pt100_small.bul +5 -0
- orgui/datautils/xrayutils/unitcells/Pt110.bul +5 -0
- orgui/datautils/xrayutils/unitcells/Pt111.bul +6 -0
- orgui/datautils/xrayutils/unitcells/Pt310.bul +13 -0
- orgui/datautils/xrayutils/unitcells/Pt3O4(100).bul +19 -0
- orgui/datautils/xrayutils/unitcells/PtO(001).bul +9 -0
- orgui/datautils/xrayutils/unitcells/PtO(010).bul +9 -0
- orgui/datautils/xrayutils/unitcells/PtO(100).bul +9 -0
- orgui/datautils/xrayutils/unitcells/__init__.py +67 -0
- orgui/datautils/xrayutils/unitcells/a-PtO2(0001).bul +6 -0
- orgui/main.py +101 -0
- orgui/resources/__init__.py +40 -0
- orgui/resources/icons/alpha.png +0 -0
- orgui/resources/icons/alpha.svg +67 -0
- orgui/resources/icons/diffractometer_v3.png +0 -0
- orgui/resources/icons/disable-image.png +0 -0
- orgui/resources/icons/disable-image.svg +68 -0
- orgui/resources/icons/document-nx-open.png +0 -0
- orgui/resources/icons/document-nx-open.svg +152 -0
- orgui/resources/icons/document-nx-save.png +0 -0
- orgui/resources/icons/document-nx-save.svg +73 -0
- orgui/resources/icons/logo.png +0 -0
- orgui/resources/icons/logo.svg +808 -0
- orgui/resources/icons/max_image.png +0 -0
- orgui/resources/icons/max_image.svg +77 -0
- orgui/resources/icons/max_image2.png +0 -0
- orgui/resources/icons/max_image2.svg +83 -0
- orgui/resources/icons/search-image.png +0 -0
- orgui/resources/icons/search-image.svg +94 -0
- orgui/resources/icons/search-reflection.png +0 -0
- orgui/resources/icons/search-reflection.svg +126 -0
- orgui/resources/icons/search.png +0 -0
- orgui/resources/icons/search.svg +91 -0
- orgui/resources/icons/select-image.png +0 -0
- orgui/resources/icons/select-image.svg +60 -0
- orgui/resources/icons/set-reflection.png +0 -0
- orgui/resources/icons/set-reflection.svg +91 -0
- orgui/resources/icons/sum_image.png +0 -0
- orgui/resources/icons/sum_image.svg +63 -0
- orgui/resources/icons/sum_image2.png +0 -0
- orgui/resources/icons/sum_image2.svg +75 -0
orgui/app/__init__.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# /*##########################################################################
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2020-2024 Timo Fuchs
|
|
5
|
+
#
|
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
# furnished to do so, subject to the following conditions:
|
|
12
|
+
#
|
|
13
|
+
# The above copyright notice and this permission notice shall be included in
|
|
14
|
+
# all copies or substantial portions of the Software.
|
|
15
|
+
#
|
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
# THE SOFTWARE.
|
|
23
|
+
#
|
|
24
|
+
# ###########################################################################*/
|
|
25
|
+
__author__ = "Timo Fuchs"
|
|
26
|
+
__copyright__ = "Copyright 2020-2024 Timo Fuchs"
|
|
27
|
+
__license__ = "MIT License"
|
|
28
|
+
__version__ = "1.0.0"
|
|
29
|
+
__maintainer__ = "Timo Fuchs"
|
|
30
|
+
__email__ = "fuchs@physik.uni-kiel.de"
|
|
31
|
+
|
|
32
|
+
"""Module descripiton
|
|
33
|
+
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
__all__ = ['orGUI','QReflectionSelector','QSpecScanSelector','QUBCalculator','database']
|
orgui/app/database.py
ADDED
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# /*##########################################################################
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2020-2024 Timo Fuchs
|
|
5
|
+
#
|
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
# furnished to do so, subject to the following conditions:
|
|
12
|
+
#
|
|
13
|
+
# The above copyright notice and this permission notice shall be included in
|
|
14
|
+
# all copies or substantial portions of the Software.
|
|
15
|
+
#
|
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
# THE SOFTWARE.
|
|
23
|
+
#
|
|
24
|
+
# ###########################################################################*/
|
|
25
|
+
__author__ = "Timo Fuchs"
|
|
26
|
+
__copyright__ = "Copyright 2020-2024 Timo Fuchs"
|
|
27
|
+
__license__ = "MIT License"
|
|
28
|
+
__version__ = "1.0.0"
|
|
29
|
+
__maintainer__ = "Timo Fuchs"
|
|
30
|
+
__email__ = "fuchs@physik.uni-kiel.de"
|
|
31
|
+
|
|
32
|
+
import sys
|
|
33
|
+
import numpy as np
|
|
34
|
+
import silx.gui.hdf5
|
|
35
|
+
from silx.gui import icons
|
|
36
|
+
from silx.gui.data import DataViewerFrame
|
|
37
|
+
from silx.gui.hdf5.Hdf5TreeModel import Hdf5TreeModel
|
|
38
|
+
from silx.gui.data import DataViewerFrame
|
|
39
|
+
from silx.gui import qt
|
|
40
|
+
import tempfile
|
|
41
|
+
import silx.io.h5py_utils
|
|
42
|
+
from silx.io import nxdata
|
|
43
|
+
import silx.io.utils
|
|
44
|
+
import h5py
|
|
45
|
+
|
|
46
|
+
import datetime
|
|
47
|
+
import os
|
|
48
|
+
import traceback
|
|
49
|
+
import time
|
|
50
|
+
|
|
51
|
+
from ..datautils.xrayutils import unitcells
|
|
52
|
+
from ..datautils.xrayutils import HKLVlieg, CTRcalc
|
|
53
|
+
from ..datautils.xrayutils import DetectorCalibration
|
|
54
|
+
|
|
55
|
+
from silx.io.dictdump import dicttonx ,nxtodict
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class ConfigData(qt.QObject):
|
|
59
|
+
def __init__(self, config=None):
|
|
60
|
+
self.detector = DetectorCalibration.Detector2D_SXRD()
|
|
61
|
+
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
#@classmethod
|
|
65
|
+
def readConfig(self, filename):
|
|
66
|
+
config = configparser.ConfigParser()
|
|
67
|
+
config.read(configfile)
|
|
68
|
+
|
|
69
|
+
machine = config['Machine']
|
|
70
|
+
lattice = config['Lattice']
|
|
71
|
+
diffrac = config['Diffractometer']
|
|
72
|
+
|
|
73
|
+
self.azimuth = np.deg2rad(diffrac.getfloat('azimuthal_reference',0))
|
|
74
|
+
self.polaxis = np.deg2rad(diffrac.getfloat('polarization_axis',90))
|
|
75
|
+
self.polfactor = diffrac.getfloat('polarization_factor',0)
|
|
76
|
+
|
|
77
|
+
sdd = machine.getfloat('SDD',0.729) #m
|
|
78
|
+
E = machine.getfloat('E',78.0) #keV
|
|
79
|
+
pixelsize = machine.getfloat('pixelsize',172e-6) #m
|
|
80
|
+
cpx = machine.getfloat('cpx',731)
|
|
81
|
+
cpy = machine.getfloat('cpy',1587)
|
|
82
|
+
cp = [cpx,cpy]
|
|
83
|
+
|
|
84
|
+
self.mu = np.deg2rad(diffrac.getfloat('mu',0.05))
|
|
85
|
+
self.chi = np.deg2rad(diffrac.getfloat('chi',0.0))
|
|
86
|
+
self.phi = np.deg2rad(diffrac.getfloat('phi',0.0))
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
a1 = lattice.getfloat('a1',-1)
|
|
90
|
+
a2 = lattice.getfloat('a2',-1)
|
|
91
|
+
a3 = lattice.getfloat('a3',-1)
|
|
92
|
+
alpha1 = lattice.getfloat('alpha1',-1)
|
|
93
|
+
alpha2 = lattice.getfloat('alpha2',-1)
|
|
94
|
+
alpha3 = lattice.getfloat('alpha3',-1)
|
|
95
|
+
self.n = 1 - lattice.getfloat('refractionindex',0.0)
|
|
96
|
+
|
|
97
|
+
lat = np.array([a1,a2,a3])
|
|
98
|
+
|
|
99
|
+
latticeoverride = True
|
|
100
|
+
latangle = np.array([alpha1,alpha2,alpha3])
|
|
101
|
+
if np.any(lat < 0.) or np.any(latangle < 0):
|
|
102
|
+
latticeoverride = False
|
|
103
|
+
a1 = a2 = a3 = 1.
|
|
104
|
+
alpha1 = alpha2 = alpha3 = 90.
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
self.crystal = CTRcalc.UnitCell([a1,a2,a3],[alpha1,alpha2,alpha3])
|
|
108
|
+
self.crystal.addAtom('Pt',[0.,0.,0.],0.1,0.1,1.)
|
|
109
|
+
self.crystal.setEnergy(E*1e3)
|
|
110
|
+
|
|
111
|
+
self.ubCal = HKLVlieg.UBCalculator(self.crystal,E)
|
|
112
|
+
self.ubCal.defaultU()
|
|
113
|
+
self.angles = HKLVlieg.VliegAngles(self.ubCal)
|
|
114
|
+
|
|
115
|
+
if 'crystal' in lattice:
|
|
116
|
+
idx = self.crystalparams.crystalComboBox.findText(lattice['crystal'],qt.Qt.MatchFixedString)
|
|
117
|
+
if idx == -1:
|
|
118
|
+
qt.QMessageBox.warning(self,"Did not find crystal","Can not find crystal <%s> \nException occured during read of configfile %s,\nException:\n%s" % (unitcellsconfigfile,traceback.format_exc()))
|
|
119
|
+
else:
|
|
120
|
+
self.crystalparams.crystalComboBox.setCurrentIndex(idx)
|
|
121
|
+
self.crystalparams.onSwitchCrystal(idx)
|
|
122
|
+
#self.crystal = self.crystalparams.getCrystal()
|
|
123
|
+
|
|
124
|
+
if latticeoverride:
|
|
125
|
+
print('foo')
|
|
126
|
+
self.crystal.setLattice([a1,a2,a3],[alpha1,alpha2,alpha3])
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
if 'poni' in machine:
|
|
130
|
+
if machine['poni']:
|
|
131
|
+
self.detectorCal.load(machine['poni'])
|
|
132
|
+
self.ubCal.setLambda(self.detectorCal.get_wavelength()*1e10)
|
|
133
|
+
|
|
134
|
+
else:
|
|
135
|
+
self.detectorCal.setFit2D(sdd*1e3,cpx,cpy,pixelX=pixelsize*1e6, pixelY=pixelsize*1e6)
|
|
136
|
+
self.detectorCal.set_wavelength(self.ubCal.getLambda()*1e-10)
|
|
137
|
+
self.detectorCal.detector.shape = (2880,2880) # Perkin
|
|
138
|
+
|
|
139
|
+
else:
|
|
140
|
+
self.detectorCal.setFit2D(sdd*1e3,cpx,cpy,pixelX=pixelsize*1e6, pixelY=pixelsize*1e6)
|
|
141
|
+
self.detectorCal.set_wavelength(self.ubCal.getLambda()*1e-10)
|
|
142
|
+
self.detectorCal.detector.shape = (2880,2880)
|
|
143
|
+
|
|
144
|
+
self.detectorCal.setAzimuthalReference(self.azimuth)
|
|
145
|
+
self.detectorCal.setPolarization(self.polaxis,self.polfactor)
|
|
146
|
+
|
|
147
|
+
fit2dCal = self.detectorCal.getFit2D()
|
|
148
|
+
|
|
149
|
+
paramlist = [self.ubCal.getEnergy(),self.mu,fit2dCal['directDist']/1e3,
|
|
150
|
+
fit2dCal['pixelX']*1e-6,[fit2dCal['centerX'],fit2dCal['centerY']],self.polaxis
|
|
151
|
+
,self.polfactor,self.azimuth,self.chi,self.phi]
|
|
152
|
+
self.crystalparams.setValues(self.crystal,self.n)
|
|
153
|
+
self.machineParams.setValues(paramlist)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class DataBase(qt.QMainWindow):
|
|
161
|
+
|
|
162
|
+
def __init__(self, plot, parent=None):
|
|
163
|
+
qt.QMainWindow.__init__(self, parent)
|
|
164
|
+
self.nxfile = None
|
|
165
|
+
self.filedialogdir = os.getcwd()
|
|
166
|
+
self.plot = plot
|
|
167
|
+
|
|
168
|
+
self.view = silx.gui.hdf5.Hdf5TreeView()
|
|
169
|
+
self.view.setSortingEnabled(True)
|
|
170
|
+
|
|
171
|
+
#self.view.addContextMenuCallback(self.nexus_treeview_callback)
|
|
172
|
+
#self.hdf5model = self.view.findHdf5TreeModel()
|
|
173
|
+
|
|
174
|
+
customModel = Hdf5TreeModel
|
|
175
|
+
customModel.NAME_COLUMN = 0
|
|
176
|
+
customModel.DESCRIPTION_COLUMN = 1
|
|
177
|
+
customModel.VALUE_COLUMN = 2
|
|
178
|
+
customModel.SHAPE_COLUMN = 3
|
|
179
|
+
customModel.TYPE_COLUMN = 4
|
|
180
|
+
customModel.NODE_COLUMN = 5
|
|
181
|
+
customModel.LINK_COLUMN = 6
|
|
182
|
+
|
|
183
|
+
self.hdf5model = customModel(self.view)
|
|
184
|
+
self.view.setModel(self.hdf5model)
|
|
185
|
+
|
|
186
|
+
self.dataviewer = DataViewerFrame.DataViewerFrame()
|
|
187
|
+
self.dataviewerDialog = qt.QDialog(self)
|
|
188
|
+
dvlayout = qt.QVBoxLayout()
|
|
189
|
+
dvlayout.addWidget(self.dataviewer)
|
|
190
|
+
self.dataviewerDialog.setLayout(dvlayout)
|
|
191
|
+
self.dataviewerDialog.setModal(False)
|
|
192
|
+
|
|
193
|
+
self.view.setExpandsOnDoubleClick(False)
|
|
194
|
+
self.hdf5model.setFileMoveEnabled(True)
|
|
195
|
+
#self.__treeModelSorted = silx.gui.hdf5.NexusSortFilterProxyModel(self.view)
|
|
196
|
+
#self.__treeModelSorted.setSourceModel(self.hdf5model)
|
|
197
|
+
#self.__treeModelSorted.sort(0, qt.Qt.AscendingOrder)
|
|
198
|
+
#self.__treeModelSorted.setSortCaseSensitivity(qt.Qt.CaseInsensitive)
|
|
199
|
+
|
|
200
|
+
#self.hdfTreeView.setModel(self.__treeModelSorted)
|
|
201
|
+
|
|
202
|
+
self.view.doubleClicked.connect(self._onNEXUSDoubleClicked)
|
|
203
|
+
self.view.addContextMenuCallback(self.nexus_treeview_callback)
|
|
204
|
+
|
|
205
|
+
self.temp_directory = tempfile.TemporaryDirectory(dir=os.path.join(os.getcwd()))
|
|
206
|
+
tempfilepath = os.path.join(self.temp_directory.name,"orgui_database.h5")
|
|
207
|
+
self.createNewDBFile(tempfilepath)
|
|
208
|
+
#self.add_nxdict(gauss)
|
|
209
|
+
#self.add_nxdict(gauss)
|
|
210
|
+
self.setCentralWidget(self.view)
|
|
211
|
+
|
|
212
|
+
toolbar = qt.QToolBar("Database toolbar",self)
|
|
213
|
+
|
|
214
|
+
loadDatabaseAct = toolbar.addAction(icons.getQIcon("document-open"),"Open orgui database")
|
|
215
|
+
loadDatabaseAct.triggered.connect(self.onOpenDatabase)
|
|
216
|
+
|
|
217
|
+
savenewact = toolbar.addAction(icons.getQIcon("layer-nx"),"Select orgui database location")
|
|
218
|
+
savenewact.triggered.connect(self.onSaveNewDBFile)
|
|
219
|
+
|
|
220
|
+
saveact = toolbar.addAction(icons.getQIcon("document-save"),"Save orgui database")
|
|
221
|
+
saveact.triggered.connect(self.onSaveDBFile)
|
|
222
|
+
|
|
223
|
+
self.addToolBar(toolbar)
|
|
224
|
+
|
|
225
|
+
def _onNEXUSDoubleClicked(self,index): # ToDo add try except with popup message!
|
|
226
|
+
nodes = list(self.view.selectedH5Nodes())
|
|
227
|
+
if len(nodes) > 0:
|
|
228
|
+
obj = nodes[0]
|
|
229
|
+
if obj.ntype is h5py.Dataset:
|
|
230
|
+
roi_node = self.get_roinode(obj.h5py_object)
|
|
231
|
+
if roi_node is not None:
|
|
232
|
+
self.plot_signal_callback(roi_node, obj)
|
|
233
|
+
return
|
|
234
|
+
self.plot_default(obj.h5py_object)
|
|
235
|
+
|
|
236
|
+
def plot_default(self, h5py_object):
|
|
237
|
+
try:
|
|
238
|
+
nxdat = nxdata.get_default(h5py_object)
|
|
239
|
+
#print(nxdat.axes, nxdat.signal, nxdat.title)
|
|
240
|
+
#print(nxdat.signal_name, nxdat.errors, nxdat.axes_names)
|
|
241
|
+
if nxdat is not None and len(nxdat.axes) == 1:
|
|
242
|
+
self.plot.addCurve(nxdat.axes[0], nxdat.signal, legend=nxdat.title, xlabel=nxdat.axes_names[0], ylabel=nxdat.signal_name, yerror=nxdat.errors)
|
|
243
|
+
except Exception as e:
|
|
244
|
+
traceback.print_exc()
|
|
245
|
+
print("Cannot plot data: %s" % e)
|
|
246
|
+
|
|
247
|
+
def get_roinode(self, obj):
|
|
248
|
+
if silx.io.utils.get_h5_class(obj) is None:
|
|
249
|
+
return None
|
|
250
|
+
|
|
251
|
+
while(obj.name != '/'):
|
|
252
|
+
meta = obj.attrs.get('orgui_meta', False)
|
|
253
|
+
if meta and meta == 'roi':
|
|
254
|
+
return obj
|
|
255
|
+
obj = obj.parent
|
|
256
|
+
|
|
257
|
+
def get_scannode(self, obj):
|
|
258
|
+
if silx.io.utils.get_h5_class(obj) is None:
|
|
259
|
+
return None
|
|
260
|
+
|
|
261
|
+
while(obj.name != '/'):
|
|
262
|
+
meta = obj.attrs.get('orgui_meta', False)
|
|
263
|
+
if meta and meta == 'scan':
|
|
264
|
+
return obj
|
|
265
|
+
obj = obj.parent
|
|
266
|
+
|
|
267
|
+
def nexus_treeview_callback(self,event):
|
|
268
|
+
objects = list(event.source().selectedH5Nodes())
|
|
269
|
+
obj = objects[0] # for single selection
|
|
270
|
+
menu = event.menu()
|
|
271
|
+
action = qt.QAction("Refresh", menu)
|
|
272
|
+
action.triggered.connect(lambda: self.hdf5model.synchronizeH5pyObject(obj))
|
|
273
|
+
menu.addAction(action)
|
|
274
|
+
action = qt.QAction("details", menu)
|
|
275
|
+
action.triggered.connect(lambda: self.view_data_callback(obj))
|
|
276
|
+
menu.addAction(action)
|
|
277
|
+
|
|
278
|
+
if obj.ntype is h5py.Dataset:
|
|
279
|
+
roi_node = self.get_roinode(obj.h5py_object)
|
|
280
|
+
if roi_node is not None:
|
|
281
|
+
action = qt.QAction("plot %s" % obj.name, menu)
|
|
282
|
+
action.triggered.connect(lambda: self.plot_signal_callback(roi_node, obj))
|
|
283
|
+
menu.addAction(action)
|
|
284
|
+
|
|
285
|
+
if obj.ntype is h5py.Group:
|
|
286
|
+
meta = obj.h5py_object.attrs.get('orgui_meta', False)
|
|
287
|
+
if meta and meta == 'roi':
|
|
288
|
+
action = qt.QAction("rename", menu)
|
|
289
|
+
action.triggered.connect(lambda: self.onRenameNode(obj.h5py_object))
|
|
290
|
+
menu.addAction(action)
|
|
291
|
+
menu.addSeparator()
|
|
292
|
+
action = qt.QAction("delete", menu)
|
|
293
|
+
action.triggered.connect(lambda: self.delete_node(obj.h5py_object))
|
|
294
|
+
menu.addAction(action)
|
|
295
|
+
|
|
296
|
+
if meta and meta == 'scan':
|
|
297
|
+
menu.addSeparator()
|
|
298
|
+
action = qt.QAction("delete", menu)
|
|
299
|
+
action.triggered.connect(lambda: self.onDeleteScan(obj.h5py_object))
|
|
300
|
+
menu.addAction(action)
|
|
301
|
+
|
|
302
|
+
"""
|
|
303
|
+
if obj.ntype is h5py.File:
|
|
304
|
+
action = qt.QAction("remove", menu)
|
|
305
|
+
action.triggered.connect(lambda: self._onCloseFile())
|
|
306
|
+
menu.addAction(action)
|
|
307
|
+
"""
|
|
308
|
+
def plot_signal_callback(self, roi_node, dataset):
|
|
309
|
+
try:
|
|
310
|
+
nxdat = nxdata.get_default(roi_node)
|
|
311
|
+
data = dataset.h5py_object[()]
|
|
312
|
+
#print(nxdat.axes, nxdat.signal, nxdat.title)
|
|
313
|
+
#print(nxdat.signal_name, nxdat.errors, nxdat.axes_names)
|
|
314
|
+
if nxdat is not None and len(nxdat.axes) == 1:
|
|
315
|
+
self.plot.addCurve(nxdat.axes[0], data, legend=nxdat.title + "_" + dataset.name, xlabel=nxdat.axes_names[0], ylabel=dataset.name)
|
|
316
|
+
except Exception as e:
|
|
317
|
+
traceback.print_exc()
|
|
318
|
+
print("Cannot plot data: %s" % e)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def view_data_callback(self,obj):
|
|
323
|
+
self.dataviewer.setData(obj)
|
|
324
|
+
self.dataviewerDialog.open()
|
|
325
|
+
|
|
326
|
+
def onSaveNewDBFile(self):
|
|
327
|
+
fileTypeDict = {'NEXUS Files (*.h5)': '.h5', 'All files (*)': '' }
|
|
328
|
+
fileTypeFilter = ""
|
|
329
|
+
for f in fileTypeDict:
|
|
330
|
+
fileTypeFilter += f + ";;"
|
|
331
|
+
|
|
332
|
+
filename, filetype = qt.QFileDialog.getSaveFileName(self,"Select database location",
|
|
333
|
+
self.filedialogdir,
|
|
334
|
+
fileTypeFilter[:-2])
|
|
335
|
+
if filename == '':
|
|
336
|
+
return
|
|
337
|
+
|
|
338
|
+
self.filedialogdir = os.path.splitext(filename)[0]
|
|
339
|
+
#filename += fileTypeDict[filetype]
|
|
340
|
+
self.saveNewDBFile(filename)
|
|
341
|
+
|
|
342
|
+
def onSaveDBFile(self):
|
|
343
|
+
fileTypeDict = {'NEXUS Files (*.h5)': '.h5', 'All files (*)': '' }
|
|
344
|
+
fileTypeFilter = ""
|
|
345
|
+
for f in fileTypeDict:
|
|
346
|
+
fileTypeFilter += f + ";;"
|
|
347
|
+
|
|
348
|
+
filename, filetype = qt.QFileDialog.getSaveFileName(self,"Save database",
|
|
349
|
+
self.filedialogdir,
|
|
350
|
+
fileTypeFilter[:-2])
|
|
351
|
+
if filename == '':
|
|
352
|
+
return
|
|
353
|
+
|
|
354
|
+
self.filedialogdir = os.path.splitext(filename)[0]
|
|
355
|
+
#filename += fileTypeDict[filetype]
|
|
356
|
+
self.saveDBFile(filename)
|
|
357
|
+
|
|
358
|
+
def onOpenDatabase(self):
|
|
359
|
+
fileTypeDict = {'NEXUS Files (*.h5)': '.h5', 'All files (*)': '' }
|
|
360
|
+
fileTypeFilter = ""
|
|
361
|
+
for f in fileTypeDict:
|
|
362
|
+
fileTypeFilter += f + ";;"
|
|
363
|
+
|
|
364
|
+
filename, filetype = qt.QFileDialog.getOpenFileName(self,"Save database",
|
|
365
|
+
self.filedialogdir,
|
|
366
|
+
fileTypeFilter[:-2])
|
|
367
|
+
if filename == '':
|
|
368
|
+
return
|
|
369
|
+
|
|
370
|
+
self.filedialogdir = os.path.splitext(filename)[0]
|
|
371
|
+
#filename += fileTypeDict[filetype]
|
|
372
|
+
try:
|
|
373
|
+
self.openDBFile(filename)
|
|
374
|
+
except:
|
|
375
|
+
msgbox = qt.QMessageBox(qt.QMessageBox.Critical,'Cannot open db file',
|
|
376
|
+
'Cannot open db file %s.' % filename,
|
|
377
|
+
qt.QMessageBox.Ok, self)
|
|
378
|
+
msgbox.setDetailedText(traceback.format_exc())
|
|
379
|
+
clickedbutton = msgbox.exec()
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
def saveNewDBFile(self, filename):
|
|
383
|
+
alldata = nxtodict(self.nxfile)
|
|
384
|
+
self.createNewDBFile(filename, alldata)
|
|
385
|
+
|
|
386
|
+
def saveDBFile(self, filename):
|
|
387
|
+
alldata = nxtodict(self.nxfile)
|
|
388
|
+
dicttonx(alldata, filename)
|
|
389
|
+
|
|
390
|
+
def createNewDBFile(self, filename, datadict=None):
|
|
391
|
+
if self.nxfile is not None:
|
|
392
|
+
while(self.hdf5model.hasPendingOperations()):
|
|
393
|
+
qt.QApplication.processEvents()
|
|
394
|
+
time.sleep(0.01)
|
|
395
|
+
self.hdf5model.removeH5pyObject(self.nxfile)
|
|
396
|
+
self.nxfile.close()
|
|
397
|
+
self.nxfile = None
|
|
398
|
+
if hasattr(self, "temp_directory"):
|
|
399
|
+
del self.temp_directory
|
|
400
|
+
|
|
401
|
+
fileattrs = {"@NX_class": u"NXroot",
|
|
402
|
+
"@creator": u"orGUI version %s" % __version__,
|
|
403
|
+
"@file_name": str(os.path.basename(filename)),
|
|
404
|
+
"@file_time": datetime.datetime.utcnow().isoformat()}
|
|
405
|
+
if datadict is None:
|
|
406
|
+
datadict = fileattrs
|
|
407
|
+
else:
|
|
408
|
+
datadict.update(fileattrs)
|
|
409
|
+
try:
|
|
410
|
+
dicttonx(datadict, filename)
|
|
411
|
+
self.openDBFile(filename)
|
|
412
|
+
except:
|
|
413
|
+
msgbox = qt.QMessageBox(qt.QMessageBox.Critical,'Cannot create db file',
|
|
414
|
+
'Cannot create file %s.' % filename,
|
|
415
|
+
qt.QMessageBox.Ok, self)
|
|
416
|
+
msgbox.setDetailedText(traceback.format_exc())
|
|
417
|
+
clickedbutton = msgbox.exec()
|
|
418
|
+
|
|
419
|
+
def openDBFile(self, filename):
|
|
420
|
+
if self.nxfile is not None:
|
|
421
|
+
self.hdf5model.removeH5pyObject(self.nxfile)
|
|
422
|
+
self.nxfile.close()
|
|
423
|
+
if hasattr(self, "temp_directory"):
|
|
424
|
+
del self.temp_directory
|
|
425
|
+
self.nxfile = silx.io.h5py_utils.File(filename,'a')
|
|
426
|
+
self._filepath = filename
|
|
427
|
+
while(self.hdf5model.hasPendingOperations()):
|
|
428
|
+
qt.QApplication.processEvents()
|
|
429
|
+
time.sleep(0.01)
|
|
430
|
+
self.hdf5model.insertH5pyObject(self.nxfile)
|
|
431
|
+
self.view.expandToDepth(0)
|
|
432
|
+
|
|
433
|
+
def add_nxdict(self, nxentry):
|
|
434
|
+
if self.nxfile is None:
|
|
435
|
+
raise Exception("No database file open.")
|
|
436
|
+
dicttonx(nxentry, self.nxfile, update_mode='add')
|
|
437
|
+
while(self.hdf5model.hasPendingOperations()):
|
|
438
|
+
qt.QApplication.processEvents()
|
|
439
|
+
time.sleep(0.01)
|
|
440
|
+
self.hdf5model.synchronizeH5pyObject(self.nxfile)
|
|
441
|
+
self.view.expandToDepth(0)
|
|
442
|
+
|
|
443
|
+
def onDeleteScan(self, obj):
|
|
444
|
+
btn = qt.QMessageBox.question(self,"Delete scan?","Are you sure that you want to delete %s from the orgui database?" % obj.name.split("/")[-1])
|
|
445
|
+
if btn == qt.QMessageBox.Yes:
|
|
446
|
+
self.delete_node(obj)
|
|
447
|
+
|
|
448
|
+
def delete_node(self, obj):
|
|
449
|
+
basename = obj.name.split("/")[-1]
|
|
450
|
+
objpar = obj.parent
|
|
451
|
+
del objpar[basename]
|
|
452
|
+
while(self.hdf5model.hasPendingOperations()):
|
|
453
|
+
qt.QApplication.processEvents()
|
|
454
|
+
time.sleep(0.01)
|
|
455
|
+
self.hdf5model.synchronizeH5pyObject(self.nxfile)
|
|
456
|
+
self.view.expandToDepth(0)
|
|
457
|
+
|
|
458
|
+
def onRenameNode(self, obj):
|
|
459
|
+
basename = obj.name.split("/")[-1]
|
|
460
|
+
newname, success = qt.QInputDialog.getText(self,"Rename NEXUS node",
|
|
461
|
+
"New name:", qt.QLineEdit.EchoMode.Normal,
|
|
462
|
+
basename)
|
|
463
|
+
if success and newname != '':
|
|
464
|
+
self.rename_node(obj, newname)
|
|
465
|
+
|
|
466
|
+
def rename_node(self, obj, newname):
|
|
467
|
+
basename = obj.name.split("/")[-1]
|
|
468
|
+
objpar = obj.parent
|
|
469
|
+
objpar.move(basename, newname)
|
|
470
|
+
while(self.hdf5model.hasPendingOperations()):
|
|
471
|
+
qt.QApplication.processEvents()
|
|
472
|
+
time.sleep(0.01)
|
|
473
|
+
self.hdf5model.synchronizeH5pyObject(self.nxfile)
|
|
474
|
+
self.view.expandToDepth(0)
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
def close(self):
|
|
478
|
+
if self.nxfile is not None:
|
|
479
|
+
self.hdf5model.removeH5pyObject(self.nxfile)
|
|
480
|
+
self.nxfile.close()
|
|
481
|
+
self.nxfile = None
|
|
482
|
+
if hasattr(self, "temp_directory"):
|
|
483
|
+
del self.temp_directory
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
|