diff --git a/documentation/01 _ Table of Contents.help.md b/documentation/01 _ Table of Contents.help.md
index f7e158e1eb463f7b419d7f220879acbe094331ae..60e076d08b46d31af4e52b8bcd509a2c73aaefde 100644
--- a/documentation/01 _ Table of Contents.help.md	
+++ b/documentation/01 _ Table of Contents.help.md	
@@ -4,6 +4,8 @@ Welcome to the SOH Station Viewer documentation. Here you will find usage guides
 
 On the left-hand side you will find a list of currently available help topics.
 
+If the links of the Table of Contents are broken, click on Recreate Table of Content <img src='recreate_table_contents.png' height=30 style='margin: 3px 0px 0px 0px;'/> to rebuild it.
+
 The home button can be used to return to this page at any time.
 
 # Table of Contents
@@ -14,19 +16,23 @@ The home button can be used to return to this page at any time.
 
 + [How to Use Help](03%20_%20How%20to%20Use%20Help.help.md)
 
-+ [Search SOH n LOG](04%20_%20Search%20SOH%20n%20LOG.help.md)
++ [Search List of Directories](04%20_%20Search%20List%20of%20Directories.help.md)
+
++ [Read from Data Card](05%20_%20Read%20from%20Data%20Card.help.md)
+
++ [Select SOH](06%20_%20Select%20SOH.help.md)
 
-+ [Search List of Directories](05%20_%20Search%20List%20of%20Directories.help.md)
++ [Select Mass Position](07%20_%20Select%20Mass%20Position.help.md)
 
-+ [Read from Data Card](06%20_%20Read%20from%20Data%20Card.help.md)
++ [Select Waveforms](08%20_%20Select%20Waveforms.help.md)
 
-+ [Select SOH](07%20_%20Select%20SOH.help.md)
++ [Gap Display](09%20_%20Gap%20Display.help.md)
 
-+ [Select Mass Position](08%20_%20Select%20Mass%20Position.help.md)
++ [Change TPS Color Range](10%20_%20Change%20TPS%20Color%20Range.help.md)
 
-+ [Select Waveforms](09%20_%20Select%20Waveforms.help.md)
++ [Save Plots](11%20_%20Save%20Plots.help.md)
 
-+ [Gap Display](10%20_%20Gap%20Display.help.md)
++ [Search SOH n LOG](12%20_%20Search%20SOH%20n%20LOG.help.md)
 
 + [GPS Dialog](20%20_%20GPS%20Dialog.help.md)
 
diff --git a/documentation/05 _ Search List of Directories.help.md b/documentation/04 _ Search List of Directories.help.md
similarity index 100%
rename from documentation/05 _ Search List of Directories.help.md
rename to documentation/04 _ Search List of Directories.help.md
diff --git a/documentation/06 _ Read from Data Card.help.md b/documentation/05 _ Read from Data Card.help.md
similarity index 100%
rename from documentation/06 _ Read from Data Card.help.md
rename to documentation/05 _ Read from Data Card.help.md
diff --git a/documentation/07 _ Select SOH.help.md b/documentation/06 _ Select SOH.help.md
similarity index 100%
rename from documentation/07 _ Select SOH.help.md
rename to documentation/06 _ Select SOH.help.md
diff --git a/documentation/08 _ Select Mass Position.help.md b/documentation/07 _ Select Mass Position.help.md
similarity index 100%
rename from documentation/08 _ Select Mass Position.help.md
rename to documentation/07 _ Select Mass Position.help.md
diff --git a/documentation/09 _ Select Waveforms.help.md b/documentation/08 _ Select Waveforms.help.md
similarity index 100%
rename from documentation/09 _ Select Waveforms.help.md
rename to documentation/08 _ Select Waveforms.help.md
diff --git a/documentation/11 _ Gap Display.help.md b/documentation/09 _ Gap Display.help.md
similarity index 100%
rename from documentation/11 _ Gap Display.help.md
rename to documentation/09 _ Gap Display.help.md
diff --git a/documentation/11 _ Save Plots.help.md b/documentation/11 _ Save Plots.help.md
new file mode 100644
index 0000000000000000000000000000000000000000..0027b76db29eeb97aa0adf7cbe68dc7fa5126b09
--- /dev/null
+++ b/documentation/11 _ Save Plots.help.md	
@@ -0,0 +1,60 @@
+# Save Plots
+
+---------------------------
+---------------------------
+
+## Step 1: click 'Save Plot'
+In Main Window,  Raw Data Plot and TPS Plot there are buttons labeled 'Save Plot'.
+
+User need to click those button to save plots in each window.
+
+* Saving State-of-Health plots
+<br />
+<img alt="Save SOH" src="images/save_plots/save_button_soh.png" height="30" />
+<br />
+* Saving Raw data plots
+<br />
+<img alt="Save Waveform" src="images/save_plots/save_button_wf.png" height="60" />
+<br />
+* Saving Time-power-square plots
+<br />
+<img alt="Save TPS" src="images/save_plots/save_button_tps.png" height="80" />
+<br />
+<br />
+<br />
+
+If the current color mode is black, user will be asked to continue or cancel 
+to change mode before saving the image.
+
+<br />
+<br />
+<img alt="Want to change color mode?" src="images/save_plots/question_on_changing_black_mode.png" height="150" />
+<br />
+
+* If user click 'Cancel'. The process of saving plots will be canceled for user 
+to change mode before restarting saving plots again.
+* If user click 'Continue'. The process of saving plots will be continue and the 
+image will be saved in black mode.
+<br />
+
+---------------------------
+## Step 2: Edit file path and select image's format
+Once clicking on 'Save Plot' button,  the 'Save Plot' dialog will pop up.
+
+<br />
+<br />
+<img alt="Select Image Format dialog" src="images/save_plots/save_file_dialog.png" height="200" />
+<br />
+
++ The default path to save the image file is preset in (1) text box.  If user 
+wants to change the path,  click on 'Save Directory button' to open file dialog 
+for changing path.
++ The default filename to save the image is preset in (2) text box.  User can 
+change the name in this box.
++ In side oval (3) are the radio buttons to select image format to save 
+file.
++ For 'PNG' format,  user can change DPI which is the resolution of the 
+image.  Other formats are vector formats which don't require resolution.
+
+Then user can click 'CANCEL' to cancel saving plot or click 'SAVE PLOT' to save
+the current plots to file.
\ No newline at end of file
diff --git a/documentation/04 _ Search SOH n LOG.help.md b/documentation/12 _ Search SOH n LOG.help.md
similarity index 100%
rename from documentation/04 _ Search SOH n LOG.help.md
rename to documentation/12 _ Search SOH n LOG.help.md
diff --git a/documentation/99 _ test.md b/documentation/99 _ test.md
index 7ef0655b760ac6880ab28c7b87f54ad34c2bb4ae..84fbede232f89c3fc5c6e9c03a105021552adb20 100644
--- a/documentation/99 _ test.md	
+++ b/documentation/99 _ test.md	
@@ -39,7 +39,7 @@ printf("%s\n", syntaxHighlighting.doesItWork ? "Success!" : "Oof.");
 ^ This is a horizontal line
 
 v This is an image
