diff --git a/.gitignore b/.gitignore
index 1532d61..a36fb84 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,7 +21,7 @@ var/
 *.egg-info/
 .installed.cfg
 *.egg
-.idea
+.idea/
 
 # PyInstaller
 #  Usually these files are written by a python script from a template
diff --git a/pydsf.py b/pydsf.py
index b3d4e4c..65c3310 100644
--- a/pydsf.py
+++ b/pydsf.py
@@ -1,6 +1,7 @@
 #! /usr/bin/env python2
 # -*- coding: utf-8 -*-
 import csv
+import multiprocessing as mp
 
 try:
     import matplotlib as mpl
@@ -23,54 +24,56 @@ except ImportError:
     raise ImportError('----- NumPy must be installed. -----')
 
 try:
-    from scipy.signal import filtfilt,  butter
+    from scipy.signal import filtfilt, butter
     from scipy import interpolate
     from scipy import optimize
 except ImportError:
     raise ImportError('----- SciPy must be installed. -----')
 
+
 class Well:
-    def __init__(self,  owner):
+    def __init__(self, owner):
         self.owner = owner
         self.name = None
-        self.raw = np.zeros(self.owner.reads,  dtype=np.float)
-        self.filtered = np.zeros(self.owner.reads,  dtype=np.float)
-        self.derivatives = np.zeros((4,  self.owner.reads))
-        self.splines = {"raw": None,  
-                                 "filtered": None,  
-                                 "derivative1": None}
+        self.raw = np.zeros(self.owner.reads, dtype=np.float)
+        self.filtered = np.zeros(self.owner.reads, dtype=np.float)
+        self.derivatives = np.zeros((4, self.owner.reads))
+        self.splines = {"raw": None,
+                        "filtered": None,
+                        "derivative1": None}
         self.tm = np.NaN
         self.tm_sd = np.NaN
         self.baseline_correction = owner.baseline_correction
         self.baseline = None
-        
+
     def filter_raw(self):
         """
         Apply a filter to the raw data
         """
         b, a = butter(3, 0.3)
         self.filtered = filtfilt(b, a, self.raw)
-        
+
     def calc_spline(self, y):
         """
         Calculate a spline that represents the smoothed data points
         """
         spline = interpolate.InterpolatedUnivariateSpline(self.owner.temprange, y)
-        return spline 
-        
+        return spline
+
     def calc_derivatives(self, spline='filtered'):
         for t in self.owner.temprange:
             temp = self.splines[spline].derivatives(t)
             for i in range(4):
-                self.derivatives[i,  t - self.owner.t1] = temp[i]
+                self.derivatives[i, t - self.owner.t1] = temp[i]
 
-    def calc_baseline(self, y):
+    @staticmethod
+    def calc_baseline(y):
         try:
             baseline = peakutils.baseline(y)
             return baseline
         except:
             return np.NaN
