diff --git a/orangecontrib/tomwer/widgets/reconstruction/AxisOW.py b/orangecontrib/tomwer/widgets/reconstruction/AxisOW.py
index aa1a3f8925580051ef8b3349683ced0f3d6a5671..a976a277fb46da80e46a00c4de2d8efd86d602e4 100644
--- a/orangecontrib/tomwer/widgets/reconstruction/AxisOW.py
+++ b/orangecontrib/tomwer/widgets/reconstruction/AxisOW.py
@@ -37,7 +37,7 @@ from tomwer.core.process.reconstruction.axis import AxisProcess
 from tomwer.synctools.ftseries import QReconsParams
 from tomwer.gui.ftserie.axis import AxisWindow
 from tomwer.core.scan.scanbase import TomoBase
-
+import functools
 import logging
 
 logger = logging.getLogger(__name__)
@@ -96,6 +96,21 @@ class AxisOW(widget.OWWidget, AxisProcess):
         if _connect_handler:
             self.settingsHandler.addCallback(self._updateSettingsVals)
 
+        # connect Signal / Slot
+        self._widget.sigComputationRequested.connect(self.__compute)
+        self._widget.sigApply.connect(self.__validate)
+
+    def __compute(self):
+        self.__lastAxisProcessParamsCache = self.recons_params.to_dict()
+        AxisProcess.process(self, self.__scan)
+
+    def __validate(self):
+        # if parameters has changed since last processing, reprocess axis method
+        if self.recons_params.to_dict() != self.__lastAxisProcessParamsCache:
+            self.__compute()
+
+        self.signalReady(self.__scan)
+
     def signalReady(self, scanID):
         assert isinstance(scanID, TomoBase)
         self.send("data", scanID)
@@ -110,6 +125,7 @@ class AxisOW(widget.OWWidget, AxisProcess):
             assert scan.tomo_recons_params.axis is not None
             self.signalReady(scan_res)
         else:
+            self.__scan = scan
             self.exec()
 
     def _updateSettingsVals(self):
diff --git a/tomwer/app/axis.py b/tomwer/app/axis.py
index 1350e69ec0f58b13faab2024c7b3a9c64537cc00..a32c6034e2f586554588726642a62760ec246e4d 100644
--- a/tomwer/app/axis.py
+++ b/tomwer/app/axis.py
@@ -1,27 +1,32 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 
+import os
+import sys
 import argparse
 from silx.gui import qt
 import logging
 import signal
+import functools
 from tomwer.utils import getMainSplashScreen
 from tomwer.gui.ftserie.axis.axis import AxisWindow
 from tomwer.core.scan.scanfactory import ScanFactory
 from tomwer.synctools.ftseries import QReconsParams
-import os
-import sys
-
 from tomwer.core.process.reconstruction.axis import AxisProcess
 
 
 class _AxisProcessGUI(AxisProcess, AxisWindow):
-    def __init__(self):
+    def __init__(self, scan):
         recons_params = QReconsParams()
         AxisProcess.__init__(self, recons_params=recons_params.axis)
         AxisWindow.__init__(self, axis=recons_params)
         self._lockBut.hide()
         self._lockLabel.hide()
+        self._applyBut.hide()
+
+        # connect Signal / Slot
+        callback = functools.partial(self.process, scan)
+        self.sigComputationRequested.connect(callback)
 
 
 def main(argv):
@@ -59,8 +64,7 @@ def main(argv):
 
     scan = ScanFactory.create_scan_object(scan_path=options.scan_path)
 
-    window = _AxisProcessGUI()
-    window.process(scan=scan)
+    window = _AxisProcessGUI(scan=scan)
     splash.finish(window)
     window.show()
     app.exec_()
diff --git a/tomwer/gui/ftserie/axis/axis.py b/tomwer/gui/ftserie/axis/axis.py
index fe81283304bb1ee01223d832d4ee262f2adbbbf1..490633fe908e3bd88d9afbee697c6d12d0e93cda 100644
--- a/tomwer/gui/ftserie/axis/axis.py
+++ b/tomwer/gui/ftserie/axis/axis.py
@@ -69,6 +69,13 @@ class AxisWindow(qt.QMainWindow):
         widget.setImages(imgA=imgA, imgB=imgB, flipB=False)
         widget.show()
     """
+
+    sigComputationRequested = qt.Signal()
+    """signal emitted when a computation is requested"""
+
+    sigApply = qt.Signal()
+    """signal emitted when the axis reconstruction parameters are validated"""
+
     def __init__(self, axis, parent=None):
         qt.QMainWindow.__init__(self, parent)
         if isinstance(axis, _QAxisRP):
@@ -110,7 +117,6 @@ class AxisWindow(qt.QMainWindow):
         self._buttons.layout().addWidget(self._lockBut)
         self._lockLabel = qt.QLabel('lock axis position', parent=self)
         self._buttons.layout().addWidget(self._lockLabel)
-        self._lockBut.toggled.connect(self._lockAxisPosition)
 
         spacer = qt.QWidget(self)
         spacer.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Minimum)
@@ -118,12 +124,19 @@ class AxisWindow(qt.QMainWindow):
 
         self._computeBut = qt.QPushButton('compute', parent=self)
         self._buttons.layout().addWidget(self._computeBut)
+        style = qt.QApplication.style()
+        applyIcon = style.standardIcon(qt.QStyle.SP_DialogApplyButton)
+        self._applyBut = qt.QPushButton(applyIcon, 'validate', parent=self)
+        self._buttons.layout().addWidget(self._applyBut)
+
         self._controlWidget.layout().addWidget(self._buttons)
 
         # signal / slot connection
         self._controlWidget.sigShiftChanged.connect(self._updateShift)
         self._controlWidget.sigRoiChanged.connect(self._updateShift)
         self._controlWidget.sigAuto.connect(self._updateAuto)
+        self._lockBut.toggled.connect(self._lockAxisPosition)
+        self._computeBut.pressed.connect(self._computationRequested)
 
         # expose API
         self.getXShift = self._controlWidget.getXShift
@@ -141,6 +154,9 @@ class AxisWindow(qt.QMainWindow):
         # adapt gui to the axis value
         self.setReconsParams(axis=self.__recons_params)
 
+    def _computationRequested(self):
+        self.sigComputationRequested.emit()
+
     def _lockAxisPosition(self, lock):
         raise NotImplementedError()