Commit d083ee5d authored by Damien Naudet's avatar Damien Naudet

Added some conversion info to the tree (qspace node).

parent 1681525c
......@@ -25,10 +25,7 @@ image_binning = [4, 4]
# positions (on the sample) to convert to qspace
# if pos_indices will be ignored if rect_roi is provided
# rect_roi = [x_min, x_max, y_min, y_max] (sample positions)
# pos_indices = array with indices (of the sample positions array)
# to convert to qspace
roi = None
sample_indices = None
# set to true if you want to overwrite the output file
# otherwise an exception will be raised if the file already exists
......@@ -43,6 +40,5 @@ kmap_2_qspace(xsocs_h5,
qspace_dims,
image_binning=image_binning,
roi=roi,
sample_indices=sample_indices,
n_proc=n_proc,
overwrite=overwrite)
......@@ -182,7 +182,6 @@ class H5Base(Node):
return newChildren
def _refreshNode(self):
diff = set()
with h5py.File(self.h5File) as h5f:
thisItem = h5f[self.h5Path]
try:
......
......@@ -34,6 +34,7 @@ import weakref
from silx.gui import qt as Qt, icons
from ..model.Node import Node
from ..model.ModelDef import ModelColumns
from ..model.NodeEditor import EditorMixin
......@@ -44,9 +45,13 @@ from .Hdf5Nodes import H5GroupNode, H5NodeClassDef, H5DatasetNode
from ..view.FitView import FitView
from ..view.QspaceView import QSpaceView
from ..view.intensity.IntensityView import IntensityView
from ..project.QSpaceGroup import QSpaceItem
from ..project.ProjectItem import ProjectItem
from ..project.IntensityGroup import IntensityGroup
class ScatterPlotButton(EditorMixin, Qt.QWidget):
persistent = True
......@@ -134,10 +139,133 @@ class IntensityNode(H5DatasetNode):
Qt.Qt.DisplayRole)
class QSpaceInfoNode(Node):
"""
Simple node displaying the qspace conversion parameters.
"""
icons = Qt.QStyle.SP_FileDialogInfoView
def _loadChildren(self):
# This node is created by a QSpaceItemNode, which is a H5Node
# and H5Node have themselves as subject, and the groupClasses
# inherit their parent's subject.
qspaceNode = self.subject
qspaceItem = ProjectItem(qspaceNode.h5File, qspaceNode.h5Path).cast()
children = []
if not isinstance(qspaceItem, QSpaceItem):
node = Node(nodeName='Error, invalid file.')
icon = Qt.qApp.style().standardIcon(
Qt.QStyle.SP_MessageBoxCritical)
node.setData(0, icon, Qt.Qt.DecorationRole)
return [node]
qspaceH5 = qspaceItem.qspaceH5
##################################################
# Adding selected/discarded entries.
##################################################
selected = qspaceH5.selected_entries
discarded = qspaceH5.discarded_entries
# support for previous versions.
# TODO : remove sometimes...
if selected is None or len(selected) == 0:
selected = qspaceItem.projectRoot().xsocsH5.entries()
if discarded is None:
discarded = []
nSelected = len(selected)
nDiscarded = len(discarded)
selectedList = Node(nodeName='Selected entries')
selectedList.setData(0,
'Entries used for the conversion.',
role=Qt.Qt.ToolTipRole)
selectedList.setData(ModelColumns.ValueColumn,
'{0}'.format(nSelected))
for entry in selected:
node = Node(nodeName=entry)
selectedList.appendChild(node)
children.append(selectedList)
discardedList = Node(nodeName='Discarded entries')
discardedList.setData(0,
'Discarded input entries.',
role=Qt.Qt.ToolTipRole)
discardedList.setData(ModelColumns.ValueColumn,
'{0}'.format(nDiscarded))
for entry in discarded:
node = Node(nodeName=entry)
discardedList.appendChild(node)
children.append(discardedList)
##################################################
# Adding ROI info
##################################################
sampleRoi = qspaceH5.sample_roi
toolTip = """<ul>
<li>xMin : {0:.7g}
<li>xMax : {1:.7g}
<li>yMin : {2:.7g}
<li>yMax : {3:.7g}
</ul>
""".format(*sampleRoi)
roiNode = Node(nodeName='Roi')
text = '{0:6g}, {1:6g}, {2:6g}, {3:6g}'.format(*sampleRoi)
roiNode.setData(ModelColumns.ValueColumn, text)
roiNode.setData(ModelColumns.NameColumn, toolTip, Qt.Qt.ToolTipRole)
node = Node(nodeName='xMin')
node.setData(ModelColumns.ValueColumn, '{0:.7g}'.format(sampleRoi[0]))
roiNode.appendChild(node)
node = Node(nodeName='xMax')
node.setData(ModelColumns.ValueColumn, '{0:.7g}'.format(sampleRoi[1]))
roiNode.appendChild(node)
node = Node(nodeName='yMin')
node.setData(ModelColumns.ValueColumn, '{0:.7g}'.format(sampleRoi[2]))
roiNode.appendChild(node)
node = Node(nodeName='yMax')
node.setData(ModelColumns.ValueColumn, '{0:.7g}'.format(sampleRoi[3]))
roiNode.appendChild(node)
children.append(roiNode)
##################################################
# Adding image binning.
##################################################
node = Node(nodeName='Image binning')
imageBinning = qspaceH5.image_binning
# support for previous versions
# TODO : remove eventualy
if imageBinning is None:
text = 'unavailable'
else:
text = '{0}x{1}'.format(*imageBinning)
node.setData(ModelColumns.ValueColumn, text)
children.append(node)
##################################################
# Adding qspace dims.
##################################################
qspaceDimsNode = Node(nodeName='Qspace size')
qspaceDims = qspaceH5.qspace_dimensions
# support for previous versions
# TODO : remove eventualy
text = '{0}x{1}x{2} (qx, qy, qz)'.format(*qspaceDims)
qspaceDimsNode.setData(ModelColumns.ValueColumn, text)
children.append(qspaceDimsNode)
return children
@H5NodeClassDef('QSpaceItem',
attribute=('XsocsClass', 'QSpaceItem'))
class QSpaceItemNode(H5GroupNode):
editors = QSpaceButton
groupClasses = [('Infos', QSpaceInfoNode)]
def __init__(self, *args, **kwargs):
super(QSpaceItemNode, self).__init__(*args, **kwargs)
......@@ -157,6 +285,14 @@ class QSpaceItemNode(H5GroupNode):
self.__viewWidget = view
return view()
def _loadChildren(self):
# dirty hack to remove a legacy group from appearing in the tree
# TODO : to be removed eventualy
children = super(QSpaceItemNode, self)._loadChildren()
filtered = [child for child in children
if os.path.basename(child.h5Path) != 'info']
return filtered
class FitButton(EditorMixin, Qt.QWidget):
persistent = True
......
......@@ -103,25 +103,28 @@ class QSpaceItem(ProjectItem):
if qspaceFile is None:
return
with QSpaceH5(qspaceFile) as qspaceH5:
with self:
pathTpl = self.path + '/info/{0}'
with qspaceH5.qspace_dset_ctx() as ctx:
shape = np.array(ctx.shape)
itemPath = pathTpl.format('#')
self._set_scalar_data(itemPath, shape[0])
itemPath = pathTpl.format('shape')
self._set_array_data(itemPath, shape[1:])
qx = qspaceH5.qx
qy = qspaceH5.qy
qz = qspaceH5.qz
itemPath = pathTpl.format('qx range')
self._set_array_data(itemPath, np.array([qx[0], qx[-1]]))
itemPath = pathTpl.format('qy range')
self._set_array_data(itemPath, np.array([qy[0], qy[-1]]))
itemPath = pathTpl.format('qz range')
self._set_array_data(itemPath, np.array([qz[0], qz[-1]]))
# with QSpaceH5(qspaceFile) as qspaceH5:
# with self:
# pathTpl = self.path + '/info/{0}'
# with qspaceH5.qspace_dset_ctx() as ctx:
# shape = np.array(ctx.shape)
# itemPath = pathTpl.format('# points')
# self._set_scalar_data(itemPath, shape[0])
# itemPath = pathTpl.format('qspace dims')
# self._set_array_data(itemPath, shape[1:])
# qx = qspaceH5.qx
# qy = qspaceH5.qy
# qz = qspaceH5.qz
# itemPath = pathTpl.format('qx range')
# self._set_array_data(itemPath, np.array([qx[0], qx[-1]]))
# itemPath = pathTpl.format('qy range')
# self._set_array_data(itemPath, np.array([qy[0], qy[-1]]))
# itemPath = pathTpl.format('qz range')
# self._set_array_data(itemPath, np.array([qz[0], qz[-1]]))
FitGroup(self.filename,
self.path + '/' + QSpaceItem.FitGroupPath,
mode=self.mode)
\ No newline at end of file
mode=self.mode)
if __name__ == '__main__':
pass
......@@ -103,6 +103,60 @@ class QSpaceH5(XsocsH5Base):
image_shape = property(lambda self:
self._get_array_data(QSpaceH5.image_shape_path))
@property
def selected_entries(self):
"""
Returns the input entries used for the conversion.
:return:
"""
path = self.entries_path + '/selected'
entries = self._get_array_data(path)
if entries is not None:
return [entry.decode() for entry in entries]
return []
@property
def discarded_entries(self):
"""
Returns the input entries that were not used for the conversion.
:return:
"""
path = self.entries_path + '/discarded'
entries = self._get_array_data(path)
if entries is not None:
return [entry.decode() for entry in entries]
return []
@property
def image_binning(self):
"""
Returns the image binning used when converting to q space.
:return:
"""
path = self.params_path + '/image_binning'
return self._get_array_data(path)
@property
def sample_roi(self):
"""
Returns the sample area selected for conversion (sample coordinates).
:return: 4 elements array : xMin, xMax, yMin, yMax
"""
path = self.params_path + '/sample_roi'
sample_roi = self._get_array_data(path)
if sample_roi is None:
return [_np.nan, _np.nan, _np.nan, _np.nan]
return sample_roi
@property
def qspace_dimensions(self):
"""
Returns the dimensions of the qspace cubes
:return:
"""
with self.qspace_dset_ctx() as dset:
return dset.shape[1:]
class QSpaceH5Writer(QSpaceH5):
cube_dtype = _np.float32
......@@ -213,7 +267,24 @@ class QSpaceH5Writer(QSpaceH5):
:return:
"""
path = self.params_path + '/image_binning'
if image_binning is None or len(image_binning) != 2:
raise ValueError('image_binning must be a 2 elements array : '
'{0}.'.format(image_binning))
self._set_array_data(path, _np.array(image_binning))
def set_sample_roi(self, sample_roi):
"""
Stores the sample area selected for conversion (sample coordinates).
:param sample_roi: 4 elements array : xMin, xMax, yMin, yMax
:return:
"""
path = self.params_path + '/sample_roi'
if sample_roi is None:
sample_roi = [_np.nan, _np.nan, _np.nan, _np.nan]
elif len(sample_roi) != 4:
raise ValueError('sample_roi must be a 4 elements array (or None):'
' {0}.'.format(sample_roi))
self._set_array_data(path, _np.array(sample_roi))
if __name__ == '__main__':
pass
......@@ -86,7 +86,6 @@ class QSpaceConverter(object):
def __init__(self,
xsocsH5_f,
qspace_dims=None,
sample_indices=None,
img_binning=None,
output_f=None,
roi=None,
......@@ -144,7 +143,6 @@ class QSpaceConverter(object):
self.image_binning = img_binning
self.qspace_dims = qspace_dims
self.sample_indices = sample_indices
self.roi = roi
self.__set_status(self.READY)
......@@ -285,27 +283,27 @@ class QSpaceConverter(object):
self.__params['image_binning'] = np.array(image_binning_int,
dtype=np.int32)
@sample_indices.setter
def sample_indices(self, sample_indices):
"""
Binning applied to the image before converting to qspace
"""
if sample_indices is None:
self.__params['sample_indices'] = None
return
sample_indices = np.array(sample_indices, ndmin=1).astype(np.long)
if sample_indices.ndim != 1:
raise ValueError('sample_indices must be a 1D array.')
if len(sample_indices) == 0:
self.__params['sample_indices'] = None
return
# TODO : check values
self.__params['sample_indices'] = np.array(sample_indices,
dtype=np.int32)
# @sample_indices.setter
# def sample_indices(self, sample_indices):
# """
# Binning applied to the image before converting to qspace
# """
# if sample_indices is None:
# self.__params['sample_indices'] = None
# return
#
# sample_indices = np.array(sample_indices, ndmin=1).astype(np.long)
#
# if sample_indices.ndim != 1:
# raise ValueError('sample_indices must be a 1D array.')
#
# if len(sample_indices) == 0:
# self.__params['sample_indices'] = None
# return
#
# # TODO : check values
# self.__params['sample_indices'] = np.array(sample_indices,
# dtype=np.int32)
@roi.setter
def roi(self, roi):
......@@ -461,6 +459,7 @@ class QSpaceConverter(object):
qspace_dims = self.qspace_dims
xsocsH5_f = self.xsocsH5_f
output_f = self.output_f
sample_roi = self.__params['roi']
try:
ta = time.time()
......@@ -683,6 +682,8 @@ class QSpaceConverter(object):
_create_result_file(output_f,
output_shape,
image_binning,
sample_roi,
sample_x[sample_indices],
sample_y[sample_indices],
qx_idx,
......@@ -929,6 +930,7 @@ def _init_thread(idx_queue_,
def _create_result_file(h5_fn,
qspace_dims,
image_binning,
sample_roi,
pos_x,
pos_y,
q_x,
......@@ -984,6 +986,7 @@ def _create_result_file(h5_fn,
qspace_h5.set_qz(q_z)
qspace_h5.set_entries(selected_entries, discarded=discarded_entries)
qspace_h5.set_image_binning(image_binning)
qspace_h5.set_sample_roi(sample_roi)
def _to_qspace(th_idx,
......
......@@ -36,7 +36,6 @@ def kmap_2_qspace(xsocsH5_f,
qspace_dims,
image_binning=(4, 4),
roi=None,
sample_indices=None,
n_proc=None,
overwrite=False):
"""
......@@ -64,12 +63,6 @@ def kmap_2_qspace(xsocsH5_f,
y_max.
:type roi: *optional* `array_like` (x_min, x_max, y_min, y_max)
:param sample_indices: indices of the positions (on the sample) that have
to be converted to qspace. **Ignored** if *roi* is provided.
E.g : if the array [0, 1, 2] is provided, only the first 3 sample
scans positions will be converted to qspace.
:type sample_indices: *optional* `array_like`
:param n_proc: number of process to use. If None, the number of process
used will be the one returned by multiprocessing.cpu_count().
:type n_proc: `int`
......@@ -85,8 +78,6 @@ def kmap_2_qspace(xsocsH5_f,
if roi is not None:
converter.roi = roi
elif sample_indices is not None:
converter.sample_indices = sample_indices
converter.image_binning = image_binning
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment