diff --git a/sohstationviewer/view/plotting/plotting_widget/plotting_widget.py b/sohstationviewer/view/plotting/plotting_widget/plotting_widget.py
index 2956030825ff312dec677e0165e0e52d2ae33c29..182b79e9054a337a3ff898bc075b84c63880fa89 100644
--- a/sohstationviewer/view/plotting/plotting_widget/plotting_widget.py
+++ b/sohstationviewer/view/plotting/plotting_widget/plotting_widget.py
@@ -1,7 +1,7 @@
 """
 Class of which object is used to plot data
 """
-from typing import List, Optional, Union
+from typing import List, Optional, Union, Tuple
 import math
 import numpy as np
 import matplotlib.text
@@ -71,6 +71,12 @@ class PlottingWidget(QtWidgets.QScrollArea):
         self.min_x = 0
         self.max_x = 0
         """
+        zoom_minmax_list: list of x ranges of zooming. The first range is the
+        original of x ranges. If there is more than one ranges the plotting has
+        been zoomed in.
+        """
+        self.zoom_minmax_list: List[Tuple[float, float]] = []
+        """
         plotting_bot: float - bottom of a current plot, decrease by plot_h
             return from self.get_height() whenever a new plot is added
         """
@@ -349,6 +355,19 @@ class PlottingWidget(QtWidgets.QScrollArea):
         self.zoom_marker2.set_visible(False)
         self.plotting_axes.canvas.draw()
 
+    def zoom_out(self):
+        """
+        Zoom out by setting limit to the previous range when there's at least
+            one zoom-in.
+        """
+        if len(self.zoom_minmax_list) > 1:
+            self.min_x, self.max_x = self.zoom_minmax_list[-2]
+            self.zoom_minmax_list.pop(-1)
+            self.set_lim(is_zoom_in=False)
+            self.zoom_marker1.set_visible(False)
+            self.zoom_marker2.set_visible(False)
+            self.plotting_axes.canvas.draw()
+
     def eventFilter(self, target: QObject, event: QEvent) -> bool:
         """
         Reimplements: QObject.eventFilter()
@@ -587,6 +606,7 @@ class PlottingWidget(QtWidgets.QScrollArea):
     def on_shift_click(self, xdata):
         """
         On shift + left click:
+        if click on the left of a plot, do zoom out to the previous range
         if zoom_marker1 not shown yet:
             + hide ruler
             + connect zoom_marker2 to follow mouse
@@ -597,6 +617,10 @@ class PlottingWidget(QtWidgets.QScrollArea):
 
         :param xdata: float - time value of a channel plot
         """
+        if xdata < self.min_x:
+            # click on left of plot
+            self.zoom_out()
+            return
         if not self.zoom_marker1_shown:
             self.ruler.set_visible(False)
             self.set_ruler_visibled(self.zoom_marker1, xdata)
@@ -673,8 +697,10 @@ class PlottingWidget(QtWidgets.QScrollArea):
                 or min(gap) <= self.min_x <= max(gap)
                 or min(gap) <= self.max_x <= max(gap))
 
-    def set_lim(self, first_time=False):
+    def set_lim(self, first_time=False, is_zoom_in=True):
         """
+        + Append to zoom_minmax_list if called from a zoom_in. First time
+        plotting is considered a zoom_in to create first x range in the list.
         + Re-decimate channel data to get more detail when zoom in
             (get_zoom_data)
         + Update timestamp bar with new ticks info
@@ -683,7 +709,11 @@ class PlottingWidget(QtWidgets.QScrollArea):
 
         :param first_time: bool - flag shows that this set_lim is called the
             fist time for this data set or not.
+        :param is_zoom_in: if set_lim comes from zoom_in task
         """
+        if is_zoom_in:
+            self.zoom_minmax_list.append((self.min_x, self.max_x))
+
         self.plotting_axes.update_timestamp_bar(self.timestamp_bar_top)
         self.plotting_axes.update_timestamp_bar(self.timestamp_bar_bottom)
         if self.gap_bar is not None: