diff --git a/src/est/core/io.py b/src/est/core/io.py
index 7d6c5f11e233ef12d712abde5d022a84798e199e..fed17229b2d862023d96ae801e253ec44810d76b 100644
--- a/src/est/core/io.py
+++ b/src/est/core/io.py
@@ -64,6 +64,8 @@ def read_from_url(
     I2_url: DataUrl | None = None,
     mu_ref_url: DataUrl | None = None,
     is_concatenated: bool = False,
+    skip_concatenated_n_points: int = 0,
+    skip_concatenated_n_spectra: int = 0,
     timeout: float = settings.DEFAULT_READ_TIMEOUT,
 ) -> XASObject:
     """
@@ -89,6 +91,8 @@ def read_from_url(
         I2_url=I2_url,
         mu_ref_url=mu_ref_url,
         is_concatenated=is_concatenated,
+        skip_concatenated_n_points=skip_concatenated_n_points,
+        skip_concatenated_n_spectra=skip_concatenated_n_spectra,
     )
     return read_from_input_information(input_information, timeout=timeout)
 
diff --git a/src/est/core/process/plotspectrumdata.py b/src/est/core/process/plotspectrumdata.py
index fd6a67aadc623a8edfafb759013893c036451f85..50f0a61ddbaf210bcff796a60960d35b8e88647e 100644
--- a/src/est/core/process/plotspectrumdata.py
+++ b/src/est/core/process/plotspectrumdata.py
@@ -106,7 +106,7 @@ class PlotSpectrumData(
     output_names=["plot_data"],
 ):
     def run(self):
-        spectrum = next(iter(self.inputs.xas_obj.spectra.data.flat))
-        self.outputs.plot_data = process_plotspectrumdata(
-            spectrum, plot_names=self.inputs.plot_names
-        )
+        self.outputs.plot_data = [
+            process_plotspectrumdata(spectrum, plot_names=self.inputs.plot_names)
+            for spectrum in self.inputs.xas_obj.spectra.data.flat
+        ]
diff --git a/src/est/core/types/spectra.py b/src/est/core/types/spectra.py
index b23047417abee2b414cb48dda0a18d84960be5c3..17362e7ab4b79584b79ba6acc0a22479965e7ac2 100644
--- a/src/est/core/types/spectra.py
+++ b/src/est/core/types/spectra.py
@@ -141,55 +141,54 @@ class Spectra:
 
         if len(self.data.flat) == 0:
             return None
-        else:
 
-            def allocate_array(relative_to_len):
-                if relative_to_len is not None:
-                    return numpy.zeros((relative_to_len, len(self.data.flat)))
-                else:
-                    return numpy.zeros(len(self.data.flat))
-
-            key = str(data_info)
-            array = None
-            for i_spectrum, spectrum in enumerate(self.data.flat):
-                try:
-                    if "." in key:
-                        subkeys = key.split(".")
-                        key_ = subkeys[-1]
-                        subkeys = subkeys[:-1]
-                        value = get_param(spectrum, subkeys[0])
-                        for subkey in subkeys[1:]:
-                            value = get_param(value, subkey)
-                        value = get_param(value, key_)
-                    else:
-                        value = get_param(spectrum, key)
-                except Exception:
-                    _logger.info("fail to access to {}".format(key))
-                    break
+        def allocate_array(relative_to_len):
+            if relative_to_len is not None:
+                return numpy.zeros((relative_to_len, len(self.data.flat)))
+            else:
+                return numpy.zeros(len(self.data.flat))
+
+        key = str(data_info)
+        array = None
+        for i_spectrum, spectrum in enumerate(self.data.flat):
+            try:
+                if "." in key:
+                    subkeys = key.split(".")
+                    key_ = subkeys[-1]
+                    subkeys = subkeys[:-1]
+                    value = get_param(spectrum, subkeys[0])
+                    for subkey in subkeys[1:]:
+                        value = get_param(value, subkey)
+                    value = get_param(value, key_)
                 else:
-                    if isinstance(value, pint.Quantity):
-                        value = value.m_as(ur.eV)
-                    if symboltable is not None and isinstance(value, symboltable.Group):
-                        _logger.info("pass larch details, not managed for now")
-                        continue
-                    # create array if necessary
-                    if array is None:
-                        if relative_to is None:
-                            array = allocate_array(relative_to_len=None)
-                        elif value is None:
-                            array = allocate_array(relative_to_len=None)
-                        else:
-                            array = allocate_array(relative_to_len=len(value))
-                    if relative_to is not None:
-                        array[:, i_spectrum] = value
-                    else:
-                        array[i_spectrum] = value
-            shape = list(self.data.shape)
-            shape.insert(0, -1)
+                    value = get_param(spectrum, key)
+            except Exception:
+                _logger.info("fail to access to {}".format(key))
+                break
+
+            if isinstance(value, pint.Quantity):
+                value = value.m_as(ur.eV)
+            if symboltable is not None and isinstance(value, symboltable.Group):
+                _logger.info("pass larch details, not managed for now")
+                continue
+
             if array is None:
-                return array
+                if relative_to is None or value is None:
+                    array = allocate_array(relative_to_len=None)
+                else:
+                    array = allocate_array(relative_to_len=len(value))
+
+            if relative_to is not None:
+                array[:, i_spectrum] = value
             else:
-                return array.reshape(shape)
+                array[i_spectrum] = value
+
+        if array is None:
+            return array
+
+        shape = list(self.data.shape)
+        shape.insert(0, -1)
+        return array.reshape(shape)
 
     def keys(self) -> tuple:
         """