-![An Image?](images/image.jpg)
+![An Image?](recreate_table_contents.png)
 
 ---
 Another horizontal line
diff --git a/documentation/images/save_plots/question_on_changing_black_mode.png b/documentation/images/save_plots/question_on_changing_black_mode.png
new file mode 100644
index 0000000000000000000000000000000000000000..7424afda3387e8cbcad71a7fba63903072d2f23d
Binary files /dev/null and b/documentation/images/save_plots/question_on_changing_black_mode.png differ
diff --git a/documentation/images/save_plots/save_button_soh.png b/documentation/images/save_plots/save_button_soh.png
new file mode 100644
index 0000000000000000000000000000000000000000..588e20ca07de4e9dfde974de414107bb855ac1c8
Binary files /dev/null and b/documentation/images/save_plots/save_button_soh.png differ
diff --git a/documentation/images/save_plots/save_button_tps.png b/documentation/images/save_plots/save_button_tps.png
new file mode 100644
index 0000000000000000000000000000000000000000..1bfe4977370d6b904ff3d63a79bb6a4fbfe67266
Binary files /dev/null and b/documentation/images/save_plots/save_button_tps.png differ
diff --git a/documentation/images/save_plots/save_button_wf.png b/documentation/images/save_plots/save_button_wf.png
new file mode 100644
index 0000000000000000000000000000000000000000..f65ac57c793dd9b43cfd4814e56604eb3f3f3c80
Binary files /dev/null and b/documentation/images/save_plots/save_button_wf.png differ
diff --git a/documentation/images/save_plots/save_file_dialog.png b/documentation/images/save_plots/save_file_dialog.png
new file mode 100644
index 0000000000000000000000000000000000000000..ddb40fe65456a44943792bd94933a88a64556111
Binary files /dev/null and b/documentation/images/save_plots/save_file_dialog.png differ
diff --git a/documentation/img.png b/documentation/img.png
deleted file mode 100644
index 5d8c5a2165cf11862b70318e57343665de6e1a77..0000000000000000000000000000000000000000
Binary files a/documentation/img.png and /dev/null differ
diff --git a/documentation/recreate_table_contents.png b/documentation/recreate_table_contents.png
new file mode 100644
index 0000000000000000000000000000000000000000..34ab02a858eb4da3d62325cff47e1bd56dc90186
Binary files /dev/null and b/documentation/recreate_table_contents.png differ
diff --git a/sohstationviewer/conf/constants.py b/sohstationviewer/conf/constants.py
index 8bd00e091e0c436c87c64027c626cfa716dab02f..d060a1f8a3ac0865a719cddd898f39a6d55dd97e 100644
--- a/sohstationviewer/conf/constants.py
+++ b/sohstationviewer/conf/constants.py
@@ -50,8 +50,11 @@ TABLE_CONTENTS = "01 _ Table of Contents.help.md"
 SEARCH_RESULTS = "Search Results.md"
 
 # the list of all color modes
-ALL_COLOR_MODES = {'B', 'W'}
+ALL_COLOR_MODES = {'B': 'black', 'W': 'white'}
 
+# List of image formats. Have to put PNG at the beginning to go with
+# dpi in dialog
+IMG_FORMAT = ['PNG', 'PDF', 'EPS', 'SVG']
 # ================================================================= #
 #                      PLOTTING CONSTANT
 # ================================================================= #
diff --git a/sohstationviewer/controller/processing.py b/sohstationviewer/controller/processing.py
index 28f3c17269fb45098332e490e9328ce1971051ba..4c34572b75880464d1cbb933b417165f388058e8 100644
--- a/sohstationviewer/controller/processing.py
+++ b/sohstationviewer/controller/processing.py
@@ -139,7 +139,7 @@ def read_mseed_channels(tracking_box: QTextBrowser, list_of_dir: List[str],
                 spr_gr_1_chan_ids.update(ret[3])
     if not on_unittest:
         QApplication.restoreOverrideCursor()
-    return sorted(list(soh_chan_ids)), sorted(list(mass_pos_chan_ids)),\
+    return sorted(list(soh_chan_ids)), sorted(list(mass_pos_chan_ids)), \
         sorted(list(wf_chan_ids)), sorted(list(spr_gr_1_chan_ids))
 
 
diff --git a/sohstationviewer/view/db_config/param_dialog.py b/sohstationviewer/view/db_config/param_dialog.py
index 2fc8c8ad99d312e01857c2d4514062aeb49b4e10..21ecf7bcca7316e30a6b5e7253d7f1ce19ef400b 100755
--- a/sohstationviewer/view/db_config/param_dialog.py
+++ b/sohstationviewer/view/db_config/param_dialog.py
@@ -47,7 +47,7 @@ class ParamDialog(UiDBInfoDialog):
         color_mode_label = QtWidgets.QLabel('Color mode:')
         color_selector = QComboBox()
         color_selector.insertItem(0, initial_color_mode)
-        other_color_modes = ALL_COLOR_MODES - {initial_color_mode}
+        other_color_modes = set(ALL_COLOR_MODES.keys()) - {initial_color_mode}
         color_selector.insertItems(1, other_color_modes)
         color_selector.setFixedWidth(100)
         color_selector.currentTextChanged.connect(self.on_color_mode_changed)
diff --git a/sohstationviewer/view/main_window.py b/sohstationviewer/view/main_window.py
index 55229391942838e45a3383ae4c3cf458eaab4cc8..0f5fdcd435719e19840e5a2ac133ed55bfb4186f 100755
--- a/sohstationviewer/view/main_window.py
+++ b/sohstationviewer/view/main_window.py
@@ -63,9 +63,17 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow):
         """
         self.dir_names: List[Path] = []
         """
-        current_dir: str - the current main data directory
+        current_dir: the current main data directory
         """
-        self.current_dir = ''
+        self.current_dir: str = ''
+        """
+        save_plot_dir: directory to save plot
+        """
+        self.save_plot_dir: str = ''
+        """
+        save_plot_format: format to save plot
+        """
+        self.save_plot_format: str = 'SVG'
         """
         rt130_das_dict: dict by rt130 for data paths, so user can choose
             dasses to assign list of data paths to selected_rt130_paths
@@ -185,6 +193,10 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow):
         self.validate_config()
         self.apply_config()
 
