Commit 22b2b6a0 authored by Damien Naudet's avatar Damien Naudet

Lots of refactoring.

parent e1e4b4f1
This diff is collapsed.
......@@ -3,7 +3,7 @@ import sys
from silx.gui import qt as Qt
print('Using Qt {0}'.format(Qt.qVersion()))
from XsocsMainWindow import XsocsMainWindow
from XsocsGui import XsocsGui
from .MergeWidget import MergeWidget
from .RecipSpaceWidget import RecipSpaceWidget
......@@ -21,6 +21,6 @@ def conversion_window(*args, **kwargs):
def xsocs_main(*args, **kwargs):
app = Qt.QApplication(sys.argv)
mw = XsocsMainWindow(*args, **kwargs)
mw = XsocsGui(*args, **kwargs)
mw.show()
app.exec_()
# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2016 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ###########################################################################*/
from __future__ import absolute_import
__authors__ = ["D. Naudet"]
__license__ = "MIT"
__date__ = "15/09/2016"
from functools import partial
from silx.gui import qt as Qt
import h5py
from silx.gui.hdf5 import Hdf5TreeModel
from silx.gui import icons
from . import ItemClassDef
from .ProjectItem import ProjectItem, ItemEvent
class HybridItemEvent(ItemEvent):
def plotData(self):
eventType = self.type
if eventType == 'scatter':
return self.item.getScatter()
if eventType == 'image':
return self.item.getImage()
return None
class HybridItemDelegate(Qt.QWidget):
sigEditorEvent = Qt.Signal(object)
def __init__(self, parent, option, index):
super(HybridItemDelegate, self).__init__(parent)
self.__index = Qt.QPersistentModelIndex(index)
layout = Qt.QHBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
icon = icons.getQIcon('item-1dim')
bn = Qt.QToolButton()
bn.setIcon(icon)
bn.clicked.connect(partial(self.__onClicked, type='scatter'))
layout.addWidget(bn, Qt.Qt.AlignLeft)
icon = icons.getQIcon('item-2dim')
bn = Qt.QToolButton()
bn.setIcon(icon)
bn.clicked.connect(partial(self.__onClicked, type='image'))
layout.addWidget(bn, Qt.Qt.AlignLeft)
layout.addStretch(1)
# self.setAutoFillBackground(True)
# layout.setSizeConstraint(Qt.QLayout.SetMinimumSize)
def __onClicked(self, checked, type=None):
obj = self.__index.data(Hdf5TreeModel.H5PY_OBJECT_ROLE)
instance = ProjectItem.load(obj.file.filename, obj.name)
event = HybridItemEvent(instance, type)
self.sigEditorEvent.emit(event)
def sizeHint(self):
print super(HybridItem, self).sizeHint()
return Qt.QSize(0, 0)
# def sizeHint(self):
# # TODO connect to cell resize
# if self.__sizeHint:
# return self.parent().sizeHint()
# # return Qt.QSize(self.__sizeHint)
# return super(XsocsProjectDataGroupDelegate, self).sizeHint()
@ItemClassDef('HybridItem', editor=HybridItemDelegate)
class HybridItem(ProjectItem):
viewShowChildren = False
icon = 'item-2dim'
def __init__(self, *args, **kwargs):
super(HybridItem, self).__init__(*args, **kwargs)
def setScatter(self, x, y, data=None):
self._commit(scatter=(x, y, data))
def setImage(self, x, y, data):
self._commit(image=(x, y, data))
# def setImageFromScatter(self, xSlice, ySlice):
# self._commit(imageSlice=(xSlice, ySlice))
def getScatter(self):
with h5py.File(self.file, 'r') as h5f:
grp = h5f.get(self.path)
if grp is None:
return None
scatterPath = grp.attrs.get('XsocsScatter')
if scatterPath is None:
return None
scatterGrp = grp[scatterPath]
# TODO : checks
x = scatterGrp.get('x')
y = scatterGrp.get('y')
data = scatterGrp.get('data')
x = x and x[:]
y = y and y[:]
data = data and data[:]
return x, y, data
def getImage(self):
with h5py.File(self.file, 'r') as h5f:
grp = h5f.get(self.path)
if grp is None:
return None
imagePath = grp.attrs.get('XsocsImage')
if imagePath is None:
return None
imageGrp = grp[imagePath]
# TODO : checks
x = imageGrp.get('x')
y = imageGrp.get('y')
data = imageGrp.get('data')
if x:
if x.shape == ():
x = x[()]
if isinstance(x, h5py.RegionReference):
x = h5f[x][x]
else:
x = x[:]
if y.shape == ():
y = y[()]
if isinstance(y, h5py.RegionReference):
y = h5f[y][y]
else:
y = y[:]
reshape = imageGrp.attrs.get('XsocsShape')
data = data and data[:]
if reshape is not None:
data.shape = reshape
return x, y, data
def _commit(self,
scatter=None,
image=None,
cube=None,
imageSlice=None):
super(HybridItem, self)._commit()
# TODO : check if data already exists in file.
with h5py.File(self.file, 'a') as h5f:
grp = h5f.require_group(self.path)
if scatter:
x, y, data = scatter
scatterGrp = grp.require_group('scatter')
scatterGrp['x'] = x
scatterGrp['y'] = y
if data is not None:
grp['scatter/data'] = data
grp.attrs.update({'XsocsScatter': 'scatter'})
if image:
x, y, data = image
grp['image/data'] = data
grp['image/x'] = x
grp['image/y'] = y
grp.attrs.update({'XsocsImage': 'image'})
elif imageSlice:
xSlice, ySlice = imageSlice
dataSet = grp.get('scatter/data')
if dataSet is None:
raise ValueError('Cant convert scatter to image : '
'no data.')
xSet = grp.get('scatter/x')
ySet = grp.get('scatter/y')
x = xSet.regionref[xSlice]
y = ySet.regionref[ySlice]
xShape = xSet[x].shape
yShape = ySet[y].shape
if len(xShape) != 1 or len(yShape) != 1:
raise ValueError('Invalid slice shapes x:{0}, y:{1}.'
''.format(xShape, yShape))
imageGrp = grp.require_group('image')
imageGrp['x'] = x
imageGrp['y'] = y
imageGrp['data'] = dataSet
print imageGrp['x'], x
imageGrp.attrs.update({'XsocsShape': [yShape[0],
xShape[0]]})
grp.attrs.update({'XsocsImage': 'image'})
if cube:
grp.attrs.update({'XsocsCube': 'cube'})
# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2016 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ###########################################################################*/
from __future__ import absolute_import
__authors__ = ["D. Naudet"]
__license__ = "MIT"
__date__ = "15/09/2016"
import h5py
_registeredItems = {}
def getItemClass(itemName):
return _registeredItems.get(itemName)
def registerItemClass(klass):
global _registeredItems
itemName = klass.itemName
if itemName in _registeredItems:
raise AttributeError('Failed to register item class {0}.'
'attribute is already registered.'
''.format(klass.__name__))
# TODO : some kind of checks on the klass
_registeredItems[itemName] = klass
def ItemClassDef(itemName, editor=None):
def inner(cls):
cls.itemName = itemName
cls.editor = editor
registerItemClass(cls)
return cls
return inner
class ProjectItem(object):
itemName = None
editor = None
viewShowChildren = True
icon = None
XsocsNone, XsocsInput, XsocsQSpace, XsocsFit = range(4)
def __init__(self, h5File, nodePath, processLevel=None):
# TODO : check if parent already has a child with the same name
super(ProjectItem, self).__init__()
self.__nodePath = nodePath
self.__h5File = h5File
self.__processLevel = processLevel or ProjectItem.XsocsNone
path = property(lambda self: self.__nodePath)
file = property(lambda self: self.__h5File)
dataLevel = property(lambda self: self.__dataLevel)
def _commit(self):
with h5py.File(self.file, 'a') as h5f:
grp = h5f.require_group(self.path)
grp.attrs.update({'XsocsType': self.itemName})
grp.attrs.update({'XsocsLevel': self.__processLevel or 'None'})
@classmethod
def load(cls, h5File, groupPath):
with h5py.File(h5File, 'r') as h5f:
grp = h5f[groupPath]
xsocsType = grp.attrs.get('XsocsType')
if xsocsType is None:
return None
klass = _registeredItems.get(xsocsType)
if klass is None:
return None
instance = klass(h5File, groupPath)
return instance
class ItemEvent(object):
def __init__(self, item, eventType):
super(ItemEvent, self).__init__()
self.__item = item
self.__type = eventType
def plotData(self):
raise NotImplementedError('')
type = property(lambda self: self.__type)
item = property(lambda self: self.__item)
# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2016 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ###########################################################################*/
from __future__ import absolute_import
__authors__ = ["D. Naudet"]
__license__ = "MIT"
__date__ = "15/09/2016"
from silx.gui import qt as Qt
from silx.gui.hdf5 import Hdf5TreeModel
from silx.gui import icons
from . import getItemClass
def itemTypeFromIndex(index):
obj = index.data(Hdf5TreeModel.H5PY_OBJECT_ROLE)
xsocsType = obj.attrs.get('XsocsType')
return xsocsType
def itemClassFromIndex(index):
xsocsType = itemTypeFromIndex(index)
xsocsClass = getItemClass(xsocsType)
return xsocsClass
def itemEditorFromIndex(index):
xsocsClass = itemClassFromIndex(index)
if xsocsClass:
return xsocsClass.editor
return None
class ProjectModel(Qt.QSortFilterProxyModel):
TypeRole, IsXsocsNode, TypeLast = \
range(Hdf5TreeModel.H5PY_OBJECT_ROLE + 1,
Hdf5TreeModel.H5PY_OBJECT_ROLE + 4)
def __init__(self, parent=None):
super(ProjectModel, self).__init__(parent)
def columnCount(self, parent=Qt.QModelIndex(), *args, **kwargs):
return 2
def hasChildren(self, parent=Qt.QModelIndex(), *args, **kwargs):
obj = parent.data(Hdf5TreeModel.H5PY_OBJECT_ROLE)
xsocsType = obj.attrs.get('XsocsType')
if xsocsType:
klass = getItemClass(xsocsType)
return klass.viewShowChildren
return super(ProjectModel, self).hasChildren(parent)
# def flags(self, index):
# flags = super(ProjectModel, self).flags(index)
# if _xsocsNodeTypeFromIndex is not None:
# return flags | Qt.Qt.ItemIsEditable
def data(self, index, role=Qt.Qt.DisplayRole):
"""
Reimplemtation of the QSortFilterProxyModel.
Adds the following roles : XsocsTypeRole, XsocsIsXsocsNode.
Filters the DecorationRole for XsocsProjectItems
:param index:
:param role:
:return:
"""
if role == ProjectModel.TypeRole:
obj = index.data(Hdf5TreeModel.H5PY_OBJECT_ROLE)
xsocsType = obj.attrs.get('XsocsType')
return xsocsType
if role == ProjectModel.IsXsocsNode:
obj = index.data(Hdf5TreeModel.H5PY_OBJECT_ROLE)
return ((obj.attrs.get('XsocsType') is not None) and 1) or 0
if role == Qt.Qt.BackgroundRole and \
index.column() == 0 and \
itemTypeFromIndex(index) is not None:
return Qt.QBrush(Qt.QColor(170, 255, 255))
if (index.column() == Hdf5TreeModel.NAME_COLUMN and
role == Qt.Qt.DecorationRole):
obj = index.data(Hdf5TreeModel.H5PY_OBJECT_ROLE)
xsocsType = obj.attrs.get('XsocsType')
if xsocsType:
klass = getItemClass(xsocsType)
if klass:
return icons.getQIcon(klass.icon)
return super(ProjectModel, self).data(index, role)
def filterAcceptsColumn(self, source_column, source_parent):
if source_column in (Hdf5TreeModel.VALUE_COLUMN,
Hdf5TreeModel.NAME_COLUMN):
return True
return False
# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2016 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ###########################################################################*/
from __future__ import absolute_import
__authors__ = ["D. Naudet"]
__license__ = "MIT"
__date__ = "15/09/2016"
from silx.gui import qt as Qt
from .ProjectModel import itemEditorFromIndex
class ProjectView(Qt.QTreeView):
sigItemEvent = Qt.Signal(object)
def __init__(self, parent=None):
super(ProjectView, self).__init__(parent)
delegate = ItemDelegate(self)
self.setItemDelegateForColumn(1, delegate)
delegate.sigDelegateEvent.connect(self.sigItemEvent)
class ItemDelegate(Qt.QStyledItemDelegate):
sigDelegateEvent = Qt.Signal(object)
def __init__(self, parent=None):
super(ItemDelegate, self).__init__(parent)
def createEditor(self, parent, option, index):
editorClass = itemEditorFromIndex(index)
if editorClass is not None:
editor = editorClass(parent, option, index)
editor.sigEditorEvent.connect(self.sigDelegateEvent)
return editor
return super(ItemDelegate, self).createEditor(parent,
option,
index)
\ No newline at end of file
# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2016 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ###########################################################################*/
from __future__ import absolute_import
__authors__ = ["D. Naudet"]
__license__ = "MIT"
__date__ = "15/09/2016"
import numpy as np
from silx.gui import qt as Qt
from silx.gui.hdf5 import Hdf5TreeModel
from ...io import XsocsH5 as _XsocsH5
from .ProjectModel import ProjectModel
from .ProjectView import ProjectView
from .HybridItem import HybridItem
from .ProjectItem import ProjectItem
class XsocsProject(_XsocsH5.XsocsH5Base):
H5_SOURCE_F = '/source/file'
H5_SCAN_PARAMS = '/source/params'
H5_INPUT_DATA = '/input/'
GLOBAL_ENTRY = '_global'
def __init__(self, *args, **kwargs):
super(XsocsProject, self).__init__(*args, **kwargs)
self.__xsocsFile = None
self.__xsocsH5 = None
self.__proxyModel = None
xsocsH5 = property(lambda self: _XsocsH5.XsocsH5(self.xsocsFile)
if self.xsocsFile else None)
""" Returns an XsocsH5 instance if """
def __model(self):
"""
"""
if self.__proxyModel:
return self.__proxyModel
self.__sourceModel = Hdf5TreeModel()
self.__sourceModel.appendFile(self.filename)
self.__proxyModel = ProjectModel()
self.__proxyModel.setSourceModel(self.__sourceModel)
return self.__proxyModel
def view(self, parent=None):
view = ProjectView(parent)
view.setModel(self.__model())
root = view.model().index(0, 0, Qt.QModelIndex())
view.setRootIndex(root)
inputNode = view.model().index(0, 0, root)
view.expand(inputNode)
# view.header().setResizeMode(Qt.QHeaderView.ResizeToContents)
indices = view.model().match(view.model().index(0, 0, inputNode),
ProjectModel.IsXsocsNode,
1,
hits=-1,
flags=(Qt.Qt.MatchExactly |
Qt.Qt.MatchRecursive))
for index in indices:
# had to do this otherwise the openPersistentEditor wouldnt work
idx = view.model().index(index.row(), 1, index.parent())
view.openPersistentEditor(idx)
return view
@property
def xsocsFile(self):
""" The name of the input data file. """
if self.__xsocsFile is None:
with self._get_file() as h5f:
group = h5f.get(XsocsProject.H5_SOURCE_F)
if group:
self.__xsocsFile = group.file.filename
return self.__xsocsFile
@xsocsFile.setter
def xsocsFile(self, xsocs_f):
""" Set the input data file for this Xsocs workspace. The input data
file can only be set once. To use a different data file you have to
create a new workspace. """
# TODO : make sure file exists and is readable
if self.xsocsFile is not None:
raise ValueError('Xsocs input file is already set.')
# adding a link to the source file
self.__xsocsH5 = h5f = _XsocsH5.XsocsH5(xsocs_f)
self.__xsocsFile = xsocs_f
self.add_file_link(XsocsProject.H5_SOURCE_F, xsocs_f, '/')
# adding parameter values to the source folder
entries = h5f.entries()
# TODO : make sure that all parameters are consistent
scan_params = h5f.scan_params(entries[0])
path_tpl = '{0}/{{0}}'.format(XsocsProject.H5_SCAN_PARAMS)
for key, value in scan_params.items():
self._set_scalar_data(path_tpl.format(key), value)
path_tpl = '{0}/{{0}}'.format(XsocsProject.H5_INPUT_DATA)
globalIntensityGrp = HybridItem(self.filename,
path_tpl.format('intensity'),
processLevel=ProjectItem.XsocsInput)
gIntensity = None
gPos_0 = None
gPos_1 = None
gParams = None
gSteps_0 = None
gSteps_1 = None
# adding misc. data
path_tpl = '{0}/entries/{{0}}/{{1}}'.format(XsocsProject.H5_INPUT_DATA)
for entry in entries:
dataGrp = HybridItem(self.filename,
path_tpl.format(entry,
'intensity'),
processLevel=ProjectItem.XsocsInput)
data = h5f.image_cumul(entry)
pos_0, pos_1 = h5f.scan_positions(entry)
# intensity as a scatter plot
dataGrp.setScatter(pos_0, pos_1, data)
# intensity as an image
scan_params = h5f.scan_params(entry)
# xSlice = np.s_[0:scan_params['motor_0_steps']:1]
# ySlice = np.s_[0::scan_params['motor_0_steps']]
# dataGrp.setImageFromScatter(xSlice, ySlice)
steps_0 = scan_params['motor_0_steps']
steps_1 = scan_params['motor_1_steps']
x = np.linspace(scan_params['motor_0_start'],
scan_params['motor_0_end'], steps_0, endpoint=False)
y = np.linspace(scan_params['motor_1_start'],
scan_params['motor_1_end'], steps_1, endpoint=False)
# TODO : check overflow
if gIntensity is None:
# TODO : see if we want to keep the first entry positions,
# or an avg of all of them or ...
gIntensity = data.copy()
gPos_0 = pos_0
gPos_1 = pos_1
gParams = scan_params
gSteps_0 = steps_0
gSteps_1 = steps_1
else:
gIntensity += data
data = data.reshape(steps_1, steps_0)
dataGrp.setImage(x, y, data)
del dataGrp
globalIntensityGrp.setScatter(gPos_0, gPos_1, gIntensity)
x = np.linspace(gParams['motor_0_start'],
gParams['motor_0_end'], gSteps_0, endpoint=False)
y = np.linspace(gParams['motor_1_start'],
gParams['motor_1_end'], gSteps_1, endpoint=False)
gIntensity = gIntensity.reshape(gSteps_1, gSteps_0)