diff --git a/src/est/core/types/xasobject.py b/src/est/core/types/xasobject.py
index 118bc1e0015810367019a6dd8d5ff66cf8fab25e..4de131bd4e60e9c1b31adcdd32d994059a4ecd70 100644
--- a/src/est/core/types/xasobject.py
+++ b/src/est/core/types/xasobject.py
@@ -180,7 +180,7 @@ class XASObject:
         return res
 
     def absorbed_beam(self) -> numpy.ndarray:
-        return self.spectra.map_to(data_info="mu")
+        return self.spectra.map_to("mu")
 
     def load_from_dict(self, ddict: dict) -> XASObject:
         """load XAS values from a dict"""
diff --git a/src/est/core/utils/converter.py b/src/est/core/utils/converter.py
index 2e811d07c45339980c5aa5b086f1ea6c360aabb6..0d3deced3084ded0f14068fda65ff5f593143f6b 100644
--- a/src/est/core/utils/converter.py
+++ b/src/est/core/utils/converter.py
@@ -32,7 +32,7 @@ class Converter:
         )
         # TODO: prendre normalized_mu and normalized_energy if exists,
         # otherwise take mu and energy...
-        spectra = xas_object.spectra.map_to(data_info="mu")
+        spectra = xas_object.spectra.map_to("mu")
         # invert dimensions and axis to fit spectroscopy add-on
         X = spectra.reshape((spectra.shape[0], -1))
         X = numpy.swapaxes(X, 0, 1)
diff --git a/src/est/gui/XasObjectViewer.py b/src/est/gui/XasObjectViewer.py
index 649985d29341dca07696c9de44185f321994a204..c6667826e5f3144ca2d8bf0a6b3155773c94a4be 100644
--- a/src/est/gui/XasObjectViewer.py
+++ b/src/est/gui/XasObjectViewer.py
@@ -212,9 +212,7 @@ class MapViewer(qt.QWidget):
         if self._xasObj is None:
             return
         # set the map view
-        spectra_volume = self._xasObj.spectra.map_to(
-            data_info=self.getActiveKey(),
-        )
+        spectra_volume = self._xasObj.spectra.map_to(self.getActiveKey())
         self._mainWindow.setStack(spectra_volume)
 
     def getPlot(self):
diff --git a/src/est/gui/xas_object_definition/dialog.py b/src/est/gui/xas_object_definition/dialog.py
index 3a2d3f56e4e128f6ad8538a9f45312feffb99a60..3bbd35fbb30090ec127873b70d0d908c71233608 100644
--- a/src/est/gui/xas_object_definition/dialog.py
+++ b/src/est/gui/xas_object_definition/dialog.py
@@ -196,6 +196,8 @@ class XASObjectDialog(qt.QWidget):
             I2_url=advanceHDF5Info.getI2Url(),
             mu_ref_url=advanceHDF5Info.getMuRefUrl(),
             is_concatenated=self._h5Dialog.isSpectraConcatenated(),
+            skip_concatenated_n_points=self._h5Dialog.getSkipConcatenatedNPoints(),
+            skip_concatenated_n_spectra=self._h5Dialog.getSkipConcatenatedNSpectra(),
         )
 
     def getChannelUrl(self):
@@ -210,3 +212,9 @@ class XASObjectDialog(qt.QWidget):
 
     def setConcatenatedSpectra(self, value: bool):
         self._h5Dialog.setConcatenatedSpectra(value)
+
+    def setSkipConcatenatedNPoints(self, value: int):
+        self._h5Dialog.setSkipConcatenatedNPoints(value)
+
+    def setSkipConcatenatedNSpectra(self, value: int):
+        self._h5Dialog.setSkipConcatenatedNSpectra(value)
diff --git a/src/est/gui/xas_object_definition/hdf5.py b/src/est/gui/xas_object_definition/hdf5.py
index b93f8536545e10c5f9ff6332505c5c8c04368a11..6984c8c88571ca18bcc73c6f6fa4cd804f4f1c14 100644
--- a/src/est/gui/xas_object_definition/hdf5.py
+++ b/src/est/gui/xas_object_definition/hdf5.py
@@ -72,6 +72,18 @@ class XASObjectFromH5(qt.QTabWidget):
     def setConcatenatedSpectra(self, value: bool):
         self._basicInformation._concatenatedCheckbox.setChecked(value)
 
+    def getSkipConcatenatedNPoints(self):
+        return self._basicInformation._skipConcatenatedNPoints.value()
+
+    def setSkipConcatenatedNPoints(self, value: int):
+        self._basicInformation._skipConcatenatedNPoints.setValue(value)
+
+    def getSkipConcatenatedNSpectra(self):
+        return self._basicInformation._skipConcatenatedNSpectra.value()
+
+    def setSkipConcatenatedNSpectra(self, value: int):
+        self._basicInformation._skipConcatenatedNSpectra.setValue(value)
+
 
 class _MandatoryXASObjectInfo(qt.QWidget):
     """Widget containing mandatory information"""
@@ -89,15 +101,42 @@ class _MandatoryXASObjectInfo(qt.QWidget):
 
         self._bufWidget = qt.QWidget(parent=self)
         self._bufWidget.setLayout(qt.QHBoxLayout())
+
+        # Spacer to push elements
         spacer = qt.QWidget(parent=self)
         spacer.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Minimum)
         self._bufWidget.layout().addWidget(spacer)
+
+        # Dimension selection widget
         self._dimensionSelection = _SpectraDimensions(parent=self._bufWidget)
         self._bufWidget.layout().addWidget(self._dimensionSelection)
+
+        # Concatenated checkbox
         self._concatenatedCheckbox = qt.QCheckBox(
             "Concatenated spectra", parent=self._bufWidget
         )
         self._bufWidget.layout().addWidget(self._concatenatedCheckbox)
+
+        # Labels and spin boxes
+        self._concatenatedWidget = qt.QWidget(parent=self)
+        self._concatenatedWidget.setLayout(qt.QVBoxLayout())
+
+        label1 = qt.QLabel("Skip first N concatenated spectra", parent=self._bufWidget)
+        self._skipConcatenatedNSpectra = qt.QSpinBox(parent=self._bufWidget)
+        self._concatenatedWidget.layout().addWidget(label1)
+        self._concatenatedWidget.layout().addWidget(self._skipConcatenatedNSpectra)
+
+        label2 = qt.QLabel(
+            "Skip N first and last points of concatenated spectra",
+            parent=self._bufWidget,
+        )
+        self._skipConcatenatedNPoints = qt.QSpinBox(parent=self._bufWidget)
+        self._concatenatedWidget.layout().addWidget(label2)
+        self._concatenatedWidget.layout().addWidget(self._skipConcatenatedNPoints)
+
+        self._bufWidget.layout().addWidget(self._concatenatedWidget)
+
+        # Add buffer widget to main layout
         self.layout().addWidget(self._bufWidget, 1, 1)
 
         # channel/energy url
@@ -122,19 +161,29 @@ class _MandatoryXASObjectInfo(qt.QWidget):
         self._configSelector._qLineEdit.editingFinished.connect(self._editingIsFinished)
         self._dimensionSelection.sigDimensionChanged.connect(self._editingIsFinished)
         self._energyUnit.currentIndexChanged.connect(self._editingIsFinished)
