From fc53f5a7334f5597bce9f140d2114f4c8dc6b201 Mon Sep 17 00:00:00 2001 From: Sergey Yaroslavtsev Date: Mon, 11 May 2026 23:19:51 +0200 Subject: [PATCH 1/4] extra elif for flatten data --- src/PyMca5/PyMcaIO/HDF5Stack1D.py | 73 +++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 4 deletions(-) diff --git a/src/PyMca5/PyMcaIO/HDF5Stack1D.py b/src/PyMca5/PyMcaIO/HDF5Stack1D.py index a90df4d3a..99b887230 100644 --- a/src/PyMca5/PyMcaIO/HDF5Stack1D.py +++ b/src/PyMca5/PyMcaIO/HDF5Stack1D.py @@ -340,10 +340,12 @@ def loadFileList(self, filelist, selection, scanlist=None): and (len(yDataset.shape) > 1): #keep the original arrangement but in memory self.data = numpy.zeros(yDataset.shape, self.__dtype) + print("setting", self.data) considerAsImages = True else: # force arrangement as spectra self.data = numpy.zeros((dim0, dim1, mcaDim), self.__dtype) + print("else setting", self.data) DONE = False except (MemoryError, ValueError): # some versions report ValueError instead of MemoryError @@ -352,6 +354,7 @@ def loadFileList(self, filelist, selection, scanlist=None): if mSelection is not None: _logger.warning("Ignoring monitor") self.data = yDataset + print("except setting", self.data) if mSelection is not None: mdtype = tmpHdf[mpath].dtype if mdtype not in [numpy.float64, numpy.float32]: @@ -428,7 +431,7 @@ def loadFileList(self, filelist, selection, scanlist=None): else: del mcaObjectPaths["elapsed_time"] else: - # we have to have as many elpased times as MCA spectra + # we have to have as many elapsed times as MCA spectra _time = numpy.zeros((self.data.shape[0] * self.data.shape[1]), numpy.float32) if "calibration" in mcaObjectPaths: @@ -689,6 +692,7 @@ def loadFileList(self, filelist, selection, scanlist=None): n += 1 else: n += tmp.shape[1] * tmp.shape[2] + print('size of datsaet before cleaning', yDataset.shape) yDataset = None if dim0 == 1: self.onProgress(j) @@ -800,6 +804,8 @@ def loadFileList(self, filelist, selection, scanlist=None): # try to get scales scaleList = [] if xSelectionList is not None: + # McaIndex not always eqaul mcaIndex + stackMcaIndex = self.info.get("McaIndex", mcaIndex) if len(xDatasetList) == 1: xDataset = xDatasetList[0] if xDataset.size == shape[self.info['McaIndex']]: @@ -807,6 +813,34 @@ def loadFileList(self, filelist, selection, scanlist=None): self.x = [xDataset.reshape(-1)] else: _logger.warning("Ignoring channels selection %s" % xSelectionList) + elif len(xDatasetList) in (2, 3) and len(xDatasetList[0]) == len(xDatasetList[1]) == self.data.shape[1]: + # assuming flatten positioners + # assuming providing spatial coordinates + origin_x, origin_y = self.shortenScales(xDatasetList[0], xDatasetList[1]) + if origin_x.size > 1: + delta = numpy.mean(origin_x[1:] - origin_x[:-1], dtype=numpy.float32) + else: + delta = 1.0 + xScale = [origin_x, delta] + + if origin_y.size > 1: + delta = numpy.mean(origin_y[1:] - origin_y[:-1], dtype=numpy.float32) + else: + delta = 1.0 + yScale = [origin_y, delta] + + scaleList = [xScale, yScale] + + if len(xDatasetList) == 2: + pass + elif len(xDatasetList) == 3 and xDatasetList[2].size == shape[self.info['McaIndex']]: + # assuming providing spatial coordinates and channels + self.x = [xDatasetList[2].reshape(-1)] + else: + _logger.warning("Coordinates were applied, but channels could not be") + _logger.warning("Ignoring channels selection %s" % xSelectionList) + + elif len(xDatasetList) == len(self.data.shape): # assuming providing spatial coordinates and channels goodScale = 0 @@ -823,7 +857,7 @@ def loadFileList(self, filelist, selection, scanlist=None): for i in range(len(self.data.shape)): dataset = xDatasetList[i].reshape(-1) datasize = self.data.shape[i] - if i == mcaIndex: + if i == stackMcaIndex: self.x = [dataset] else: origin = dataset[0] @@ -842,8 +876,8 @@ def loadFileList(self, filelist, selection, scanlist=None): _logger.warning("Ignoring dimension selections %s" % xSelectionList) elif len(xDatasetList) == (len(self.data.shape) - 1): scaleList = [] - for i in range(len(self.data.shape)): - if i == mcaIndex: + for i in range(len(xDatasetList)): + if i == stackMcaIndex: continue dataset = xDatasetList[i].reshape(-1) datasize = self.data.shape[i] @@ -921,6 +955,37 @@ def loadFileList(self, filelist, selection, scanlist=None): self.info["xScale"] = xScale self.info["yScale"] = yScale + def shortenScales(self, A, B): + A = numpy.asarray(A) + B = numpy.asarray(B) + + # Detect which array is the fast-changing one + if abs(A[1] - A[0]) > abs(B[1] - B[0]): + fast = A + slow = B + fast_is_A = True + else: + fast = B + slow = A + fast_is_A = False + + # Find repetition length n in the slow array + first = slow[0] + n = numpy.where(slow != first)[0][0] + + # Shorten coordinates + short_fast = fast[:n] + short_slow = slow[::n] + + if fast_is_A: + X_sh = short_fast + Y_sh = short_slow + else: + X_sh = short_slow + Y_sh = short_fast + + return X_sh, Y_sh + def getDimensions(self, nFiles, nScans, shape, index=None): #somebody may want to overwrite this """ From 8acc5ebd58b7ae0abdba3a2f08a2a00fdae53fdd Mon Sep 17 00:00:00 2001 From: Sergey Yaroslavtsev Date: Mon, 11 May 2026 23:41:17 +0200 Subject: [PATCH 2/4] Scale are scalar not full array --- src/PyMca5/PyMcaIO/HDF5Stack1D.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/PyMca5/PyMcaIO/HDF5Stack1D.py b/src/PyMca5/PyMcaIO/HDF5Stack1D.py index 99b887230..16fad570c 100644 --- a/src/PyMca5/PyMcaIO/HDF5Stack1D.py +++ b/src/PyMca5/PyMcaIO/HDF5Stack1D.py @@ -340,12 +340,10 @@ def loadFileList(self, filelist, selection, scanlist=None): and (len(yDataset.shape) > 1): #keep the original arrangement but in memory self.data = numpy.zeros(yDataset.shape, self.__dtype) - print("setting", self.data) considerAsImages = True else: # force arrangement as spectra self.data = numpy.zeros((dim0, dim1, mcaDim), self.__dtype) - print("else setting", self.data) DONE = False except (MemoryError, ValueError): # some versions report ValueError instead of MemoryError @@ -354,7 +352,6 @@ def loadFileList(self, filelist, selection, scanlist=None): if mSelection is not None: _logger.warning("Ignoring monitor") self.data = yDataset - print("except setting", self.data) if mSelection is not None: mdtype = tmpHdf[mpath].dtype if mdtype not in [numpy.float64, numpy.float32]: @@ -692,7 +689,6 @@ def loadFileList(self, filelist, selection, scanlist=None): n += 1 else: n += tmp.shape[1] * tmp.shape[2] - print('size of datsaet before cleaning', yDataset.shape) yDataset = None if dim0 == 1: self.onProgress(j) @@ -818,16 +814,16 @@ def loadFileList(self, filelist, selection, scanlist=None): # assuming providing spatial coordinates origin_x, origin_y = self.shortenScales(xDatasetList[0], xDatasetList[1]) if origin_x.size > 1: - delta = numpy.mean(origin_x[1:] - origin_x[:-1], dtype=numpy.float32) + delta_x = numpy.mean(origin_x[1:] - origin_x[:-1], dtype=numpy.float32) else: - delta = 1.0 - xScale = [origin_x, delta] + delta_x = 1.0 + xScale = [origin_x[0], delta_x] if origin_y.size > 1: - delta = numpy.mean(origin_y[1:] - origin_y[:-1], dtype=numpy.float32) + delta_y = numpy.mean(origin_y[1:] - origin_y[:-1], dtype=numpy.float32) else: - delta = 1.0 - yScale = [origin_y, delta] + delta_y = 1.0 + yScale = [origin_y[0], delta_y] scaleList = [xScale, yScale] @@ -935,7 +931,7 @@ def loadFileList(self, filelist, selection, scanlist=None): if len(dims) == len(self.data.shape): scaleList = [] for i in range(len(self.data.shape)): - if i == mcaIndex: + if i == self.info['McaIndex']: continue dataset = dims[i] origin = dataset[0] From 9f592b3f0d6b4a3097841f1272fd363bfa1a7cdc Mon Sep 17 00:00:00 2001 From: Sergey Yaroslavtsev Date: Tue, 12 May 2026 17:38:14 +0200 Subject: [PATCH 3/4] add protectin, cleaning, add suggested dimensions to dialog --- src/PyMca5/PyMcaGui/pymca/QStackWidget.py | 3 ++- src/PyMca5/PyMcaIO/HDF5Stack1D.py | 28 +++++++++++++++-------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/PyMca5/PyMcaGui/pymca/QStackWidget.py b/src/PyMca5/PyMcaGui/pymca/QStackWidget.py index 6d79f275b..df754e34a 100644 --- a/src/PyMca5/PyMcaGui/pymca/QStackWidget.py +++ b/src/PyMca5/PyMcaGui/pymca/QStackWidget.py @@ -246,7 +246,8 @@ def setStack(self, *var, **kw): if (1 in self._stack.data.shape) and\ isinstance(self._stack.data, numpy.ndarray): oldshape = self._stack.data.shape - dialog = ImageShapeDialog(self, shape=oldshape[0:2]) + suggested = self._stack.info.get("SuggestedImageShape", oldshape[0:2]) + dialog = ImageShapeDialog(self, shape=suggested) dialog.setModal(True) ret = dialog.exec() if ret: diff --git a/src/PyMca5/PyMcaIO/HDF5Stack1D.py b/src/PyMca5/PyMcaIO/HDF5Stack1D.py index 16fad570c..abf5dc040 100644 --- a/src/PyMca5/PyMcaIO/HDF5Stack1D.py +++ b/src/PyMca5/PyMcaIO/HDF5Stack1D.py @@ -330,7 +330,7 @@ def loadFileList(self, filelist, selection, scanlist=None): if self.__dtype0 is None: if (bytefactor == 8) and (neededMegaBytes < (2*physicalMemory)): # try reading as float32 - print("Forcing the use of float32 data") + _logger.info("Forcing the use of float32 data") self.__dtype = numpy.float32 else: raise MemoryError("Force dynamic loading") @@ -808,10 +808,13 @@ def loadFileList(self, filelist, selection, scanlist=None): # assuming providing channels self.x = [xDataset.reshape(-1)] else: + # user could not set coordiantes for one axis only _logger.warning("Ignoring channels selection %s" % xSelectionList) + + # for dataset of N*M self.data.shape = (1, N, M) + # if positions are flatten then both X, Y, coordinates should be of size N. elif len(xDatasetList) in (2, 3) and len(xDatasetList[0]) == len(xDatasetList[1]) == self.data.shape[1]: - # assuming flatten positioners - # assuming providing spatial coordinates + # assuming providing spatial coordinates (and maybe channels) origin_x, origin_y = self.shortenScales(xDatasetList[0], xDatasetList[1]) if origin_x.size > 1: delta_x = numpy.mean(origin_x[1:] - origin_x[:-1], dtype=numpy.float32) @@ -826,7 +829,8 @@ def loadFileList(self, filelist, selection, scanlist=None): yScale = [origin_y[0], delta_y] scaleList = [xScale, yScale] - + self.info["SuggestedImageShape"] = (len(origin_y), len(origin_x)) + if len(xDatasetList) == 2: pass elif len(xDatasetList) == 3 and xDatasetList[2].size == shape[self.info['McaIndex']]: @@ -955,8 +959,11 @@ def shortenScales(self, A, B): A = numpy.asarray(A) B = numpy.asarray(B) - # Detect which array is the fast-changing one - if abs(A[1] - A[0]) > abs(B[1] - B[0]): + if len(A) == 0 or len(B) == 0: + raise ValueError("Arrays must not be empty") + + # Detect which array is related to the slow motor + if len(B) == 1 or (len(A)>1 and abs(A[1] - A[0]) > abs(B[1] - B[0])): fast = A slow = B fast_is_A = True @@ -966,10 +973,13 @@ def shortenScales(self, A, B): fast_is_A = False # Find repetition length n in the slow array - first = slow[0] - n = numpy.where(slow != first)[0][0] + diff_idx = numpy.where(slow != slow[0])[0] + # Protection if one motor did not move at all + if len(diff_idx) == 0: + n = len(slow) + else: + n = diff_idx[0] - # Shorten coordinates short_fast = fast[:n] short_slow = slow[::n] From b2e7126097cd98cd569e9d0401a32a8c59641159 Mon Sep 17 00:00:00 2001 From: Sergey Yaroslavtsev Date: Wed, 13 May 2026 19:09:52 +0200 Subject: [PATCH 4/4] some renaming and comment correction --- src/PyMca5/PyMcaIO/HDF5Stack1D.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/PyMca5/PyMcaIO/HDF5Stack1D.py b/src/PyMca5/PyMcaIO/HDF5Stack1D.py index abf5dc040..6c1ccaa81 100644 --- a/src/PyMca5/PyMcaIO/HDF5Stack1D.py +++ b/src/PyMca5/PyMcaIO/HDF5Stack1D.py @@ -800,7 +800,7 @@ def loadFileList(self, filelist, selection, scanlist=None): # try to get scales scaleList = [] if xSelectionList is not None: - # McaIndex not always eqaul mcaIndex + # McaIndex not always equal to mcaIndex stackMcaIndex = self.info.get("McaIndex", mcaIndex) if len(xDatasetList) == 1: xDataset = xDatasetList[0] @@ -815,21 +815,20 @@ def loadFileList(self, filelist, selection, scanlist=None): # if positions are flatten then both X, Y, coordinates should be of size N. elif len(xDatasetList) in (2, 3) and len(xDatasetList[0]) == len(xDatasetList[1]) == self.data.shape[1]: # assuming providing spatial coordinates (and maybe channels) - origin_x, origin_y = self.shortenScales(xDatasetList[0], xDatasetList[1]) - if origin_x.size > 1: - delta_x = numpy.mean(origin_x[1:] - origin_x[:-1], dtype=numpy.float32) + grid_x, grid_y = self.shortenScales(xDatasetList[0], xDatasetList[1]) + if grid_x.size > 1: + delta_x = numpy.mean(grid_x[1:] - grid_x[:-1], dtype=numpy.float32) else: delta_x = 1.0 - xScale = [origin_x[0], delta_x] + xScale = [grid_x[0], delta_x] - if origin_y.size > 1: - delta_y = numpy.mean(origin_y[1:] - origin_y[:-1], dtype=numpy.float32) + if grid_y.size > 1: + delta_y = numpy.mean(grid_y[1:] - grid_y[:-1], dtype=numpy.float32) else: delta_y = 1.0 - yScale = [origin_y[0], delta_y] - + yScale = [grid_y[0], delta_y] scaleList = [xScale, yScale] - self.info["SuggestedImageShape"] = (len(origin_y), len(origin_x)) + self.info["SuggestedImageShape"] = (len(grid_y), len(grid_x)) if len(xDatasetList) == 2: pass