+    @QtCore.Slot()
+    def save_plot(self):
+        self.plotting_widget.save_plot('SOH-Plot')
+
     @QtCore.Slot()
     def open_data_type(self) -> None:
         """
@@ -732,6 +744,10 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow):
         if self.has_problem:
             return
         self.is_plotting_soh = True
+        self.plotting_widget.set_colors(self.color_mode)
+        self.waveform_dlg.plotting_widget.set_colors(self.color_mode)
+        self.tps_dlg.plotting_widget.set_colors(self.color_mode)
+        self.gps_dialog.set_colors(self.color_mode)
 
         d_obj = self.data_object
 
@@ -854,6 +870,7 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow):
         # current directory
         self.current_directory_changed.emit(path)
         self.current_dir = path
+        self.save_plot_dir = path
         execute_db(f'UPDATE PersistentData SET FieldValue="{path}" WHERE '
                    'FieldName="currentDirectory"')
         self.set_open_files_list_texts()
@@ -1072,10 +1089,6 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow):
         if not checked:
             return
         self.color_mode = color_mode
-        self.plotting_widget.set_colors(color_mode)
-        self.waveform_dlg.plotting_widget.set_colors(color_mode)
-        self.tps_dlg.plotting_widget.set_colors(color_mode)
-        self.gps_dialog.set_colors(color_mode)
 
     @QtCore.Slot()
     def clear_file_search(self):
diff --git a/sohstationviewer/view/plotting/plotting_widget/plotting_axes.py b/sohstationviewer/view/plotting/plotting_widget/plotting_axes.py
index 508f96cd256e6277d51c23807a657c1c6a5f3da8..002e0dd6fc613ba135b3df1a919a5894401e2583 100644
--- a/sohstationviewer/view/plotting/plotting_widget/plotting_axes.py
+++ b/sohstationviewer/view/plotting/plotting_widget/plotting_axes.py
@@ -78,6 +78,7 @@ class PlottingAxes:
             labelbottom = False
         else:
             labelbottom = True
+            self.parent.plotting_bot -= 0.007       # space for ticks
         timestamp_bar.tick_params(which='major', length=7, width=2,
                                   direction='inout',
                                   colors=self.parent.display_color['basic'],
@@ -90,7 +91,8 @@ class PlottingAxes:
                                  fontweight='bold',
                                  fontsize=self.parent.font_size,
                                  rotation=0,
-                                 labelpad=constants.HOUR_TO_TMBAR_D,
+                                 labelpad=constants.HOUR_TO_TMBAR_D *
+                                 self.parent.ratio_w,
                                  ha='left',
                                  color=self.parent.display_color['basic'])
         # not show any y ticks
@@ -112,7 +114,8 @@ class PlottingAxes:
         timestamp_bar.set_xticks(times, minor=True)
         timestamp_bar.set_xticks(major_times)
         timestamp_bar.set_xticklabels(major_time_labels,
-                                      fontsize=self.parent.font_size + 2)
+                                      fontsize=self.parent.font_size +
+                                      2 * self.parent.ratio_w)
         timestamp_bar.set_xlim(self.parent.min_x, self.parent.max_x)
 
     def create_axes(self, plot_b, plot_h, has_min_max_lines=True):
@@ -221,7 +224,7 @@ class PlottingAxes:
                 rotation='horizontal',
                 transform=ax.transAxes,
                 color=color,
-                size=self.parent.font_size + 2
+                size=self.parent.font_size + 2 * self.parent.ratio_w
             )
 
         # set samples' total on right side
@@ -352,17 +355,23 @@ class PlottingAxes:
                 )
             )
 
-    def get_height(self, ratio, bw_plots_distance=0.0015):
+    def get_height(self, ratio: float, bw_plots_distance: float = 0.0015,
+                   pixel_height: float = 19) -> float:
         """
         Calculate new plot's bottom position and return plot's height.
 
-        :param ratio: float - ratio of the plot height on the BASIC_HEIGHT
-        :param bw_plots_distance: float - distance between plots
-        :return plot_h: float - height of the plot
+        :param ratio: ratio of the plot height on the BASIC_HEIGHT
+        :param bw_plots_distance: distance between plots
+        :param pixel_height: height of plot in pixel (
+            for TPS/TPS legend, height of each day row)
+
+        :return plot_h: height of the plot
         """
         plot_h = constants.BASIC_HEIGHT * ratio  # ratio with figure height
         self.parent.plotting_bot -= plot_h + bw_plots_distance
-        self.parent.plotting_bot_pixel += 19 * ratio
+        bw_plots_distance_pixel = 3000 * bw_plots_distance
+        self.parent.plotting_bot_pixel += (pixel_height * ratio +
+                                           bw_plots_distance_pixel)
         return plot_h
 
     def add_ruler(self, color):
@@ -403,4 +412,4 @@ class PlottingAxes:
                       horizontalalignment='left',
                       transform=self.parent.timestamp_bar_top.transAxes,
                       color=self.parent.display_color['basic'],
-                      size=self.parent.font_size)
+                      size=self.parent.font_size + 2 * self.parent.ratio_w)
diff --git a/sohstationviewer/view/plotting/plotting_widget/plotting_widget.py b/sohstationviewer/view/plotting/plotting_widget/plotting_widget.py
index 9cc7a78fbcbd701deedda58b3b3f1b1d912900aa..20a8d99105e4b0c73d33577f34776d8d96b93db9 100755
--- a/sohstationviewer/view/plotting/plotting_widget/plotting_widget.py
+++ b/sohstationviewer/view/plotting/plotting_widget/plotting_widget.py
@@ -2,10 +2,10 @@
 Class of which object is used to plot data
 """
 from typing import List, Optional, Union
-
 import matplotlib.text
-from PySide2.QtCore import QTimer, Qt
 from matplotlib import pyplot as pl
+from matplotlib.transforms import Bbox
+from PySide2.QtCore import QTimer, Qt
 from PySide2 import QtCore, QtWidgets
 from PySide2.QtWidgets import QWidget, QApplication, QTextBrowser
 
@@ -18,6 +18,7 @@ from sohstationviewer.view.plotting.plotting_widget.plotting_axes import (
     PlottingAxes
 )
 from sohstationviewer.view.plotting.plotting_widget.plotting import Plotting
+from sohstationviewer.view.save_plot_dialog import SavePlotDialog
 
 from sohstationviewer.controller.plotting_data import format_time
 from sohstationviewer.controller.util import display_tracking_info
@@ -110,6 +111,7 @@ class PlottingWidget(QtWidgets.QScrollArea):
         font_size: float - font size on plot. With some require bigger font,
             +2 to the font_size
         """
+        self.base_font_size = 7
         self.font_size = 7
         """
         bottom: float - y position of the bottom edge of all plots in self.axes
@@ -243,6 +245,7 @@ class PlottingWidget(QtWidgets.QScrollArea):
         # set view size fit with the scroll's view port size
         self.main_widget.setFixedWidth(geo.width())
         self.ratio_w = geo.width() / self.width_base_px
+        self.font_size = self.ratio_w * self.base_font_size
         self.plotting_w = self.ratio_w * self.width_base
         self.plotting_l = self.ratio_w * self.plotting_l_base
         if self.plot_total == 0:
@@ -652,6 +655,57 @@ class PlottingWidget(QtWidgets.QScrollArea):
         """
         self.peer_plotting_widgets = widgets
 
+    def save_plot(self, default_name='plot'):
+        if self.c_mode != self.main_window.color_mode:
+            main_color = constants.ALL_COLOR_MODES[self.main_window.color_mode]
+            curr_color = constants.ALL_COLOR_MODES[self.c_mode]
+            msg = (f"Main window's color mode is {main_color}"
+                   f" but the mode haven't been applied to plotting.\n\n"
+                   f"Do you want to cancel to apply {main_color} mode "
+                   f"by clicking RePlot?\n"
+                   f"Or continue with {curr_color}?")
+            msgbox = QtWidgets.QMessageBox()
+            msgbox.setWindowTitle("Color Mode Conflict")
+            msgbox.setText(msg)
+            msgbox.addButton(QtWidgets.QMessageBox.Cancel)
+            msgbox.addButton('Continue', QtWidgets.QMessageBox.YesRole)
+            result = msgbox.exec_()
+            if result == QtWidgets.QMessageBox.Cancel:
+                return
+            self.main_window.color_mode = self.c_mode
+            if self.c_mode == 'B':
+                self.main_window.background_black_radio_button.setChecked(True)
+            else:
+                self.main_window.background_white_radio_button.setChecked(True)
+        if self.c_mode == 'B':
+            msg = ("The current background mode is black.\n"
+                   "Do you want to cancel to change the background mode "
+                   "before saving the plots to file?")
+            msgbox = QtWidgets.QMessageBox()
+            msgbox.setWindowTitle("Background Mode Confirmation")
+            msgbox.setText(msg)
+            msgbox.addButton(QtWidgets.QMessageBox.Cancel)
+            msgbox.addButton('Continue', QtWidgets.QMessageBox.YesRole)
+            result = msgbox.exec_()
+            if result == QtWidgets.QMessageBox.Cancel:
+                return
+        save_plot_dlg = SavePlotDialog(
+            self.parent, self.main_window, default_name)
+        save_plot_dlg.exec_()
+        save_file_path = save_plot_dlg.save_file_path
+        if save_file_path is None:
+            return
+        dpi = save_plot_dlg.dpi
+
+        self.plotting_axes.fig.savefig(
+            save_file_path,
+            bbox_inches=Bbox([[0, self.plotting_bot*100],
+                              [self.ratio_w*15.5, 100]]),
+            dpi=dpi
+        )
+        msg = f"Graph is saved at {save_file_path}"
+        display_tracking_info(self.tracking_box, msg)
+
     def clear(self):
         self.plotting_axes.fig.clear()
         self.axes = []
diff --git a/sohstationviewer/view/plotting/time_power_squared_dialog.py b/sohstationviewer/view/plotting/time_power_squared_dialog.py
index 1c5acdb972716024206009c925052032f57c0538..dbdaa82f57f03ef74dc7b04e361ba540174ffd1b 100755
--- a/sohstationviewer/view/plotting/time_power_squared_dialog.py
+++ b/sohstationviewer/view/plotting/time_power_squared_dialog.py
@@ -89,8 +89,10 @@ class TimePowerSquaredWidget(plotting_widget.PlottingWidget):
         self.is_working = True
         self.set_key = key
         self.plotting_data1 = d_obj.waveform_data[key]
+        self.plot_total = len(self.plotting_data1)
 
         self.plotting_bot = const.BOTTOM
+        self.plotting_bot_pixel = const.BOTTOM_PX
         self.processed_channels = []
         self.channels = []
         self.tps_processors = []
@@ -111,7 +113,7 @@ class TimePowerSquaredWidget(plotting_widget.PlottingWidget):
             title = get_title(key, self.min_x, self.max_x, self.date_mode)
 
         self.timestamp_bar_top = self.plotting_axes.add_timestamp_bar(0.)
-        self.plotting_axes.set_title(title, y=0, v_align='bottom')
+        self.plotting_axes.set_title(title, y=5, v_align='bottom')
 
         if self.plotting_data1 == {}:
             self.is_working = False
@@ -220,11 +222,12 @@ class TimePowerSquaredWidget(plotting_widget.PlottingWidget):
 
         total_days = c_data['tps_data'].shape[0]
         plot_h = self.plotting_axes.get_height(
-            1.5 * total_days, bw_plots_distance=0.003)
+            total_days/1.5, bw_plots_distance=0.003, pixel_height=12.1)
         ax = self.create_axes(self.plotting_bot, plot_h)
+        ax.spines[['right', 'left', 'top', 'bottom']].set_visible(False)
         ax.text(
-            -0.1, 1.2,
-            f"{get_chan_label(chan_id)} {c_data['samplerate']}",
+            -0.12, 1,
+            f"{get_chan_label(chan_id)} {c_data['samplerate']}sps",
             horizontalalignment='left',
             verticalalignment='top',
             rotation='horizontal',
@@ -234,17 +237,17 @@ class TimePowerSquaredWidget(plotting_widget.PlottingWidget):
         )
 
         zoom_marker1 = ax.plot(
-            [], [], marker='|', markersize=10,
+            [], [], marker='|', markersize=5,
             markeredgecolor=self.display_color['zoom_marker'])[0]
         self.zoom_marker1s.append(zoom_marker1)
 
         zoom_marker2 = ax.plot(
-            [], [], marker='|', markersize=10,
+            [], [], marker='|', markersize=5,
             markeredgecolor=self.display_color['zoom_marker'])[0]
         self.zoom_marker2s.append(zoom_marker2)
 
         ruler = ax.plot(
-            [], [], marker='s', markersize=5,
+            [], [], marker='s', markersize=4,
             markeredgecolor=self.display_color['time_ruler'],
             markerfacecolor='None')[0]
         self.rulers.append(ruler)
@@ -258,8 +261,8 @@ class TimePowerSquaredWidget(plotting_widget.PlottingWidget):
             # not draw data out of day range
             color_set = self.get_color_set(y, square_counts, color_codes)
             # (- dayIdx): each day is a line, increase from top to bottom
-            ax.scatter(x, [- dayIdx] * len(x), marker='|',
-                       c=color_set, s=7, alpha=0.8)
+            ax.scatter(x, [- dayIdx] * len(x), marker='s',
+                       c=color_set, s=3)
         # extra to show highlight square
         ax.set_ylim(-(c_data['tps_data'].shape[0] + 1), 1)
 
@@ -274,11 +277,13 @@ class TimePowerSquaredWidget(plotting_widget.PlottingWidget):
         ax.legend will create one label for each dot.
         """
         # set height of legend and distance bw legend and upper ax
-        plot_h = self.plotting_axes.get_height(7, bw_plots_distance=0.003)
+        plot_h = self.plotting_axes.get_height(
+            21, bw_plots_distance=0.004, pixel_height=12)
         ax = self.plotting_axes.canvas.figure.add_axes(
             [self.plotting_l, self.plotting_bot, self.plotting_w, plot_h],
             picker=True
         )
+        ax.axis('off')
         ax.patch.set_alpha(0)
         c_labels = self.parent.sel_col_labels
         clrs = self.parent.color_def  # colordef
@@ -466,6 +471,7 @@ class TimePowerSquaredWidget(plotting_widget.PlottingWidget):
         with new color range selected.
         """
         self.clear()
+        self.set_colors(self.main_window.color_mode)
         self.plotting_bot = const.BOTTOM
         title = get_title(self.set_key, self.min_x, self.max_x, self.date_mode)
         self.timestamp_bar_top = self.plotting_axes.add_timestamp_bar(0.)
@@ -554,6 +560,7 @@ class TimePowerSquaredDialog(QtWidgets.QWidget):
         """
         self.color_range_choice = QtWidgets.QComboBox(self)
         self.color_range_choice.addItems(self.color_ranges)
+
         self.color_range_choice.setCurrentText('High')
         color_layout.addWidget(self.color_range_choice)
         # ##################### Replot button ########################
@@ -561,8 +568,8 @@ class TimePowerSquaredDialog(QtWidgets.QWidget):
         buttons_layout.addWidget(self.replot_button)
 
         # ##################### Save button ##########################
-        self.save_button = QtWidgets.QPushButton('Save', self)
-        buttons_layout.addWidget(self.save_button)
+        self.save_plot_button = QtWidgets.QPushButton('Save Plot', self)
+        buttons_layout.addWidget(self.save_plot_button)
 
         self.info_text_browser.setFixedHeight(60)
         bottom_layout.addWidget(self.info_text_browser)
@@ -595,7 +602,7 @@ class TimePowerSquaredDialog(QtWidgets.QWidget):
         """
         Connect functions to widgets
         """
-        self.save_button.clicked.connect(self.save)
+        self.save_plot_button.clicked.connect(self.save_plot)
         self.replot_button.clicked.connect(self.plotting_widget.replot)
         self.color_range_choice.currentTextChanged.connect(
             self.color_range_changed)
@@ -612,8 +619,8 @@ class TimePowerSquaredDialog(QtWidgets.QWidget):
         self.sel_col_labels = self.color_label[cr_index]
 
     @QtCore.Slot()
-    def save(self):
+    def save_plot(self):
         """
         Save the plotting to a file
         """
-        print("save")
+        self.plotting_widget.save_plot('TPS-Plot')
diff --git a/sohstationviewer/view/plotting/waveform_dialog.py b/sohstationviewer/view/plotting/waveform_dialog.py
index ba9a2a2cd66f18d3658bacd72751b834901ff404..8a161ab29dfac4a906fe6c3109e3f0338c9a5980 100755
--- a/sohstationviewer/view/plotting/waveform_dialog.py
+++ b/sohstationviewer/view/plotting/waveform_dialog.py
@@ -118,11 +118,11 @@ class WaveformDialog(QtWidgets.QWidget):
         bottom_layout = QtWidgets.QHBoxLayout()
         main_layout.addLayout(bottom_layout)
         """
-        save_button: save plot in plotting_widget to file
+        save_plot_button: save plot in plotting_widget to file
         """
-        self.save_button = QtWidgets.QPushButton('Save', self)
-        self.save_button.clicked.connect(self.save)
-        bottom_layout.addWidget(self.save_button)
+        self.save_plot_button = QtWidgets.QPushButton('Save Plot', self)
+        self.save_plot_button.clicked.connect(self.save_plot)
+        bottom_layout.addWidget(self.save_plot_button)
         self.info_text_browser.setFixedHeight(60)
         bottom_layout.addWidget(self.info_text_browser)
 
@@ -148,11 +148,11 @@ class WaveformDialog(QtWidgets.QWidget):
         self.plotting_widget.init_size()
 
     @QtCore.Slot()
-    def save(self):
+    def save_plot(self):
         """
         Save the plotting to a file
         """
-        print("save")
+        self.plotting_widget.save_plot('Waveform-Plot')
 
     def plot_finished(self):
         self.parent.is_plotting_waveform = False
diff --git a/sohstationviewer/view/save_plot_dialog.py b/sohstationviewer/view/save_plot_dialog.py
new file mode 100644
index 0000000000000000000000000000000000000000..77a988f25a6679ac7ecd3bd4f916ca625d6a97d1
--- /dev/null
+++ b/sohstationviewer/view/save_plot_dialog.py
@@ -0,0 +1,139 @@
+import sys
+import platform
+import os
+from pathlib import Path
+from typing import Union, Optional
+
+from PySide2 import QtWidgets, QtCore, QtGui
+from PySide2.QtWidgets import QApplication, QWidget, QDialog
+
+from sohstationviewer.conf import constants
+
+
+class SavePlotDialog(QDialog):
+    def __init__(self, parent: Union[QWidget, QApplication],
+                 main_window: QApplication,
+                 default_name: str):
+        """
+        Dialog allow choosing file format and open file dialog to
+            save file as
+
+        :param parent: the parent widget
+        :param main_window: to keep path to save file
+        :param default_name: default name for graph file to be saved as
+        """
+        super(SavePlotDialog, self).__init__(parent)
+        self.main_window = main_window
+        """
+        save_file_path: path to save file
+        """
+        self.save_file_path: Optional[Path] = None
+        """
+        save_dir_path: path to save dir
+        """
+        self.save_dir_path: Path = main_window.save_plot_dir
+        """
+        dpi: resolution for png format
+        """
+        self.dpi: int = 100
+
+        self.save_dir_btn = QtWidgets.QPushButton("Save Directory", self)
+        self.save_dir_textbox = QtWidgets.QLineEdit(self.save_dir_path)
+        self.save_filename_textbox = QtWidgets.QLineEdit(default_name)
+
+        self.dpi_line_edit = QtWidgets.QSpinBox(self)
+        self.format_radio_btns = {}
+        for fmt in constants.IMG_FORMAT:
+            self.format_radio_btns[fmt] = QtWidgets.QRadioButton(fmt, self)
+            if fmt == self.main_window.save_plot_format:
+                self.format_radio_btns[fmt].setChecked(True)
+        self.cancel_btn = QtWidgets.QPushButton('CANCEL', self)
+        self.continue_btn = QtWidgets.QPushButton('SAVE PLOT', self)
+
+        self.setup_ui()
+        self.connect_signals()
+
+    def setup_ui(self) -> None:
+        self.setWindowTitle("Save Plot")
+
+        main_layout = QtWidgets.QGridLayout()
+        self.setLayout(main_layout)
+
+        main_layout.addWidget(self.save_dir_btn, 0, 0, 1, 1)
+        self.save_dir_textbox.setFixedWidth(500)
+        main_layout.addWidget(self.save_dir_textbox, 0, 1, 1, 5)
+        main_layout.addWidget(QtWidgets.QLabel('Save Filename'),
+                              1, 0, 1, 1)
+        main_layout.addWidget(self.save_filename_textbox, 1, 1, 1, 5)
+
+        main_layout.addWidget(QtWidgets.QLabel('DPI'),
+                              2, 2, 1, 1, QtGui.Qt.AlignRight)
+        self.dpi_line_edit.setRange(50, 300)
+        self.dpi_line_edit.setValue(100)
+        main_layout.addWidget(self.dpi_line_edit, 2, 3, 1, 1)
+        rowidx = 2
+        for fmt in self.format_radio_btns:
+            main_layout.addWidget(self.format_radio_btns[fmt], rowidx, 1, 1, 1)
+            rowidx += 1
+
+        main_layout.addWidget(self.cancel_btn, rowidx, 1, 1, 1)
+        main_layout.addWidget(self.continue_btn, rowidx, 3, 1, 1)
+
+    def connect_signals(self) -> None:
+        self.save_dir_btn.clicked.connect(self.change_save_directory)
+        self.cancel_btn.clicked.connect(self.close)
+        self.continue_btn.clicked.connect(self.on_continue)
+
+    @QtCore.Slot()
+    def change_save_directory(self) -> None:
+        """
+        Show a file selection window and change the GPS data save directory
+        based on the folder selected by the user.
+        """
+        fd = QtWidgets.QFileDialog(self)
+        fd.setFileMode(QtWidgets.QFileDialog.Directory)
+        fd.setDirectory(self.save_dir_textbox.text())
+        fd.exec_()
+        new_path = fd.selectedFiles()[0]
+        self.save_dir_textbox.setText(new_path)
+        self.save_dir_path = new_path
+        self.main_window.save_plot_dir = new_path
+
+    @QtCore.Slot()
+    def on_continue(self):
+        if self.save_dir_textbox.text().strip() == '':
+            QtWidgets.QMessageBox.warning(
+                self, "Add Directory",
+                "A directory need to be given before continue.")
+            return
+
+        if self.save_filename_textbox.text().strip() == '':
+            QtWidgets.QMessageBox.warning(
+                self, "Add Filename",
+                "A file name need to be given before continue.")
+            return
+
+        for img_format in self.format_radio_btns:
+            if self.format_radio_btns[img_format].isChecked():
+                save_format = img_format
+                self.main_window.save_plot_format = img_format
+                break
+
+        self.save_file_path = Path(self.save_dir_path).joinpath(
+            f"{self.save_filename_textbox.text()}.{save_format}")
+        self.dpi = self.dpi_line_edit.value()
+        self.close()
+
+
+if __name__ == '__main__':
+    os_name, version, *_ = platform.platform().split('-')
+    if os_name == 'macOS':
+        os.environ['QT_MAC_WANTS_LAYER'] = '1'
+    app = QtWidgets.QApplication(sys.argv)
+    save_path = '/Users/ldam/Documents/GIT/sohstationviewer/tests/test_data/Q330-sample'  # noqa: E501
+    test = SavePlotDialog(None, 'test_plot')
+    test.set_save_directory(save_path)
+    test.exec_()
+    print("dpi:", test.dpi)
+    print("save file path:", test.save_file_path)
+    sys.exit(app.exec_())
diff --git a/sohstationviewer/view/ui/main_ui.py b/sohstationviewer/view/ui/main_ui.py
index 005029668262238706fc02f0bf176aa25995df5e..194b23483bc13cbd916c0d77a737d556eee6a313 100755
--- a/sohstationviewer/view/ui/main_ui.py
+++ b/sohstationviewer/view/ui/main_ui.py
@@ -793,6 +793,8 @@ class UIMainWindow(object):
 
         self.stop_button.clicked.connect(main_window.stop)
 
+        self.save_plot_button.clicked.connect(main_window.save_plot)
+
     def read_config(self):
         self.config = configparser.ConfigParser()
         config_path = Path('sohstationviewer/conf/read_settings.ini')
diff --git a/sohstationviewer/view/util/functions.py b/sohstationviewer/view/util/functions.py
index 2927cae8c88a35dbe38423b4448c5c615c469da9..254f32030c796164cd0399d3e7d938174df27c8d 100644
--- a/sohstationviewer/view/util/functions.py
+++ b/sohstationviewer/view/util/functions.py
@@ -96,6 +96,9 @@ def create_table_of_content_file(base_path: Path) -> None:
         "this software.\n\n"
         "On the left-hand side you will find a list of currently available"
         " help topics.\n\n"
+        "If the links of the Table of Contents are broken, click on Recreate "
+        "Table of Content <img src='recreate_table_contents.png' height=30 /> "
+        "to rebuild it.\n\n"
         "The home button can be used to return to this page at any time.\n\n"
         "# Table of Contents\n\n")
     links = ""