-        self._concatenatedCheckbox.clicked.connect(self._onBidimensionalCheckboxChange)
+        self._concatenatedCheckbox.stateChanged.connect(
+            self._onConcatenatedCheckboxChange
+        )
+        self._skipConcatenatedNPoints.valueChanged.connect(self._editingIsFinished)
+        self._skipConcatenatedNSpectra.valueChanged.connect(self._editingIsFinished)
 
         # expose API
         self.setDimensions = self._dimensionSelection.setDimensions
         self.getDimensions = self._dimensionSelection.getDimensions
 
-    def _onBidimensionalCheckboxChange(self):
-        self._dimensionSelection.setDisabled(self._concatenatedCheckbox.isChecked())
+        self._syncConcatenatedCheckbox()
+
+    def _syncConcatenatedCheckbox(self):
+        concatenated = self._concatenatedCheckbox.isChecked()
+        self._concatenatedWidget.setEnabled(concatenated)
+        self._dimensionSelection.setDisabled(concatenated)
+
+    def _onConcatenatedCheckboxChange(self):
+        self._syncConcatenatedCheckbox()
         self._editingIsFinished()
 
     def getSpectraUrl(self):
         """
-
         :return: the DataUrl of the spectra
         :rtype: DataUrl
         """
@@ -142,7 +191,6 @@ class _MandatoryXASObjectInfo(qt.QWidget):
 
     def getEnergyUrl(self):
         """
-
         :return: the DataUrl of energy / channel
         :rtype: DataUrl
         """
diff --git a/src/est/io/concatenated.py b/src/est/io/concatenated.py
index 0e7f8a36bae54978efe81ed6920fd44aa524d4bf..156f9bac5a8030763dbe60dddc818fd127a94305 100644
--- a/src/est/io/concatenated.py
+++ b/src/est/io/concatenated.py
@@ -1,5 +1,10 @@
 from __future__ import annotations
+
+from typing import Tuple, Dict, Any
+
+import pint
 import numpy
+import numpy.ma
 
 from est import settings
 from est.io.information import InputInformation
@@ -10,14 +15,14 @@ from est.core.monotonic import piecewise_monotonic_interpolation_values
 
 def read_concatenated_xas(
     information: InputInformation, timeout: float = settings.DEFAULT_READ_TIMEOUT
-):
+) -> Tuple[numpy.ndarray, pint.Quantity, Dict[str, Any]]:
     """
     Method to read spectra acquired with the energy ramping up and down, with any number of repetitions.
 
-    When the scan is uni-directional, the ramp is always up. When the scan is concatenated the ramp is
+    When the scan is uni-directional, the ramp is always up. When the scan is bi-directional the ramp is
     alternating up and down.
 
-    The spectra are then interpolated to produce a 3D spectra (nb_energy_pts, nb_of_ramps, 1)
+    The spectra are then interpolated to produce a 3D data aray (nb_energy_pts, nb_of_ramps, 1).
 
     Limitations: the original spectra and energy datasets must be 1D.
     """
