From cf75c8ee099d509c9de94d6225f07103333a8c31 Mon Sep 17 00:00:00 2001
From: Alexander Minges
Date: Fri, 30 Jan 2015 20:14:56 +0100
Subject: [PATCH] Embedded plots into GUI
---
.gitignore | 2 +-
pydsf.py | 583 +++++++++++++++++++++-----------------------
ui/Ui_mainwindow.py | 57 +++--
ui/icons.qrc | 4 +-
ui/mainwindow.py | 64 +++--
ui/mainwindow.ui | 60 ++++-
ui/mplwidget.py | 25 ++
7 files changed, 446 insertions(+), 349 deletions(-)
create mode 100644 ui/mplwidget.py
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", "
ΔT
"))
self.doubleSpinBox_dt.setSuffix(_translate("MainWindow", " °C"))
self.groupBox_cutoff.setToolTip(_translate("MainWindow", "Only Tm values within this limit are considered valid.
"))
- 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 @@
-
- qtlogo.svg
-
+
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 @@
0
0
- 388
- 642
+ 808
+ 646
@@ -35,7 +35,7 @@
false
-
+
-
@@ -247,7 +247,7 @@
<html><head/><body><p>Only T<span style=" vertical-align:sub;">m</span> values within this limit are considered valid.</p></body></html>
- Cutoff
+ &Cutoff
Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
@@ -406,14 +406,44 @@
+ -
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
- -
-
-
- QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
-
+
+
+ 3
+
+
+ Raw Data
+
+
+
+
+ &1st derivative
+
+
+
+
+ Heatmap
+
+
+
+
+ false
+
+
+ Heatmap average
+
+
@@ -423,7 +453,7 @@
0
0
- 388
+ 808
29
@@ -444,7 +474,7 @@
- Help
+ Hel&p
@@ -465,7 +495,7 @@
-
+
:/qtlogo.svg:/qtlogo.svg
@@ -473,6 +503,14 @@
+
+
+ MplWidget
+ QWidget
+
+ 1
+
+
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