-                
+
     def calc_tm(self):
         """
         Calculate the Tm of the well. Returns either the Tm or 'np.NaN'.
@@ -83,7 +86,7 @@ class Well:
         self.owner.denatured_wells.append(self)
 
         if self.owner.tm_cutoff_low != self.owner.t1 or self.owner.tm_cutoff_high != self.owner.t1:
-            x = np.arange(self.owner.tm_cutoff_low, self.owner.tm_cutoff_high + 1, self.owner.dt,  dtype=float)
+            x = np.arange(self.owner.tm_cutoff_low, self.owner.tm_cutoff_high + 1, self.owner.dt, dtype=float)
 
         x = self.owner.temprange
         y = self.derivatives[1]
@@ -93,83 +96,85 @@ class Well:
 
         try:
             peak_indexes = peakutils.indexes(y, min_dist=len(x))  # calculate a rough estimate of peaks; set min_dist
-                                                                  # temperature range to only find one/the highest peak
-            tm = peakutils.interpolate(x, y, ind=peak_indexes)[0] # increase resolution by fitting gaussian function
-                                                                  # to peak
+            # temperature range to only find one/the highest peak
+            tm = peakutils.interpolate(x, y, ind=peak_indexes)[0]  # increase resolution by fitting gaussian function
+            # to peak
         except:
             return np.NaN  # In case of error, return no peak
-        
+
         try:
-                # Check if the peak is within cutoff range
-                if tm and tm >= self.owner.tm_cutoff_low and tm <= self.owner.tm_cutoff_high:
-                    self.owner.denatured_wells.remove(self) # If everything is fine, remove the denatured flag
-                    return tm  # and return the Tm
-                else:
-                    return np.NaN  # otherwise, return NaN
+            # Check if the peak is within cutoff range
+            if tm and tm >= self.owner.tm_cutoff_low and tm <= self.owner.tm_cutoff_high:
+                self.owner.denatured_wells.remove(self)  # If everything is fine, remove the denatured flag
+                return tm  # and return the Tm
+            else:
+                return np.NaN  # otherwise, return NaN
         except:
             return np.NaN  # In case of error, return NaN
-            
+
     def is_denatured(self):
         """
         Check if the well is denatured. Returns true if the well has been already flagged as
         denatured, no Tm was found, or if the initial signal intensity is above a user definded
         threshold.
         """
-        denatured = True # Assumption is that the well is denatured
-        
-        if self in self.owner.denatured_wells: # check if the well is already flagged as denatured
-            return denatured # return true if it is
-            
+        denatured = True  # Assumption is that the well is denatured
+
+        if self in self.owner.denatured_wells:  # check if the well is already flagged as denatured
+            return denatured  # return true if it is
+
         if self.tm and (self.tm <= self.owner.tm_cutoff_low or self.tm >= self.owner.tm_cutoff_high):
             denatured = True
             return denatured
-            
-        for i in self.derivatives[1]: # Iterate over all points in the first derivative
-            if i > 0: # If a positive slope is found
-                denatured = False # set denatured flag to False
-        
-        reads = int(round(self.owner.reads/10)) # How many values should be checked against the signal threshold:
-                                                # 1/10 of the total number of data point
-        read = 0 # Initialize running variable representing the current data point
-        
+
+        for i in self.derivatives[1]:  # Iterate over all points in the first derivative
+            if i > 0:  # If a positive slope is found
+                denatured = False  # set denatured flag to False
+
+        reads = int(round(self.owner.reads / 10))  # How many values should be checked against the signal threshold:
+        # 1/10 of the total number of data point
+        read = 0  # Initialize running variable representing the current data point
+
         if not denatured:
-            for j in self.filtered: # Iterate over the filtered data
-                if self.owner.signal_threshold:                           # If a signal threshold was defined
-                    if j > self.owner.signal_threshold and read <= reads: # iterate over 1/10 of all data points 
-                                                                          # and check for values larger than the threshold.
-                        denatured = True # Set flag to True if a match is found
+            for j in self.filtered:  # Iterate over the filtered data
+                if self.owner.signal_threshold:  # If a signal threshold was defined
+                    if j > self.owner.signal_threshold and read <= reads:  # iterate over 1/10 of all data points
+                        # and check for values larger than the threshold.
+                        denatured = True  # Set flag to True if a match is found
                         print("{}: {}".format(self.name, j))
-                        return denatured # and return
+                        return denatured  # and return
             read += 1
-            
+
         return denatured
-                
+
     def analyze(self):
         self.filter_raw()
         self.splines["raw"] = self.calc_spline(self.raw)
         self.splines["filtered"] = self.calc_spline(self.filtered)
-        
+
         self.calc_derivatives()
         if self.baseline_correction:
             self.baseline = self.calc_baseline(self.derivatives[1])
         if self.is_denatured():
             self.owner.denatured_wells.append(self)
-        
+
         self.splines["derivative1"] = self.calc_spline(self.derivatives[1])
 
         self.tm = self.calc_tm()
         if self.tm is None:
             self.tm = np.NaN
-        
+
+
 class Experiment:
-    def __init__(self, type, gui=None, files=None, replicates=None, t1=25, t2=95, dt=1, cols=12, rows=8,  cutoff_low=None,  cutoff_high=None,  signal_threshold=None,  color_range=None, baseline_correction=False):
+    def __init__(self, type, gui=None, files=None, replicates=None, t1=25, t2=95, dt=1, cols=12, rows=8,
+                 cutoff_low=None, cutoff_high=None, signal_threshold=None, color_range=None, baseline_correction=False):
         self.replicates = replicates
         self.cols = cols
         self.rows = rows
         self.t1 = t1
         self.t2 = t2
         self.dt = dt
-        self.temprange = np.arange(self.t1, self.t2 + 1, self.dt,  dtype=float)
+        self.temprange = np.arange(self.t1, self.t2 + 1, self.dt, dtype=float)
         self.reads = int(round((t2 + 1 - t1) / dt))
         self.wellnum = self.cols * self.rows
         self.files = files
@@ -178,10 +183,10 @@ class Experiment:
         self.max_tm = None
         self.min_tm = None
         self.replicates = None
-        self.gui=gui
+        self.gui = gui
         self.signal_threshold = signal_threshold
         self.avg_plate = None
-        self.baseline_correction=baseline_correction
+        self.baseline_correction = baseline_correction
         if cutoff_low:
             self.tm_cutoff_low = cutoff_low
         else:
@@ -193,48 +198,54 @@ class Experiment:
         if color_range:
             self.color_range = color_range
         else:
-            self.color_range = (self.t1, self.t2)
-            
+            self.color_range = None
+
         self.plates = []
-            
+
         i = 1
         for file in files:
-            plate = Plate(type=self.type, owner=self, filename=file, t1=self.t1, t2=self.t2, dt=self.dt, cols=self.cols,  rows=self.rows,  cutoff_low=self.tm_cutoff_low,  cutoff_high=self.tm_cutoff_high,  signal_threshold=self.signal_threshold,  color_range=self.color_range)
+            plate = Plate(type=self.type, owner=self, filename=file, t1=self.t1, t2=self.t2, dt=self.dt, cols=self.cols,
+                          rows=self.rows, cutoff_low=self.tm_cutoff_low, cutoff_high=self.tm_cutoff_high,
+                          signal_threshold=self.signal_threshold, color_range=self.color_range)
             plate.id = i
             self.plates.append(plate)
             i += 1
         if len(files) > 1:
-            self.avg_plate = Plate(type=self.type, owner=self, filename=None, t1=self.t1, t2=self.t2, dt=self.dt, cols=self.cols,  rows=self.rows,  cutoff_low=self.tm_cutoff_low,  cutoff_high=self.tm_cutoff_high,  signal_threshold=self.signal_threshold,  color_range=self.color_range)
+            self.avg_plate = Plate(type=self.type, owner=self, filename=None, t1=self.t1, t2=self.t2, dt=self.dt,
+                                   cols=self.cols, rows=self.rows, cutoff_low=self.tm_cutoff_low,
+                                   cutoff_high=self.tm_cutoff_high, signal_threshold=self.signal_threshold,
+                                   color_range=self.color_range)
             self.avg_plate.id = 'average'
- 
+
     def analyze(self):
         for plate in self.plates:
             plate.analyze(gui=self.gui)
-            
+
         if len(self.plates) > 1:
-        
-            #self.tm_replicates = np.zeros( self.wellnum, dtype=float )
-            #self.tm_replicates_sd = np.zeros( self.wellnum, dtype=float )
-        
-        
+
+            # self.tm_replicates = np.zeros( self.wellnum, dtype=float )
+            # self.tm_replicates_sd = np.zeros( self.wellnum, dtype=float )
+
+
             for i in range(self.wellnum):
-                tmp =  []
+                tmp = []
                 for plate in self.plates:
                     tm = plate.wells[i].tm
                     self.avg_plate.wells[i].name = plate.wells[i].name
                     if plate.wells[i] not in plate.denatured_wells:
                         tmp.append(tm)
                 if len(tmp) > 0:
-                    #self.avg_plate.wells[i].tm = (sum(tmp)/len(tmp))
+                    # self.avg_plate.wells[i].tm = (sum(tmp)/len(tmp))
                     self.avg_plate.wells[i].tm = np.mean(tmp)
                     self.avg_plate.wells[i].tm_sd = np.std(tmp)
-                    #self.tm_replicates[i] = (sum(tmp)/len(tmp))
+                    # self.tm_replicates[i] = (sum(tmp)/len(tmp))
                 else:
                     self.avg_plate.denatured_wells.append(self.avg_plate.wells[i])
 
 
 class Plate:
-    def __init__(self,  type, owner, id=None, filename=None, replicates=None, t1=None, t2=None, dt=None, cols=12, rows=8,  cutoff_low=None,  cutoff_high=None,  signal_threshold=None,  color_range=None):
+    def __init__(self, type, owner, id=None, filename=None, replicates=None, t1=None, t2=None, dt=None, cols=12, rows=8,
+                 cutoff_low=None, cutoff_high=None, signal_threshold=None, color_range=None):
         self.cols = cols
         self.rows = rows
         self.owner = owner
@@ -250,7 +261,7 @@ class Plate:
             self.dt = dt
         else:
             self.dt = owner.dt
-        self.temprange = np.arange(self.t1, self.t2 + 1, self.dt,  dtype=float)
+        self.temprange = np.arange(self.t1, self.t2 + 1, self.dt, dtype=float)
         self.reads = int(round((t2 + 1 - t1) / dt))
         self.wellnum = self.cols * self.rows
         self.filename = filename
@@ -274,28 +285,26 @@ class Plate:
             self.color_range = color_range
         else:
             self.color_range = None
-        
+
         self.denatured_wells = []
         self.tms = []
-        
-        for i in range(self.wellnum):
-            well = Well(owner = self)
-            self.wells.append(well)
-                  
-        #self.analyze()
 
-    
+        for i in range(self.wellnum):
+            well = Well(owner=self)
+            self.wells.append(well)
+
+
     def analytikJena(self):
         """
         Data processing for Analytik Jena qTower 2.0 export files
         """
-        with open(self.filename,  'r') as f:
-            reader = csv.reader(f, delimiter=';',  quoting=csv.QUOTE_NONE)
-            
+        with open(self.filename, 'r') as f:
+            reader = csv.reader(f, delimiter=';', quoting=csv.QUOTE_NONE)
+
             i = 0
             for row in reader:
-                temp = np.zeros(self.reads,  dtype=float)
-                for read in range(self.reads+1):
+                temp = np.zeros(self.reads, dtype=float)
+                for read in range(self.reads + 1):
                     if read > 0:
                         try:
                             temp[read - 1] = row[read]
@@ -306,15 +315,15 @@ class Plate:
                 self.wells[i].raw = temp
                 i += 1
 
-    def analyze(self,  gui=None):
+    def analyze(self, gui=None):
         try:
             # Try to access data file in the given path
-            with open(self.filename) as f: pass
+            with open(self.filename) as f:
+                pass
         except IOError as e:
             # If the file is not found, or not accessible: abort
             print('Error accessing file: {}'.format(e))
-        
-        
+
         if self.type == 'Analytik Jena qTOWER 2.0/2.2':
             self.analytikJena()
             if gui:
@@ -322,23 +331,23 @@ class Plate:
         else:
             # Raise exception, if the instrument's name is unknown
             raise NameError('Unknown instrument type: {}'.format(self.type))
-        
+
         for well in self.wells:
             well.analyze()
             if gui:
                 update_progress_bar(gui.pb, 15)
-            
+
             self.tms.append(well.tm)
-            
+
         if self.replicates:
             if self.replicates == 'rows':
                 print("rows")
             if self.replicates == 'cols':
                 print("cols")
-        #print(self.tms)
+        # print(self.tms)
         self.max_tm = max(self.tms)
         self.min_tm = min(self.tms)
-        
+
     def write_tm_table(self, filename):
         with open(filename, 'w') as f:
             f.write('#{:<4s}{:>13s}\n'.format('ID', '"Tm [°C]"'))
@@ -347,7 +356,7 @@ class Plate:
                     f.write('{:<5s}{:>12s}\n'.format(well.name, 'NaN'))
                 else:
                     f.write('{:<5s}{:>12s}\n'.format(well.name, str(well.tm)))
-                    
+
     def write_avg_tm_table(self, filename):
         with open(filename, 'w') as f:
             f.write('#{:<4s}{:>13s}{:>13s}\n'.format('"ID"', '"Tm [°C]"', '"SD"'))
@@ -356,7 +365,7 @@ class Plate:
                     f.write('{:<5s}{:>12s}{:>12s}\n'.format(well.name, 'NaN', 'NaN'))
                 else:
                     f.write('{:<5s}{:>12s}{:>12s}\n'.format(well.name, str(well.tm), str(well.tm_sd)))
-                    
+
     def write_raw_table(self, filename):
         with open(filename, 'w') as f:
             f.write('#"Raw data"\n')
@@ -364,16 +373,16 @@ class Plate:
             for well in self.wells:
                 f.write('{:>15s}'.format(well.name))
             f.write('\n')
-            
+
             i = 0
             for t in self.temprange:
                 f.write('{:<10s}'.format(str(t)))
                 for well in self.wells:
                     d = well.raw[i]
-                    f.write('{:>-15.3f}'.format(float(np.round(d,  decimals=3))))
+                    f.write('{:>-15.3f}'.format(float(np.round(d, decimals=3))))
                 f.write('\n')
                 i += 1
-                
+
     def write_filtered_table(self, filename):
         with open(filename, 'w') as f:
             f.write('#"Filtered data" \n')
@@ -381,16 +390,16 @@ class Plate:
             for well in self.wells:
                 f.write('{:>15s}'.format(well.name))
             f.write('\n')
-            
+
             i = 0
             for t in self.temprange:
                 f.write('{:<10s}'.format(str(t)))
                 for well in self.wells:
                     d = well.filtered[i]
-                    f.write('{:>-15.3f}'.format(float(np.round(d,  decimals=3))))
+                    f.write('{:>-15.3f}'.format(float(np.round(d, decimals=3))))
                 f.write('\n')
                 i += 1
-                    
+
     def write_derivative_table(self, filename):
         with open(filename, 'w') as f:
             f.write('#"Derivative dI/dT"\n')
@@ -398,13 +407,13 @@ class Plate:
             for well in self.wells:
                 f.write('{:>15s}'.format(well.name))
             f.write('\n')
-            
+
             i = 0
             for t in self.temprange:
                 f.write('{:<10s}'.format(str(t)))
                 for well in self.wells:
                     d = well.derivatives[1][i]
-                    f.write('{:>-15.3f}'.format(float(np.round(d,  decimals=3))))
+                    f.write('{:>-15.3f}'.format(float(np.round(d, decimals=3))))
                 f.write('\n')
                 i += 1
 
@@ -412,209 +421,185 @@ class Plate:
 
     def write_baseline_corrected_table(self, filename):
         raise NotImplementedError
-        
-        
+
+
 def update_progress_bar(bar, value):
     bar.setValue(value)
-    
-def plot_tm_heatmap_average(experiment, gui=None):
-    """
-    Plot Tm heatmap (Fig. 1)
-    """
-    x = 1               # Position in columns
-    y = 1               # Position in rows
-    x_values = []       # Array holding the columns
-    y_values = []       # Array holding the rows
-    c_values = []       # Array holding the color values aka Tm
 
-#    c = well.tm # If not, set color to Tm
-#    if c < experiment.tm_cutoff_low:     # Check if Tm is lower that the cutoff
-#        c = experiment.tm_cutoff_low     # If it is, set color to cutoff
-#    elif c > experiment.tm_cutoff_high:  # Check if Tm is higher that the cutoff
-#        c = experiment.tm_cutoff_high    # If it is, set color to cutoff
-#    else:                       # If the plate is denatured
-#        c = experiment.tm_cutoff_low # Set its color to the low cutoff
-    for c in experiment.tm_replicates:
+class PlotResults():
 
-        x_values.append(x)  # Add values to the respective arrays
-        y_values.append(y)
-        c_values.append(c)
-        x += 1              # Increase column by one
-        if x > experiment.cols:  # If maximum column per row is reached
-            x = 1           # reset column to one
-            y += 1          # and increase row by one
+    def __init__(self, experiment):
+        self.experiment = experiment
 
-    fig1 = plt.figure() # new figure 
-    ax1 = fig1.add_subplot(1, 1, 1) # A single canvas
-    ax1.autoscale(tight=True) # Scale plate size
-    ax1.xaxis.set_major_locator(ticker.MaxNLocator(experiment.cols + 1))  # n columns
-    ax1.yaxis.set_major_locator(ticker.MaxNLocator(experiment.rows + 1))  # n rows
-    if experiment.color_range:
-        cax = ax1.scatter(x_values, y_values, s=300, c=c_values, marker='s',  vmin=experiment.color_range[0],  vmax=experiment.color_range[1]) # plot wells and color using the colormap
-    else:
-        cax = ax1.scatter(x_values, y_values, s=300, c=c_values, marker='s') # plot wells and color using the colormap
-    ax1.invert_yaxis() # invert y axis to math plate layout
-    cbar = fig1.colorbar(cax) # show colorbar
-    ax1.set_xlabel('Columns') # set axis and colorbar label
-    ax1.set_ylabel('Rows')
-    ax1.set_title('$T_m$ heatmap (average)')
-    cbar.set_label(u"Temperature [°C]")
-        
-        
-def plot_tm_heatmap_single(plate, gui=None):
-    """
-    Plot Tm heatmap (Fig. 1)
-    """
-    x = 1               # Position in columns
-    y = 1               # Position in rows
-    x_values = []       # Array holding the columns
-    y_values = []       # Array holding the rows
-    c_values = []       # Array holding the color values aka Tm
-    dx_values = []
-    dy_values = []
-    dc_values = []
-    for well in plate.wells: # Iterate over all wells
-        if well not in plate.denatured_wells: # Check if well is denatured (no Tm found)
-            c = well.tm # If not, set color to Tm
-            if c < plate.tm_cutoff_low:     # Check if Tm is lower that the cutoff
-                c = plate.tm_cutoff_low     # If it is, set color to cutoff
-            elif c > plate.tm_cutoff_high:  # Check if Tm is higher that the cutoff
-                c = plate.tm_cutoff_high    # If it is, set color to cutoff
-        else:                       # If the plate is denatured
-            c = plate.tm_cutoff_low # Set its color to the low cutoff
-            dx_values.append(x)
-            dy_values.append(y)
-        x_values.append(x)  # Add values to the respective arrays
-        y_values.append(y)
-        c_values.append(c)
-        x += 1              # Increase column by one
-        if x > plate.cols:  # If maximum column per row is reached
-            x = 1           # reset column to one
-            y += 1          # and increase row by one
+    def plot_tm_heatmap_single(self, plate, widget):
+        """
+        Plot Tm heatmap (Fig. 1)
+        """
+        x = 1  # Position in columns
+        y = 1  # Position in rows
+        x_values = []  # Array holding the columns
+        y_values = []  # Array holding the rows
+        c_values = []  # Array holding the color values aka Tm
+        dx_values = []
+        dy_values = []
+        dc_values = []
+        canvas = widget.canvas
+        canvas.clear()
+        for well in plate.wells:  # Iterate over all wells
+            if well not in plate.denatured_wells:  # Check if well is denatured (no Tm found)
+                c = well.tm  # If not, set color to Tm
+                if c < plate.tm_cutoff_low:  # Check if Tm is lower that the cutoff
+                    c = plate.tm_cutoff_low  # If it is, set color to cutoff
+                elif c > plate.tm_cutoff_high:  # Check if Tm is higher that the cutoff
+                    c = plate.tm_cutoff_high  # If it is, set color to cutoff
+            else:  # If the plate is denatured
+                c = plate.tm_cutoff_low  # Set its color to the low cutoff
+                dx_values.append(x)
+                dy_values.append(y)
+            x_values.append(x)  # Add values to the respective arrays
+            y_values.append(y)
+            c_values.append(c)
+            x += 1  # Increase column by one
+            if x > plate.cols:  # If maximum column per row is reached
+                x = 1  # reset column to one
+                y += 1  # and increase row by one
 
-    fig1 = plt.figure() # new figure
-    ax1 = fig1.add_subplot(1, 1, 1) # A single canvas
-    ax1.autoscale(tight=True) # Scale plate size
-    ax1.xaxis.set_major_locator(ticker.MaxNLocator(plate.cols + 1))  # n columns
-    ax1.yaxis.set_major_locator(ticker.MaxNLocator(plate.rows + 1))  # n rows
-    if plate.color_range:
-        cax = ax1.scatter(x_values, y_values, s=305, c=c_values, marker='s',  vmin=plate.color_range[0],  vmax=plate.color_range[1]) # plot wells and color using the colormap
-    else:
-        cax = ax1.scatter(x_values, y_values, s=305, c=c_values, marker='s') # plot wells and color using the colormap
-
-    cax2 = ax1.scatter(dx_values, dy_values, s=80, c='white', marker='x', linewidths=(1.5,))
-    ax1.invert_yaxis() # invert y axis to math plate layout
-    cbar = fig1.colorbar(cax) # show colorbar
-    ax1.set_xlabel('Columns') # set axis and colorbar label
-    ax1.set_ylabel('Rows')
-
-    if str(plate.id) == 'average':
-        title = '$T_m$ heatmap (average)'
-    else:
-        title = '$T_m$ heatmap (plate #{})'.format(str(plate.id))
-    ax1.set_title(title)
-    cbar.set_label(u"Temperature [°C]")
-
-    #magenta_patch = mpatches.Patch(color='magenta', label='Denatured')
-    #fig1.legend([magenta_patch], 'Denatured', loc='lower right', bbox_to_anchor=[0.5, 0.5])
-    
-#    if gui:
-#        update_progress_bar(gui.pb, 50)
-    
-def plot_derivative(plate, gui=None):
-    """
-    Plot derivatives (Fig. 2)
-    """
-    fig2 = plt.figure() # new figure
-    fig2.suptitle('Individual Derivatives (plate #{})'.format(str(plate.id))) # set title
-    
-    for plot_num in range(1, plate.wellnum + 1): # iterate over all wells
-        well = plate.wells[plot_num - 1] # get single well based on current plot number
-        ax = fig2.add_subplot(plate.rows,  plate.cols,  plot_num) # add new subplot
-        ax.autoscale(tight=True) # scale to data
-        ax.set_title(well.name,  size='xx-small') # set title of current subplot to well identifier
-        
-        if well in plate.denatured_wells:
-            ax.patch.set_facecolor('#FFD6D6')
-        
-        if plot_num == plate.wellnum - plate.cols + 1: # add axis label to the subplot in the bottom left corner of the figure
-            ax.set_xlabel(u'T [°C]',  size='xx-small')
-            ax.set_ylabel('dI/dT',  size='xx-small')
-
-        x = plate.temprange     # set values for the x axis to the given temperature range
-        if well.baseline_correction:
-            print(well.baseline)
-            y = well.derivatives[1] - well.baseline
+        fig1 = canvas.fig  # new figure
+        ax1 = fig1.add_subplot(1, 1, 1)  # A single canvas
+        ax1.autoscale(tight=True)  # Scale plate size
+        ax1.xaxis.set_major_locator(ticker.MaxNLocator(plate.cols + 1))  # n columns
+        ax1.yaxis.set_major_locator(ticker.MaxNLocator(plate.rows + 1))  # n rows
+        if plate.color_range:
+            cax = ax1.scatter(x_values, y_values, s=305, c=c_values, marker='s', vmin=plate.color_range[0],
+                              vmax=plate.color_range[1])  # plot wells and color using the colormap
         else:
-            y = well.derivatives[1] # grab y values from the first derivative of the well
-        
-        ax.xaxis.set_major_locator(ticker.MaxNLocator(4)) # only show three tickmarks on both axes
-        ax.yaxis.set_major_locator(ticker.MaxNLocator(4))
-        if well not in plate.denatured_wells: # check if well is denatured (without determined Tm)
-            tm = well.tm # if not, grab its Tm
+            cax = ax1.scatter(x_values, y_values, s=305, c=c_values, marker='s')  # plot wells and color using the colormap
+
+        cax2 = ax1.scatter(dx_values, dy_values, s=80, c='white', marker='x', linewidths=(1.5,))
+        ax1.invert_yaxis()  # invert y axis to math plate layout
+        cbar = fig1.colorbar(cax)  # show colorbar
+        ax1.set_xlabel('Columns')  # set axis and colorbar label
+        ax1.set_ylabel('Rows')
+
+        if str(plate.id) == 'average':
+            title = '$T_m$ heatmap (average)'
         else:
-            tm = np.NaN # else set Tm to np.NaN
-        if tm:
-            ax.axvline(x=tm) # plot vertical line at the Tm
-        ax.axvspan(plate.t1, plate.tm_cutoff_low, facecolor='0.8',  alpha=0.5)   # shade lower cutoff area
-        ax.axvspan(plate.tm_cutoff_high, plate.t2,  facecolor='0.8',  alpha=0.5) # shade higher cutoff area 
-        for label in ax.get_xticklabels() + ax.get_yticklabels(): # set fontsize for all tick labels to xx-small
-            label.set_fontsize('xx-small')
-         
-        cax = ax.plot(x, y) # plot data to the current subplot
-#    if gui:    
-#        update_progress_bar(gui.pb, 75)
- 
-def plot_raw(plate, gui=None): 
-    """
-    Plot raw data (Fig. 3)
-    """    
-    fig3 = plt.figure() # new figure
-    fig3.suptitle('Raw Data (plate #{})'.format(str(plate.id))) # set title
-    
-    for plot_num in range(1, plate.wellnum + 1): # iterate over all wells
-        well = plate.wells[plot_num - 1] # get single well based on current plot number
-        ax = fig3.add_subplot(plate.rows,  plate.cols,  plot_num) # add new subplot
-        ax.autoscale(tight=True) # scale to data
-        ax.set_title(well.name,  size='xx-small') # set title of current subplot to well identifier
-        
-        if well in plate.denatured_wells:
-            ax.patch.set_facecolor('#FFD6D6')
-        
-        if plot_num == plate.wellnum - plate.cols + 1: # add axis label to the subplot in the bottom left corner of the figure
-            ax.set_xlabel(u'T [°C]',  size='xx-small')
-            ax.set_ylabel('I',  size='xx-small')
-        
-        x = plate.temprange # set values for the x axis to the given temperature range
-        y = well.raw        # grab y values from the raw data of the well
-        
-        ax.xaxis.set_major_locator(ticker.MaxNLocator(4)) # only show three tickmarks on both axes
-        ax.yaxis.set_major_locator(ticker.MaxNLocator(4))
-        ax.axvspan(plate.t1, plate.tm_cutoff_low, facecolor='0.8',  alpha=0.5)   # shade lower cutoff area
-        ax.axvspan(plate.tm_cutoff_high, plate.t2,  facecolor='0.8',  alpha=0.5) # shade higher cutoff area 
-        for label in ax.get_xticklabels() + ax.get_yticklabels(): # set fontsize for all tick labels to xx-small
-            label.set_fontsize('xx-small')
-        
-        cax = ax.plot(x, y) # plot data to the current subplot
-    
-#    if gui:
-#        update_progress_bar(gui.pb, 100)
-#        gui.pb.hide()
+            title = '$T_m$ heatmap (plate #{})'.format(str(plate.id))
+        ax1.set_title(title)
+        cbar.set_label(u"Temperature [°C]")
 
-def plot(experiment, gui=None):
-    for plate in experiment.plates:
-        plot_raw(plate)
-        plot_derivative(plate)
-        plot_tm_heatmap_single(plate)
-        
-    if len(experiment.plates) > 1:
-        plot_tm_heatmap_single(experiment.avg_plate)
-        #plot_tm_heatmap_average(experiment)
-    
-    plt.show()
-        
+        canvas.draw()
+
+    def plot_derivative(self, plate, widget):
+        """
+        Plot derivatives (Fig. 2)
+        """
+        canvas = widget.canvas
+        canvas.clear()
+        fig2 = canvas.fig  # new figure
+        fig2.suptitle('Individual Derivatives (plate #{})'.format(str(plate.id)))  # set title
+
+        for plot_num in range(1, plate.wellnum + 1):  # iterate over all wells
+            well = plate.wells[plot_num - 1]  # get single well based on current plot number
+            ax = fig2.add_subplot(plate.rows, plate.cols, plot_num)  # add new subplot
+            ax.autoscale(tight=True)  # scale to data
+            ax.set_title(well.name, size='xx-small')  # set title of current subplot to well identifier
+
+            if well in plate.denatured_wells:
+                ax.patch.set_facecolor('#FFD6D6')
+
+            if plot_num == plate.wellnum - plate.cols + 1:  # add axis label to the subplot in the bottom left corner of the figure
+                ax.set_xlabel(u'T [°C]', size='xx-small')
+                ax.set_ylabel('dI/dT', size='xx-small')
+
+            x = plate.temprange  # set values for the x axis to the given temperature range
+            if well.baseline_correction:
+                print(well.baseline)
+                y = well.derivatives[1] - well.baseline
+            else:
+                y = well.derivatives[1]  # grab y values from the first derivative of the well
+
+            ax.xaxis.set_major_locator(ticker.MaxNLocator(4))  # only show three tickmarks on both axes
+            ax.yaxis.set_major_locator(ticker.MaxNLocator(4))
+            if well not in plate.denatured_wells:  # check if well is denatured (without determined Tm)
+                tm = well.tm  # if not, grab its Tm
+            else:
+                tm = np.NaN  # else set Tm to np.NaN
+            if tm:
+                ax.axvline(x=tm)  # plot vertical line at the Tm
+            ax.axvspan(plate.t1, plate.tm_cutoff_low, facecolor='0.8', alpha=0.5)  # shade lower cutoff area
+            ax.axvspan(plate.tm_cutoff_high, plate.t2, facecolor='0.8', alpha=0.5)  # shade higher cutoff area
+            for label in ax.get_xticklabels() + ax.get_yticklabels():  # set fontsize for all tick labels to xx-small
+                label.set_fontsize('xx-small')
+
+            cax = ax.plot(x, y)  # plot data to the current subplot
+        canvas.draw()
+
+
+    def plot_raw(self, plate, widget):
+        """
+        Plot raw data (Fig. 3)
+        """
+        canvas = widget.canvas
+        canvas.clear()
+        fig3 = canvas.fig  # new figure
+        fig3.suptitle('Raw Data (plate #{})'.format(str(plate.id)))  # set title
+
+        for plot_num in range(1, plate.wellnum + 1):  # iterate over all wells
+            well = plate.wells[plot_num - 1]  # get single well based on current plot number
+            ax = fig3.add_subplot(plate.rows, plate.cols, plot_num)  # add new subplot
+            ax.autoscale(tight=True)  # scale to data
+            ax.set_title(well.name, size='xx-small')  # set title of current subplot to well identifier
+
+            if well in plate.denatured_wells:
+                ax.patch.set_facecolor('#FFD6D6')
+
+            if plot_num == plate.wellnum - plate.cols + 1:  # add axis label to the subplot in the bottom left corner of the figure
+                ax.set_xlabel(u'T [°C]', size='xx-small')
+                ax.set_ylabel('I', size='xx-small')
+
+            x = plate.temprange  # set values for the x axis to the given temperature range
+            y = well.raw  # grab y values from the raw data of the well
+
+            ax.xaxis.set_major_locator(ticker.MaxNLocator(4))  # only show three tickmarks on both axes
+            ax.yaxis.set_major_locator(ticker.MaxNLocator(4))
+            ax.axvspan(plate.t1, plate.tm_cutoff_low, facecolor='0.8', alpha=0.5)  # shade lower cutoff area
+            ax.axvspan(plate.tm_cutoff_high, plate.t2, facecolor='0.8', alpha=0.5)  # shade higher cutoff area
+            for label in ax.get_xticklabels() + ax.get_yticklabels():  # set fontsize for all tick labels to xx-small
+                label.set_fontsize('xx-small')
+
+            cax = ax.plot(x, y)  # plot data to the current subplot
+        canvas.draw()
+
+
+    # def _plot_wrapper(self, plot, plate):
+    #
+    #     if plot == 'raw':
+    #         fig, ax = self._plot_raw(plate)
+    #     elif plot == 'derivative':
+    #         fig, ax = self._plot_derivative(plate)
+    #     elif plot == 'tm_heatmap':
+    #         fig, ax = self._plot_tm_heatmap_single(plate)
+    #     else:
+    #         raise NotImplementedError
+    #         fig = None
+    #         ax = None
+    #     return (fig, ax)
+    #
+    # def plot_all(self):
+    #
+    #     figures = []
+    #
+    #     for plate in self.experiment.plates:
+    #
+    #         figures.append(self._plot_wrapper('raw', plate))
+    #         figures.append(self._plot_wrapper('derivative', plate))
+    #         figures.append(self._plot_wrapper('tm_heatmap', plate))
+    #
+    #     if len(self.experiment.plates) > 1:
+    #         figures.append(self._plot_wrapper('tm_heatmap', self.experiment.avg_plate))
+    #
+    #     return figures
 
-#plate = Plate('/home/alex/Dokumente/Universitaet/Promotion/Denaturierung/26092012/26092012-MG.csv', type='analytikJena', cutoff_low=35.0,  cutoff_high=60.0,  signal_threshold=50000,  color_range=(42, 50))
-#plot(plate)
 
 
diff --git a/ui/Ui_mainwindow.py b/ui/Ui_mainwindow.py
index 52a5903..e35db00 100644
--- a/ui/Ui_mainwindow.py
+++ b/ui/Ui_mainwindow.py
@@ -2,7 +2,7 @@
 
 # Form implementation generated from reading ui file 'mainwindow.ui'
 #
-# Created: Fri Jan 30 14:07:06 2015
+# Created: Fri Jan 30 19:20:59 2015
 #      by: PyQt5 UI code generator 5.4
 #
 # WARNING! All changes made in this file will be lost!
@@ -12,7 +12,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
 class Ui_MainWindow(object):
     def setupUi(self, MainWindow):
         MainWindow.setObjectName("MainWindow")
-        MainWindow.resize(388, 642)
+        MainWindow.resize(808, 646)
         MainWindow.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates))
         self.centralWidget = QtWidgets.QWidget(MainWindow)
         self.centralWidget.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates))
@@ -24,11 +24,11 @@ class Ui_MainWindow(object):
         self.groupBox_experiment.setFlat(False)
         self.groupBox_experiment.setCheckable(False)
         self.groupBox_experiment.setObjectName("groupBox_experiment")
-        self.gridLayout = QtWidgets.QGridLayout(self.groupBox_experiment)
-        self.gridLayout.setObjectName("gridLayout")
+        self.formLayout_3 = QtWidgets.QFormLayout(self.groupBox_experiment)
+        self.formLayout_3.setObjectName("formLayout_3")
         self.label_instrument = QtWidgets.QLabel(self.groupBox_experiment)
         self.label_instrument.setObjectName("label_instrument")
-        self.gridLayout.addWidget(self.label_instrument, 0, 0, 1, 1)
+        self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_instrument)
         self.comboBox_instrument = QtWidgets.QComboBox(self.groupBox_experiment)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
         sizePolicy.setHorizontalStretch(0)
@@ -37,7 +37,7 @@ class Ui_MainWindow(object):
         self.comboBox_instrument.setSizePolicy(sizePolicy)
         self.comboBox_instrument.setObjectName("comboBox_instrument")
         self.comboBox_instrument.addItem("")
-        self.gridLayout.addWidget(self.comboBox_instrument, 0, 1, 1, 1)
+        self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.comboBox_instrument)
         self.groupBox_data = QtWidgets.QGroupBox(self.groupBox_experiment)
         self.groupBox_data.setEnabled(True)
         self.groupBox_data.setObjectName("groupBox_data")
@@ -72,7 +72,7 @@ class Ui_MainWindow(object):
         self.listWidget_data.setAlternatingRowColors(True)
         self.listWidget_data.setObjectName("listWidget_data")
         self.gridLayout_4.addWidget(self.listWidget_data, 0, 0, 2, 1)
-        self.gridLayout.addWidget(self.groupBox_data, 1, 0, 1, 2)
+        self.formLayout_3.setWidget(1, QtWidgets.QFormLayout.SpanningRole, self.groupBox_data)
         self.groupBox_temp = QtWidgets.QGroupBox(self.groupBox_experiment)
         self.groupBox_temp.setEnabled(True)
         self.groupBox_temp.setAutoFillBackground(False)
@@ -108,7 +108,7 @@ class Ui_MainWindow(object):
         self.doubleSpinBox_dt.setProperty("value", 1.0)
         self.doubleSpinBox_dt.setObjectName("doubleSpinBox_dt")
         self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_dt)
-        self.gridLayout.addWidget(self.groupBox_temp, 2, 0, 1, 1)
+        self.formLayout_3.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.groupBox_temp)
         self.groupBox_cutoff = QtWidgets.QGroupBox(self.groupBox_experiment)
         self.groupBox_cutoff.setEnabled(True)
         self.groupBox_cutoff.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
@@ -135,7 +135,7 @@ class Ui_MainWindow(object):
         self.doubleSpinBox_lower.setDecimals(1)
         self.doubleSpinBox_lower.setObjectName("doubleSpinBox_lower")
         self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_lower)
-        self.gridLayout.addWidget(self.groupBox_cutoff, 2, 1, 1, 1)
+        self.formLayout_3.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.groupBox_cutoff)
         self.groupBox_signal_threshold = QtWidgets.QGroupBox(self.groupBox_experiment)
         self.groupBox_signal_threshold.setEnabled(True)
         self.groupBox_signal_threshold.setCheckable(True)
@@ -147,7 +147,7 @@ class Ui_MainWindow(object):
         self.spinBox_signal_threshold.setMaximum(1000000)
         self.spinBox_signal_threshold.setObjectName("spinBox_signal_threshold")
         self.verticalLayout.addWidget(self.spinBox_signal_threshold)
-        self.gridLayout.addWidget(self.groupBox_signal_threshold, 3, 0, 1, 1)
+        self.formLayout_3.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.groupBox_signal_threshold)
         self.groupBox_cbar = QtWidgets.QGroupBox(self.groupBox_experiment)
         self.groupBox_cbar.setEnabled(True)
         self.groupBox_cbar.setCheckable(True)
@@ -170,15 +170,31 @@ class Ui_MainWindow(object):
         self.doubleSpinBox_cbar_end.setDecimals(1)
         self.doubleSpinBox_cbar_end.setObjectName("doubleSpinBox_cbar_end")
         self.formLayout_4.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_cbar_end)
-        self.gridLayout.addWidget(self.groupBox_cbar, 3, 1, 1, 1)
-        self.gridLayout_2.addWidget(self.groupBox_experiment, 0, 0, 1, 1)
-        self.buttonBox_process = QtWidgets.QDialogButtonBox(self.centralWidget)
+        self.formLayout_3.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.groupBox_cbar)
+        self.buttonBox_process = QtWidgets.QDialogButtonBox(self.groupBox_experiment)
         self.buttonBox_process.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
         self.buttonBox_process.setObjectName("buttonBox_process")
-        self.gridLayout_2.addWidget(self.buttonBox_process, 1, 0, 1, 1)
+        self.formLayout_3.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.buttonBox_process)
+        self.gridLayout_2.addWidget(self.groupBox_experiment, 0, 0, 1, 1)
+        self.tabWidget = QtWidgets.QTabWidget(self.centralWidget)
+        self.tabWidget.setObjectName("tabWidget")
+        self.tab_raw = MplWidget()
+        self.tab_raw.setObjectName("tab_raw")
+        self.tabWidget.addTab(self.tab_raw, "")
+        self.tab_derivative = MplWidget()
+        self.tab_derivative.setObjectName("tab_derivative")
+        self.tabWidget.addTab(self.tab_derivative, "")
+        self.tab_heatmap = MplWidget()
+        self.tab_heatmap.setObjectName("tab_heatmap")
+        self.tabWidget.addTab(self.tab_heatmap, "")
+        self.tab_heatmap_avg = MplWidget()
+        self.tab_heatmap_avg.setEnabled(False)
+        self.tab_heatmap_avg.setObjectName("tab_heatmap_avg")
+        self.tabWidget.addTab(self.tab_heatmap_avg, "")
+        self.gridLayout_2.addWidget(self.tabWidget, 0, 1, 1, 1)
         MainWindow.setCentralWidget(self.centralWidget)
         self.menuBar = QtWidgets.QMenuBar(MainWindow)
-        self.menuBar.setGeometry(QtCore.QRect(0, 0, 388, 29))
+        self.menuBar.setGeometry(QtCore.QRect(0, 0, 808, 29))
         self.menuBar.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates))
         self.menuBar.setObjectName("menuBar")
         self.menuFile = QtWidgets.QMenu(self.menuBar)
@@ -215,6 +231,7 @@ class Ui_MainWindow(object):
         self.label_cbar_end.setBuddy(self.doubleSpinBox_cbar_end)
 
         self.retranslateUi(MainWindow)
+        self.tabWidget.setCurrentIndex(3)
         QtCore.QMetaObject.connectSlotsByName(MainWindow)
 
     def retranslateUi(self, MainWindow):
@@ -236,7 +253,7 @@ class Ui_MainWindow(object):
         self.label_dt.setText(_translate("MainWindow", "<html><head/><body><p>&Delta;T</p></body></html>"))
         self.doubleSpinBox_dt.setSuffix(_translate("MainWindow", " °C"))
         self.groupBox_cutoff.setToolTip(_translate("MainWindow", "<html><head/><body><p>Only T<span style=\" vertical-align:sub;\">m</span> values within this limit are considered valid.</p></body></html>"))
-        self.groupBox_cutoff.setTitle(_translate("MainWindow", "Cutoff"))
+        self.groupBox_cutoff.setTitle(_translate("MainWindow", "&Cutoff"))
         self.label_cutoff_high.setText(_translate("MainWindow", "&Upper"))
         self.doubleSpinBox_upper.setSuffix(_translate("MainWindow", " °C"))
         self.label_cutoff_low.setText(_translate("MainWindow", "Lower"))
@@ -249,8 +266,14 @@ class Ui_MainWindow(object):
         self.doubleSpinBox_cbar_start.setSuffix(_translate("MainWindow", " °C"))
         self.label_cbar_end.setText(_translate("MainWindow", "En&d"))
         self.doubleSpinBox_cbar_end.setSuffix(_translate("MainWindow", " °C"))
+        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_raw), _translate("MainWindow", "Raw Data"))
+        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_derivative), _translate("MainWindow", "&1st derivative"))
+        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_heatmap), _translate("MainWindow", "Heatmap"))
+        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_heatmap_avg), _translate("MainWindow", "Heatmap average"))
         self.menuFile.setTitle(_translate("MainWindow", "Fi&le"))
-        self.menuHelp.setTitle(_translate("MainWindow", "Help"))
+        self.menuHelp.setTitle(_translate("MainWindow", "Hel&p"))
         self.actionQuit.setText(_translate("MainWindow", "&Quit"))
         self.actionAbout.setText(_translate("MainWindow", "&About"))
         self.actionAbout_Qt.setText(_translate("MainWindow", "About &Qt"))
+
+from .mplwidget import MplWidget
diff --git a/ui/icons.qrc b/ui/icons.qrc
index f5af3f3..6bc09a8 100644
--- a/ui/icons.qrc
+++ b/ui/icons.qrc
@@ -1,5 +1,3 @@
 <RCC>
-  <qresource prefix="/">
-    <file>qtlogo.svg</file>
-  </qresource>
+  <qresource prefix="/"/>
 </RCC>
diff --git a/ui/mainwindow.py b/ui/mainwindow.py
index b41f2f6..adb4d0b 100644
--- a/ui/mainwindow.py
+++ b/ui/mainwindow.py
@@ -17,6 +17,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
     """
     Class documentation goes here.
     """
+
     def __init__(self, parent=None):
         """
         Constructor
@@ -33,6 +34,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
         self.statusBar.showMessage("Welcome to PyDSF")
 
 
+
     @pyqtSlot("QAbstractButton*")
     def on_buttonBox_open_reset_clicked(self, button):
         """
@@ -47,8 +49,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
         elif button == self.buttonBox_open_reset.button(QDialogButtonBox.Reset):
             self.listWidget_data.clear()
             print("Data cleared")
-#            self.radioButton_rep_rows.setEnabled(False)
-#            self.radioButton_rep_columns.setEnabled(False)
+        # self.radioButton_rep_rows.setEnabled(False)
+        #            self.radioButton_rep_columns.setEnabled(False)
 
 
     @pyqtSlot("QString")
@@ -61,10 +63,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
             self.groupBox_temp.setEnabled(True)
         else:
             self.groupBox_temp.setEnabled(False)
-#        self.groupBox_data.setEnabled(True)
-#        self.groupBox_cutoff.setEnabled(True)
-#        self.groupBox_cbar.setEnabled(True)
-#        self.groupBox_signal_threshold.setEnabled(True)
+        # self.groupBox_data.setEnabled(True)
+        #        self.groupBox_cutoff.setEnabled(True)
+        #        self.groupBox_cbar.setEnabled(True)
+        #        self.groupBox_signal_threshold.setEnabled(True)
 
     @pyqtSlot()
     def on_buttonBox_process_accepted(self):
@@ -76,7 +78,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
             QMessageBox.critical(self, 'Error', "No data file loaded!", QMessageBox.Close, QMessageBox.Close)
             return
         if self.spinBox_signal_threshold.value() == 0 and self.groupBox_signal_threshold.isChecked():
-            QMessageBox.warning(self, 'Warning', "Signal threshold is currently set to zero.", QMessageBox.Ok, QMessageBox.Ok)
+            QMessageBox.warning(self, 'Warning', "Signal threshold is currently set to zero.", QMessageBox.Ok,
+                                QMessageBox.Ok)
 
         self.progressBar.setEnabled(True)
         self.statusBar.showMessage("Processing...")
@@ -90,7 +93,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
             c_lower = self.doubleSpinBox_lower.value()
             c_upper = self.doubleSpinBox_upper.value()
         if self.groupBox_cbar.isChecked():
-            cbar_range = (self.doubleSpinBox_cbar_start,  self.doubleSpinBox_cbar_end)
+            cbar_range = (self.doubleSpinBox_cbar_start, self.doubleSpinBox_cbar_end)
         if self.groupBox_signal_threshold.isChecked():
             signal_threshold = self.spinBox_signal_threshold.value()
 
@@ -99,29 +102,53 @@ class MainWindow(QMainWindow, Ui_MainWindow):
         files = []
         for item in items:
             files.append(item.text())
-        exp = Experiment(type=type, files=files, t1=self.doubleSpinBox_tmin.value(), t2=self.doubleSpinBox_tmax.value(), dt=self.doubleSpinBox_dt.value(), cols=12, rows=8,  cutoff_low=c_lower,  cutoff_high=c_upper,  signal_threshold=signal_threshold,  color_range=cbar_range)
+        exp = Experiment(type=type, files=files, t1=self.doubleSpinBox_tmin.value(), t2=self.doubleSpinBox_tmax.value(),
+                         dt=self.doubleSpinBox_dt.value(), cols=12, rows=8, cutoff_low=c_lower, cutoff_high=c_upper,
+                         signal_threshold=signal_threshold, color_range=cbar_range)
         exp.analyze()
 
         # plate = Plate(type=type, filename=self.lineEdit_data_file.text(), t1=self.doubleSpinBox_tmin.value(), t2=self.doubleSpinBox_tmax.value(), dt=self.doubleSpinBox_dt.value(), cols=12, rows=8,  cutoff_low=c_lower,  cutoff_high=c_upper,  signal_threshold=signal_threshold,  color_range=cbar_range)
         # self.statusBar.addWidget(self.pb, 100)
-        #plate.analyze(gui=self)
+        # plate.analyze(gui=self)
         save_data = QMessageBox.question(self, 'Save data', "Calculations are finished. Save results?",
-                                         QMessageBox.Yes|QMessageBox.No, QMessageBox.Yes)
+                                         QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
         if save_data == QMessageBox.Yes:
             dialog = QFileDialog()
             dialog.setFileMode(QFileDialog.Directory)
             folder = dialog.getExistingDirectory(self, 'Choose path for results')
             for plate in exp.plates:
-                plate.write_tm_table('{}/plate_{}_04_tm.csv'.format(folder,  str(plate.id)))
-                plate.write_derivative_table('{}/plate_{}_03_dI_dT.csv'.format(folder,  str(plate.id)))
-                plate.write_filtered_table('{}/plate_{}_02_filtered_data.csv'.format(folder,  str(plate.id)))
-                plate.write_raw_table('{}/plate_{}_01_raw_data.csv'.format(folder,  str(plate.id)))
+                plate.write_tm_table('{}/plate_{}_04_tm.csv'.format(folder, str(plate.id)))
+                plate.write_derivative_table('{}/plate_{}_03_dI_dT.csv'.format(folder, str(plate.id)))
+                plate.write_filtered_table('{}/plate_{}_02_filtered_data.csv'.format(folder, str(plate.id)))
+                plate.write_raw_table('{}/plate_{}_01_raw_data.csv'.format(folder, str(plate.id)))
 
             if exp.avg_plate:
-                exp.avg_plate.write_avg_tm_table('{}/plate_{}_05_tm_avg.csv'.format(folder,  str(exp.avg_plate.id)))
-            #plot(plate, self)
+                exp.avg_plate.write_avg_tm_table('{}/plate_{}_05_tm_avg.csv'.format(folder, str(exp.avg_plate.id)))
+                #plot(plate, self)
 
-        plot(exp)
+        plotter = PlotResults(exp)
+        for i in range(self.tabWidget.count()):
+            for plate in exp.plates:
+                if i == 0:
+                    plotter.plot_raw(plate, self.tabWidget.widget(i))
+                elif i == 1:
+                    plotter.plot_derivative(plate, self.tabWidget.widget(i))
+                elif i == 2:
+                    plotter.plot_tm_heatmap_single(plate, self.tabWidget.widget(i))
+                elif exp.avg_plate and i == 3:
+                    plotter.plot_tm_heatmap_single(exp.avg_plate, self.tabWidget.widget(i))
+                    self.tabWidget.setTabEnabled(i, True)
+                else:
+                    self.tabWidget.setTabEnabled(i, False)
+
+        #for i in range(self.tabWidget.count()):
+        #    self.tabWidget.widget(i).canvas.clear()
+
+        #fig, ax = figures[0]
+        #self.tabWidget.widget(0).canvas.fig = fig
+        #self.tabWidget.widget(0).canvas.ax = ax
+
+        #self.tabWidget.widget(0).canvas.draw()
 
         self.progressBar.setEnabled(False)
         self.statusBar.showMessage("Finished!")
@@ -135,6 +162,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
         QApplication.quit()
 
     pyqtSlot()
+
     def on_actionQuit_triggered(self):
         """
         Slot documentation goes here.
diff --git a/ui/mainwindow.ui b/ui/mainwindow.ui
index 0b0a627..44dc5a5 100644
--- a/ui/mainwindow.ui
+++ b/ui/mainwindow.ui
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>388</width>
-    <height>642</height>
+    <width>808</width>
+    <height>646</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -35,7 +35,7 @@
       <property name="checkable">
        <bool>false</bool>
       </property>
-      <layout class="QGridLayout" name="gridLayout">
+      <layout class="QFormLayout" name="formLayout_3">
        <item row="0" column="0">
         <widget class="QLabel" name="label_instrument">
          <property name="text">
@@ -247,7 +247,7 @@
           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Only T&lt;span style=&quot; vertical-align:sub;&quot;&gt;m&lt;/span&gt; values within this limit are considered valid.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
          </property>
          <property name="title">
-          <string>Cutoff</string>
+          <string>&amp;Cutoff</string>
          </property>
          <property name="alignment">
           <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
@@ -406,14 +406,44 @@
          </layout>
         </widget>
        </item>
+       <item row="4" column="1">
+        <widget class="QDialogButtonBox" name="buttonBox_process">
+         <property name="standardButtons">
+          <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+         </property>
+        </widget>
+       </item>
       </layout>
      </widget>
     </item>
-    <item row="1" column="0">
-     <widget class="QDialogButtonBox" name="buttonBox_process">
-      <property name="standardButtons">
-       <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+    <item row="0" column="1">
+     <widget class="QTabWidget" name="tabWidget">
+      <property name="currentIndex">
+       <number>3</number>
       </property>
+      <widget class="MplWidget" name="tab_raw">
+       <attribute name="title">
+        <string>Raw Data</string>
+       </attribute>
+      </widget>
+      <widget class="MplWidget" name="tab_derivative">
+       <attribute name="title">
+        <string>&amp;1st derivative</string>
+       </attribute>
+      </widget>
+      <widget class="MplWidget" name="tab_heatmap">
+       <attribute name="title">
+        <string>Heatmap</string>
+       </attribute>
+      </widget>
+      <widget class="MplWidget" name="tab_heatmap_avg">
+       <property name="enabled">
+        <bool>false</bool>
+       </property>
+       <attribute name="title">
+        <string>Heatmap average</string>
+       </attribute>
+      </widget>
      </widget>
     </item>
    </layout>
@@ -423,7 +453,7 @@
     <rect>
      <x>0</x>
      <y>0</y>
-     <width>388</width>
+     <width>808</width>
      <height>29</height>
     </rect>
    </property>
@@ -444,7 +474,7 @@
      <locale language="English" country="UnitedStates"/>
     </property>
     <property name="title">
-     <string>Help</string>
+     <string>Hel&amp;p</string>
     </property>
     <addaction name="actionAbout"/>
     <addaction name="actionAbout_Qt"/>
@@ -465,7 +495,7 @@
   </action>
   <action name="actionAbout_Qt">
    <property name="icon">
-    <iconset resource="icons.qrc">
+    <iconset>
      <normaloff>:/qtlogo.svg</normaloff>:/qtlogo.svg</iconset>
    </property>
    <property name="text">
@@ -473,6 +503,14 @@
    </property>
   </action>
  </widget>
+ <customwidgets>
+  <customwidget>
+   <class>MplWidget</class>
+   <extends>QWidget</extends>
+   <header>mplwidget</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
  <resources>
   <include location="icons.qrc"/>
  </resources>
diff --git a/ui/mplwidget.py b/ui/mplwidget.py
new file mode 100644
index 0000000..58f446b
--- /dev/null
+++ b/ui/mplwidget.py
@@ -0,0 +1,25 @@
+from PyQt5 import QtWidgets
+from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
+from matplotlib.backends.backend_qt5agg import NavigationToolbar2QTAgg as NavigationToolbar
+from matplotlib.figure import Figure
+
+class MplCanvas(FigureCanvas):
+    def __init__(self):
+        self.fig = Figure()
+        self.ax = self.fig.add_subplot(111)
+        FigureCanvas.__init__(self, self.fig)
+        FigureCanvas.setSizePolicy(self, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
+        FigureCanvas.updateGeometry(self)
+
+    def clear(self):
+        self.ax.clear()
+        self.fig.clear()
+
+class MplWidget(QtWidgets.QWidget):
+    def __init__(self, parent = None):
+        QtWidgets.QWidget.__init__(self, parent)
+
+        self.canvas = MplCanvas()
+        self.vbl = QtWidgets.QVBoxLayout()
+        self.vbl.addWidget(self.canvas)
+        self.setLayout(self.vbl)
\ No newline at end of file