@@ -30,18 +35,30 @@ def read_concatenated_xas(
         config = None
 
     ramp_slices = split_piecewise_monotonic(raw_energy)
+
     energy = piecewise_monotonic_interpolation_values(raw_energy, ramp_slices)
 
-    interpolated_spectra = numpy.zeros(
+    if information.skip_concatenated_n_spectra:
+        ramp_slices = ramp_slices[information.skip_concatenated_n_spectra :]
+
+    interpolated_spectra = numpy.ma.masked_all(
         (len(energy), len(ramp_slices), 1), dtype=raw_spectra.dtype
     )
     for i, ramp_slice in enumerate(ramp_slices):
-        interpolated_spectra[:, i, 0] = numpy.interp(
+        raw_energy_i = raw_energy[ramp_slice]
+        raw_spectrum_i = raw_spectra[ramp_slice]
+        if information.skip_concatenated_n_points:
+            raw_spectrum_i[: information.skip_concatenated_n_points] = numpy.nan
+            raw_spectrum_i[-information.skip_concatenated_n_points :] = numpy.nan
+        spectrum_i = numpy.interp(
             energy,
-            raw_energy[ramp_slice],
-            raw_spectra[ramp_slice],
+            raw_energy_i,
+            raw_spectrum_i,
             left=numpy.nan,
             right=numpy.nan,
         )
+        interpolated_spectra[:, i, 0] = numpy.ma.masked_array(
+            spectrum_i, mask=~numpy.isfinite(spectrum_i)
+        )
 
     return interpolated_spectra, energy * information.energy_unit, config
diff --git a/src/est/io/information.py b/src/est/io/information.py
index c33d0df6b3445a84e25daee157d4be2e2faeb724..b84493896418f880b8de06720b28e02636228990 100644
--- a/src/est/io/information.py
+++ b/src/est/io/information.py
@@ -23,6 +23,8 @@ class InputInformation:
         I2_url: DataUrl | None = None,
         mu_ref_url: DataUrl | None = None,
         is_concatenated: bool = False,
+        skip_concatenated_n_points: int = 0,
+        skip_concatenated_n_spectra: int = 0,
     ):
         # main information
         self.spectra_url = spectra_url
@@ -31,6 +33,8 @@ class InputInformation:
         self.dimensions = dimensions_mod.parse_dimensions(dimensions)
         self.energy_unit = energy_unit
         self.is_concatenated = is_concatenated
+        self.skip_concatenated_n_points = skip_concatenated_n_points
+        self.skip_concatenated_n_spectra = skip_concatenated_n_spectra
 
         # "fancy information"
         self.I0_url = I0_url
@@ -56,6 +60,8 @@ class InputInformation:
             "I2_url": dump_url(self.I2_url),
             "mu_ref_url": dump_url(self.mu_ref_url),
             "is_concatenated": self.is_concatenated,
+            "skip_concatenated_n_points": self.skip_concatenated_n_points,
+            "skip_concatenated_n_spectra": self.skip_concatenated_n_spectra,
         }
 
     @staticmethod
@@ -79,4 +85,6 @@ class InputInformation:
             I2_url=load_url("I2_url"),
             mu_ref_url=load_url("mu_ref_url"),
             is_concatenated=ddict.get("is_concatenated", False),
+            skip_concatenated_n_points=ddict.get("skip_concatenated_n_points", 0),
+            skip_concatenated_n_spectra=ddict.get("skip_concatenated_n_spectra", 0),
         )
diff --git a/src/est/tests/test_plotspectrumdata.py b/src/est/tests/test_plotspectrumdata.py
index e17d5d3d8ea5c16eda779d4483e758aa7cb8e337..2805b96d51332e7da40a80e316ba345e8d2196c8 100644
--- a/src/est/tests/test_plotspectrumdata.py
+++ b/src/est/tests/test_plotspectrumdata.py
@@ -66,8 +66,12 @@ def test_larch_plotspectrumdata(filename_cu_from_pymca):
     )
 
     result = execute_graph(_LARCH_WORKFLOW, inputs=inputs)
-    assert len(result["plot_data"]) == 7
-    for name, data in result["plot_data"].items():
+    assert len(result["plot_data"]) == 1
+
+    scan_data = result["plot_data"][0]
+
+    assert len(scan_data) == 7
+    for name, data in scan_data.items():
         if name in ("chi", "chi_weighted_k"):
             n = 324
         elif name == "ft_mag":
@@ -79,13 +83,13 @@ def test_larch_plotspectrumdata(filename_cu_from_pymca):
         assert data["xlabel"]
         assert data["ylabel"]
 
-    assert "k^2" in result["plot_data"]["chi_weighted_k"]["ylabel"]
+    assert "k^2" in scan_data["chi_weighted_k"]["ylabel"]
 
     if False:
         import matplotlib.pyplot as plt
 
         fig, axs = plt.subplots(2, 3, figsize=(10, 10), constrained_layout=True)
-        for data, ax in zip(result["plot_data"].values(), axs.flatten()):
+        for data, ax in zip(scan_data.values(), axs.flatten()):
             ax.plot(data["x"], data["y"])
             ax.set_xlabel(data["xlabel"])
             ax.set_ylabel(data["ylabel"])
diff --git a/src/est/tests/test_roi.py b/src/est/tests/test_roi.py
index 47b710e9dc5066e2ad744934a337abf7cdcebdf9..750dc2f2ea6e552ebde72315eb8203ddc568811e 100644
--- a/src/est/tests/test_roi.py
+++ b/src/est/tests/test_roi.py
@@ -22,7 +22,7 @@ def test_roi(tmpdir):
         dimensions=(2, 1, 0),
     )
 
-    original_spectra = xas_obj.spectra.map_to(data_info="mu").copy()
+    original_spectra = xas_obj.spectra.map_to("mu").copy()
     assert original_spectra.shape == (16, 100, 30)
     res_xas_obj = xas_roi(
         xas_obj,
@@ -30,6 +30,6 @@ def test_roi(tmpdir):
         roi_size=(10, 20),
     )
     assert res_xas_obj.n_spectrum == 20 * 10
-    reduces_spectra = res_xas_obj.spectra.map_to(data_info="mu").copy()
+    reduces_spectra = res_xas_obj.spectra.map_to("mu").copy()
     assert reduces_spectra.shape == (16, 20, 10)
     numpy.testing.assert_array_equal(original_spectra[:, 50:70, 20:30], reduces_spectra)
diff --git a/src/est/tests/test_types.py b/src/est/tests/test_types.py
index 5bc0f4f40687440360acc6e1e1773b4d9ffd8800..9fdc0ef8fa36da3add90fac4caa883d33fbdd9fb 100644
--- a/src/est/tests/test_types.py
+++ b/src/est/tests/test_types.py
@@ -75,7 +75,7 @@ def test_create_from_several_spectrums(tmpdir):
     )
     obj2 = XASObject.from_dict(ddict)
     assert xas_obj.n_spectrum == obj2.n_spectrum
-    obj2_mu_spectra = obj2.spectra.map_to(data_info="mu")
+    obj2_mu_spectra = obj2.spectra.map_to("mu")
 
     numpy.testing.assert_array_equal(original_spectra, obj2_mu_spectra)
     assert obj2 == xas_obj
diff --git a/src/est/tests/test_xas_object.py b/src/est/tests/test_xas_object.py
index ddba00414b501d0f5ebff0b4e7c6430de077b757..79f1116c7e4fee8a621b45cfa1ea435309e694c9 100644
--- a/src/est/tests/test_xas_object.py
+++ b/src/est/tests/test_xas_object.py
@@ -66,7 +66,7 @@ def test_create_from_several_spectrums(serialize_data):
     )
     obj2 = XASObject.from_dict(ddict)
     assert xas_obj.n_spectrum == obj2.n_spectrum
-    obj2_mu_spectra = obj2.spectra.map_to(data_info="mu")
+    obj2_mu_spectra = obj2.spectra.map_to("mu")
 
     numpy.testing.assert_array_equal(original_spectra, obj2_mu_spectra)
     assert obj2 == xas_obj
diff --git a/src/orangecontrib/est/widgets/utils/xas_input.py b/src/orangecontrib/est/widgets/utils/xas_input.py
index 53cefd60146af629fa5a10c4a0729a4b36a7ac32..37dc07ad22f38ba2cbcba0c8e8b53e4c67b1b79b 100644
--- a/src/orangecontrib/est/widgets/utils/xas_input.py
+++ b/src/orangecontrib/est/widgets/utils/xas_input.py
@@ -80,10 +80,15 @@ class XASInputOW(OWEwoksWidgetNoThread, ewokstaskclass=ReadXasObject):
                 self._inputDialog.setEnergyUrl(input_information.channel_url)
             if input_information.mu_ref_url is not None:
                 advanceHDF5Info.setMuRefUrl(input_information.mu_ref_url)
-            if input_information.is_concatenated is not None:
-                self._inputDialog.getMainWindow().setConcatenatedSpectra(
-                    input_information.is_concatenated
-                )
+            self._inputDialog.getMainWindow().setSkipConcatenatedNPoints(
+                input_information.skip_concatenated_n_points
+            )
+            self._inputDialog.getMainWindow().setSkipConcatenatedNSpectra(
+                input_information.skip_concatenated_n_spectra
+            )
+            self._inputDialog.getMainWindow().setConcatenatedSpectra(
+                input_information.is_concatenated
+            )
         else:
             input_type = est.io.InputType.ascii_spectrum
             self._inputDialog.setAsciiFile(input_information.spectra_url.file_path())