1
0
Fork 0
mirror of https://github.com/Athemis/PyDSF.git synced 2025-04-10 08:31:51 +00:00

Embedded plots into GUI

This commit is contained in:
Alexander Minges 2015-01-30 20:14:56 +01:00
parent 926fb01502
commit cf75c8ee09
7 changed files with 446 additions and 349 deletions

2
.gitignore vendored
View file

@ -21,7 +21,7 @@ var/
*.egg-info/ *.egg-info/
.installed.cfg .installed.cfg
*.egg *.egg
.idea .idea/
# PyInstaller # PyInstaller
# Usually these files are written by a python script from a template # Usually these files are written by a python script from a template

475
pydsf.py
View file

@ -1,6 +1,7 @@
#! /usr/bin/env python2 #! /usr/bin/env python2
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import csv import csv
import multiprocessing as mp
try: try:
import matplotlib as mpl import matplotlib as mpl
@ -23,22 +24,23 @@ except ImportError:
raise ImportError('----- NumPy must be installed. -----') raise ImportError('----- NumPy must be installed. -----')
try: try:
from scipy.signal import filtfilt, butter from scipy.signal import filtfilt, butter
from scipy import interpolate from scipy import interpolate
from scipy import optimize from scipy import optimize
except ImportError: except ImportError:
raise ImportError('----- SciPy must be installed. -----') raise ImportError('----- SciPy must be installed. -----')
class Well: class Well:
def __init__(self, owner): def __init__(self, owner):
self.owner = owner self.owner = owner
self.name = None self.name = None
self.raw = np.zeros(self.owner.reads, dtype=np.float) self.raw = np.zeros(self.owner.reads, dtype=np.float)
self.filtered = 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.derivatives = np.zeros((4, self.owner.reads))
self.splines = {"raw": None, self.splines = {"raw": None,
"filtered": None, "filtered": None,
"derivative1": None} "derivative1": None}
self.tm = np.NaN self.tm = np.NaN
self.tm_sd = np.NaN self.tm_sd = np.NaN
self.baseline_correction = owner.baseline_correction self.baseline_correction = owner.baseline_correction
@ -62,9 +64,10 @@ class Well:
for t in self.owner.temprange: for t in self.owner.temprange:
temp = self.splines[spline].derivatives(t) temp = self.splines[spline].derivatives(t)
for i in range(4): 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: try:
baseline = peakutils.baseline(y) baseline = peakutils.baseline(y)
return baseline return baseline
@ -83,7 +86,7 @@ class Well:
self.owner.denatured_wells.append(self) self.owner.denatured_wells.append(self)
if self.owner.tm_cutoff_low != self.owner.t1 or self.owner.tm_cutoff_high != self.owner.t1: 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 x = self.owner.temprange
y = self.derivatives[1] y = self.derivatives[1]
@ -93,19 +96,19 @@ class Well:
try: try:
peak_indexes = peakutils.indexes(y, min_dist=len(x)) # calculate a rough estimate of peaks; set min_dist 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 # temperature range to only find one/the highest peak
tm = peakutils.interpolate(x, y, ind=peak_indexes)[0] # increase resolution by fitting gaussian function tm = peakutils.interpolate(x, y, ind=peak_indexes)[0] # increase resolution by fitting gaussian function
# to peak # to peak
except: except:
return np.NaN # In case of error, return no peak return np.NaN # In case of error, return no peak
try: try:
# Check if the peak is within cutoff range # Check if the peak is within cutoff range
if tm and tm >= self.owner.tm_cutoff_low and tm <= self.owner.tm_cutoff_high: 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 self.owner.denatured_wells.remove(self) # If everything is fine, remove the denatured flag
return tm # and return the Tm return tm # and return the Tm
else: else:
return np.NaN # otherwise, return NaN return np.NaN # otherwise, return NaN
except: except:
return np.NaN # In case of error, return NaN return np.NaN # In case of error, return NaN
@ -115,31 +118,31 @@ class Well:
denatured, no Tm was found, or if the initial signal intensity is above a user definded denatured, no Tm was found, or if the initial signal intensity is above a user definded
threshold. threshold.
""" """
denatured = True # Assumption is that the well is denatured 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 if self in self.owner.denatured_wells: # check if the well is already flagged as denatured
return denatured # return true if it is 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): if self.tm and (self.tm <= self.owner.tm_cutoff_low or self.tm >= self.owner.tm_cutoff_high):
denatured = True denatured = True
return denatured return denatured
for i in self.derivatives[1]: # Iterate over all points in the first derivative for i in self.derivatives[1]: # Iterate over all points in the first derivative
if i > 0: # If a positive slope is found if i > 0: # If a positive slope is found
denatured = False # set denatured flag to False denatured = False # set denatured flag to False
reads = int(round(self.owner.reads/10)) # How many values should be checked against the signal threshold: 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 # 1/10 of the total number of data point
read = 0 # Initialize running variable representing the current data point read = 0 # Initialize running variable representing the current data point
if not denatured: if not denatured:
for j in self.filtered: # Iterate over the filtered data for j in self.filtered: # Iterate over the filtered data
if self.owner.signal_threshold: # If a signal threshold was defined 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 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. # and check for values larger than the threshold.
denatured = True # Set flag to True if a match is found denatured = True # Set flag to True if a match is found
print("{}: {}".format(self.name, j)) print("{}: {}".format(self.name, j))
return denatured # and return return denatured # and return
read += 1 read += 1
return denatured return denatured
@ -161,15 +164,17 @@ class Well:
if self.tm is None: if self.tm is None:
self.tm = np.NaN self.tm = np.NaN
class Experiment: 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.replicates = replicates
self.cols = cols self.cols = cols
self.rows = rows self.rows = rows
self.t1 = t1 self.t1 = t1
self.t2 = t2 self.t2 = t2
self.dt = dt 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.reads = int(round((t2 + 1 - t1) / dt))
self.wellnum = self.cols * self.rows self.wellnum = self.cols * self.rows
self.files = files self.files = files
@ -178,10 +183,10 @@ class Experiment:
self.max_tm = None self.max_tm = None
self.min_tm = None self.min_tm = None
self.replicates = None self.replicates = None
self.gui=gui self.gui = gui
self.signal_threshold = signal_threshold self.signal_threshold = signal_threshold
self.avg_plate = None self.avg_plate = None
self.baseline_correction=baseline_correction self.baseline_correction = baseline_correction
if cutoff_low: if cutoff_low:
self.tm_cutoff_low = cutoff_low self.tm_cutoff_low = cutoff_low
else: else:
@ -193,18 +198,23 @@ class Experiment:
if color_range: if color_range:
self.color_range = color_range self.color_range = color_range
else: else:
self.color_range = (self.t1, self.t2) self.color_range = None
self.plates = [] self.plates = []
i = 1 i = 1
for file in files: 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 plate.id = i
self.plates.append(plate) self.plates.append(plate)
i += 1 i += 1
if len(files) > 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' self.avg_plate.id = 'average'
def analyze(self): def analyze(self):
@ -213,28 +223,29 @@ class Experiment:
if len(self.plates) > 1: if len(self.plates) > 1:
#self.tm_replicates = 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 ) # self.tm_replicates_sd = np.zeros( self.wellnum, dtype=float )
for i in range(self.wellnum): for i in range(self.wellnum):
tmp = [] tmp = []
for plate in self.plates: for plate in self.plates:
tm = plate.wells[i].tm tm = plate.wells[i].tm
self.avg_plate.wells[i].name = plate.wells[i].name self.avg_plate.wells[i].name = plate.wells[i].name
if plate.wells[i] not in plate.denatured_wells: if plate.wells[i] not in plate.denatured_wells:
tmp.append(tm) tmp.append(tm)
if len(tmp) > 0: 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 = np.mean(tmp)
self.avg_plate.wells[i].tm_sd = np.std(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: else:
self.avg_plate.denatured_wells.append(self.avg_plate.wells[i]) self.avg_plate.denatured_wells.append(self.avg_plate.wells[i])
class Plate: 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.cols = cols
self.rows = rows self.rows = rows
self.owner = owner self.owner = owner
@ -250,7 +261,7 @@ class Plate:
self.dt = dt self.dt = dt
else: else:
self.dt = owner.dt 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.reads = int(round((t2 + 1 - t1) / dt))
self.wellnum = self.cols * self.rows self.wellnum = self.cols * self.rows
self.filename = filename self.filename = filename
@ -279,23 +290,21 @@ class Plate:
self.tms = [] self.tms = []
for i in range(self.wellnum): for i in range(self.wellnum):
well = Well(owner = self) well = Well(owner=self)
self.wells.append(well) self.wells.append(well)
#self.analyze()
def analytikJena(self): def analytikJena(self):
""" """
Data processing for Analytik Jena qTower 2.0 export files Data processing for Analytik Jena qTower 2.0 export files
""" """
with open(self.filename, 'r') as f: with open(self.filename, 'r') as f:
reader = csv.reader(f, delimiter=';', quoting=csv.QUOTE_NONE) reader = csv.reader(f, delimiter=';', quoting=csv.QUOTE_NONE)
i = 0 i = 0
for row in reader: for row in reader:
temp = np.zeros(self.reads, dtype=float) temp = np.zeros(self.reads, dtype=float)
for read in range(self.reads+1): for read in range(self.reads + 1):
if read > 0: if read > 0:
try: try:
temp[read - 1] = row[read] temp[read - 1] = row[read]
@ -306,15 +315,15 @@ class Plate:
self.wells[i].raw = temp self.wells[i].raw = temp
i += 1 i += 1
def analyze(self, gui=None): def analyze(self, gui=None):
try: try:
# Try to access data file in the given path # 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: except IOError as e:
# If the file is not found, or not accessible: abort # If the file is not found, or not accessible: abort
print('Error accessing file: {}'.format(e)) print('Error accessing file: {}'.format(e))
if self.type == 'Analytik Jena qTOWER 2.0/2.2': if self.type == 'Analytik Jena qTOWER 2.0/2.2':
self.analytikJena() self.analytikJena()
if gui: if gui:
@ -335,7 +344,7 @@ class Plate:
print("rows") print("rows")
if self.replicates == 'cols': if self.replicates == 'cols':
print("cols") print("cols")
#print(self.tms) # print(self.tms)
self.max_tm = max(self.tms) self.max_tm = max(self.tms)
self.min_tm = min(self.tms) self.min_tm = min(self.tms)
@ -370,7 +379,7 @@ class Plate:
f.write('{:<10s}'.format(str(t))) f.write('{:<10s}'.format(str(t)))
for well in self.wells: for well in self.wells:
d = well.raw[i] 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') f.write('\n')
i += 1 i += 1
@ -387,7 +396,7 @@ class Plate:
f.write('{:<10s}'.format(str(t))) f.write('{:<10s}'.format(str(t)))
for well in self.wells: for well in self.wells:
d = well.filtered[i] 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') f.write('\n')
i += 1 i += 1
@ -404,7 +413,7 @@ class Plate:
f.write('{:<10s}'.format(str(t))) f.write('{:<10s}'.format(str(t)))
for well in self.wells: for well in self.wells:
d = well.derivatives[1][i] 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') f.write('\n')
i += 1 i += 1
@ -417,204 +426,180 @@ class Plate:
def update_progress_bar(bar, value): def update_progress_bar(bar, value):
bar.setValue(value) bar.setValue(value)
def plot_tm_heatmap_average(experiment, gui=None): class PlotResults():
"""
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 def __init__(self, experiment):
# if c < experiment.tm_cutoff_low: # Check if Tm is lower that the cutoff self.experiment = experiment
# 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:
x_values.append(x) # Add values to the respective arrays def plot_tm_heatmap_single(self, plate, widget):
y_values.append(y) """
c_values.append(c) Plot Tm heatmap (Fig. 1)
x += 1 # Increase column by one """
if x > experiment.cols: # If maximum column per row is reached x = 1 # Position in columns
x = 1 # reset column to one y = 1 # Position in rows
y += 1 # and increase row by one 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 fig1 = canvas.fig # new figure
ax1 = fig1.add_subplot(1, 1, 1) # A single canvas ax1 = fig1.add_subplot(1, 1, 1) # A single canvas
ax1.autoscale(tight=True) # Scale plate size ax1.autoscale(tight=True) # Scale plate size
ax1.xaxis.set_major_locator(ticker.MaxNLocator(experiment.cols + 1)) # n columns ax1.xaxis.set_major_locator(ticker.MaxNLocator(plate.cols + 1)) # n columns
ax1.yaxis.set_major_locator(ticker.MaxNLocator(experiment.rows + 1)) # n rows ax1.yaxis.set_major_locator(ticker.MaxNLocator(plate.rows + 1)) # n rows
if experiment.color_range: if plate.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 cax = ax1.scatter(x_values, y_values, s=305, c=c_values, marker='s', vmin=plate.color_range[0],
else: vmax=plate.color_range[1]) # plot wells and color using the colormap
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
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
else: else:
y = well.derivatives[1] # grab y values from the first derivative of the well cax = ax1.scatter(x_values, y_values, s=305, c=c_values, marker='s') # plot wells and color using the colormap
ax.xaxis.set_major_locator(ticker.MaxNLocator(4)) # only show three tickmarks on both axes cax2 = ax1.scatter(dx_values, dy_values, s=80, c='white', marker='x', linewidths=(1.5,))
ax.yaxis.set_major_locator(ticker.MaxNLocator(4)) ax1.invert_yaxis() # invert y axis to math plate layout
if well not in plate.denatured_wells: # check if well is denatured (without determined Tm) cbar = fig1.colorbar(cax) # show colorbar
tm = well.tm # if not, grab its Tm ax1.set_xlabel('Columns') # set axis and colorbar label
ax1.set_ylabel('Rows')
if str(plate.id) == 'average':
title = '$T_m$ heatmap (average)'
else: else:
tm = np.NaN # else set Tm to np.NaN title = '$T_m$ heatmap (plate #{})'.format(str(plate.id))
if tm: ax1.set_title(title)
ax.axvline(x=tm) # plot vertical line at the Tm cbar.set_label(u"Temperature [°C]")
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()
# if gui:
# update_progress_bar(gui.pb, 75)
def plot_raw(plate, gui=None): def plot_derivative(self, plate, widget):
""" """
Plot raw data (Fig. 3) Plot derivatives (Fig. 2)
""" """
fig3 = plt.figure() # new figure canvas = widget.canvas
fig3.suptitle('Raw Data (plate #{})'.format(str(plate.id))) # set title 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 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 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 = fig2.add_subplot(plate.rows, plate.cols, plot_num) # add new subplot
ax.autoscale(tight=True) # scale to data ax.autoscale(tight=True) # scale to data
ax.set_title(well.name, size='xx-small') # set title of current subplot to well identifier ax.set_title(well.name, size='xx-small') # set title of current subplot to well identifier
if well in plate.denatured_wells: if well in plate.denatured_wells:
ax.patch.set_facecolor('#FFD6D6') 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 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_xlabel(u'T [°C]', size='xx-small')
ax.set_ylabel('I', 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 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 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.xaxis.set_major_locator(ticker.MaxNLocator(4)) # only show three tickmarks on both axes
ax.yaxis.set_major_locator(ticker.MaxNLocator(4)) 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 if well not in plate.denatured_wells: # check if well is denatured (without determined Tm)
ax.axvspan(plate.tm_cutoff_high, plate.t2, facecolor='0.8', alpha=0.5) # shade higher cutoff area tm = well.tm # if not, grab its Tm
for label in ax.get_xticklabels() + ax.get_yticklabels(): # set fontsize for all tick labels to xx-small else:
label.set_fontsize('xx-small') 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 cax = ax.plot(x, y) # plot data to the current subplot
canvas.draw()
# if gui:
# update_progress_bar(gui.pb, 100)
# gui.pb.hide()
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()
#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)) def plot_raw(self, plate, widget):
#plot(plate) """
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

View file

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'mainwindow.ui' # 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 # by: PyQt5 UI code generator 5.4
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
@ -12,7 +12,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object): class Ui_MainWindow(object):
def setupUi(self, MainWindow): def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow") MainWindow.setObjectName("MainWindow")
MainWindow.resize(388, 642) MainWindow.resize(808, 646)
MainWindow.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) MainWindow.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates))
self.centralWidget = QtWidgets.QWidget(MainWindow) self.centralWidget = QtWidgets.QWidget(MainWindow)
self.centralWidget.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) 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.setFlat(False)
self.groupBox_experiment.setCheckable(False) self.groupBox_experiment.setCheckable(False)
self.groupBox_experiment.setObjectName("groupBox_experiment") self.groupBox_experiment.setObjectName("groupBox_experiment")
self.gridLayout = QtWidgets.QGridLayout(self.groupBox_experiment) self.formLayout_3 = QtWidgets.QFormLayout(self.groupBox_experiment)
self.gridLayout.setObjectName("gridLayout") self.formLayout_3.setObjectName("formLayout_3")
self.label_instrument = QtWidgets.QLabel(self.groupBox_experiment) self.label_instrument = QtWidgets.QLabel(self.groupBox_experiment)
self.label_instrument.setObjectName("label_instrument") 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) self.comboBox_instrument = QtWidgets.QComboBox(self.groupBox_experiment)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
@ -37,7 +37,7 @@ class Ui_MainWindow(object):
self.comboBox_instrument.setSizePolicy(sizePolicy) self.comboBox_instrument.setSizePolicy(sizePolicy)
self.comboBox_instrument.setObjectName("comboBox_instrument") self.comboBox_instrument.setObjectName("comboBox_instrument")
self.comboBox_instrument.addItem("") 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 = QtWidgets.QGroupBox(self.groupBox_experiment)
self.groupBox_data.setEnabled(True) self.groupBox_data.setEnabled(True)
self.groupBox_data.setObjectName("groupBox_data") self.groupBox_data.setObjectName("groupBox_data")
@ -72,7 +72,7 @@ class Ui_MainWindow(object):
self.listWidget_data.setAlternatingRowColors(True) self.listWidget_data.setAlternatingRowColors(True)
self.listWidget_data.setObjectName("listWidget_data") self.listWidget_data.setObjectName("listWidget_data")
self.gridLayout_4.addWidget(self.listWidget_data, 0, 0, 2, 1) 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 = QtWidgets.QGroupBox(self.groupBox_experiment)
self.groupBox_temp.setEnabled(True) self.groupBox_temp.setEnabled(True)
self.groupBox_temp.setAutoFillBackground(False) self.groupBox_temp.setAutoFillBackground(False)
@ -108,7 +108,7 @@ class Ui_MainWindow(object):
self.doubleSpinBox_dt.setProperty("value", 1.0) self.doubleSpinBox_dt.setProperty("value", 1.0)
self.doubleSpinBox_dt.setObjectName("doubleSpinBox_dt") self.doubleSpinBox_dt.setObjectName("doubleSpinBox_dt")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.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 = QtWidgets.QGroupBox(self.groupBox_experiment)
self.groupBox_cutoff.setEnabled(True) self.groupBox_cutoff.setEnabled(True)
self.groupBox_cutoff.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) 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.setDecimals(1)
self.doubleSpinBox_lower.setObjectName("doubleSpinBox_lower") self.doubleSpinBox_lower.setObjectName("doubleSpinBox_lower")
self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.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 = QtWidgets.QGroupBox(self.groupBox_experiment)
self.groupBox_signal_threshold.setEnabled(True) self.groupBox_signal_threshold.setEnabled(True)
self.groupBox_signal_threshold.setCheckable(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.setMaximum(1000000)
self.spinBox_signal_threshold.setObjectName("spinBox_signal_threshold") self.spinBox_signal_threshold.setObjectName("spinBox_signal_threshold")
self.verticalLayout.addWidget(self.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 = QtWidgets.QGroupBox(self.groupBox_experiment)
self.groupBox_cbar.setEnabled(True) self.groupBox_cbar.setEnabled(True)
self.groupBox_cbar.setCheckable(True) self.groupBox_cbar.setCheckable(True)
@ -170,15 +170,31 @@ class Ui_MainWindow(object):
self.doubleSpinBox_cbar_end.setDecimals(1) self.doubleSpinBox_cbar_end.setDecimals(1)
self.doubleSpinBox_cbar_end.setObjectName("doubleSpinBox_cbar_end") self.doubleSpinBox_cbar_end.setObjectName("doubleSpinBox_cbar_end")
self.formLayout_4.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.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.formLayout_3.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.groupBox_cbar)
self.gridLayout_2.addWidget(self.groupBox_experiment, 0, 0, 1, 1) self.buttonBox_process = QtWidgets.QDialogButtonBox(self.groupBox_experiment)
self.buttonBox_process = QtWidgets.QDialogButtonBox(self.centralWidget)
self.buttonBox_process.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) self.buttonBox_process.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.buttonBox_process.setObjectName("buttonBox_process") 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) MainWindow.setCentralWidget(self.centralWidget)
self.menuBar = QtWidgets.QMenuBar(MainWindow) 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.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates))
self.menuBar.setObjectName("menuBar") self.menuBar.setObjectName("menuBar")
self.menuFile = QtWidgets.QMenu(self.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.label_cbar_end.setBuddy(self.doubleSpinBox_cbar_end)
self.retranslateUi(MainWindow) self.retranslateUi(MainWindow)
self.tabWidget.setCurrentIndex(3)
QtCore.QMetaObject.connectSlotsByName(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, 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.label_dt.setText(_translate("MainWindow", "<html><head/><body><p>&Delta;T</p></body></html>"))
self.doubleSpinBox_dt.setSuffix(_translate("MainWindow", " °C")) 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.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.label_cutoff_high.setText(_translate("MainWindow", "&Upper"))
self.doubleSpinBox_upper.setSuffix(_translate("MainWindow", " °C")) self.doubleSpinBox_upper.setSuffix(_translate("MainWindow", " °C"))
self.label_cutoff_low.setText(_translate("MainWindow", "Lower")) 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.doubleSpinBox_cbar_start.setSuffix(_translate("MainWindow", " °C"))
self.label_cbar_end.setText(_translate("MainWindow", "En&d")) self.label_cbar_end.setText(_translate("MainWindow", "En&d"))
self.doubleSpinBox_cbar_end.setSuffix(_translate("MainWindow", " °C")) 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.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.actionQuit.setText(_translate("MainWindow", "&Quit"))
self.actionAbout.setText(_translate("MainWindow", "&About")) self.actionAbout.setText(_translate("MainWindow", "&About"))
self.actionAbout_Qt.setText(_translate("MainWindow", "About &Qt")) self.actionAbout_Qt.setText(_translate("MainWindow", "About &Qt"))
from .mplwidget import MplWidget

View file

@ -1,5 +1,3 @@
<RCC> <RCC>
<qresource prefix="/"> <qresource prefix="/"/>
<file>qtlogo.svg</file>
</qresource>
</RCC> </RCC>

View file

@ -17,6 +17,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
""" """
Class documentation goes here. Class documentation goes here.
""" """
def __init__(self, parent=None): def __init__(self, parent=None):
""" """
Constructor Constructor
@ -33,6 +34,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.statusBar.showMessage("Welcome to PyDSF") self.statusBar.showMessage("Welcome to PyDSF")
@pyqtSlot("QAbstractButton*") @pyqtSlot("QAbstractButton*")
def on_buttonBox_open_reset_clicked(self, button): 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): elif button == self.buttonBox_open_reset.button(QDialogButtonBox.Reset):
self.listWidget_data.clear() self.listWidget_data.clear()
print("Data cleared") print("Data cleared")
# self.radioButton_rep_rows.setEnabled(False) # self.radioButton_rep_rows.setEnabled(False)
# self.radioButton_rep_columns.setEnabled(False) # self.radioButton_rep_columns.setEnabled(False)
@pyqtSlot("QString") @pyqtSlot("QString")
@ -61,10 +63,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.groupBox_temp.setEnabled(True) self.groupBox_temp.setEnabled(True)
else: else:
self.groupBox_temp.setEnabled(False) self.groupBox_temp.setEnabled(False)
# self.groupBox_data.setEnabled(True) # self.groupBox_data.setEnabled(True)
# self.groupBox_cutoff.setEnabled(True) # self.groupBox_cutoff.setEnabled(True)
# self.groupBox_cbar.setEnabled(True) # self.groupBox_cbar.setEnabled(True)
# self.groupBox_signal_threshold.setEnabled(True) # self.groupBox_signal_threshold.setEnabled(True)
@pyqtSlot() @pyqtSlot()
def on_buttonBox_process_accepted(self): 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) QMessageBox.critical(self, 'Error', "No data file loaded!", QMessageBox.Close, QMessageBox.Close)
return return
if self.spinBox_signal_threshold.value() == 0 and self.groupBox_signal_threshold.isChecked(): 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.progressBar.setEnabled(True)
self.statusBar.showMessage("Processing...") self.statusBar.showMessage("Processing...")
@ -90,7 +93,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
c_lower = self.doubleSpinBox_lower.value() c_lower = self.doubleSpinBox_lower.value()
c_upper = self.doubleSpinBox_upper.value() c_upper = self.doubleSpinBox_upper.value()
if self.groupBox_cbar.isChecked(): 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(): if self.groupBox_signal_threshold.isChecked():
signal_threshold = self.spinBox_signal_threshold.value() signal_threshold = self.spinBox_signal_threshold.value()
@ -99,29 +102,53 @@ class MainWindow(QMainWindow, Ui_MainWindow):
files = [] files = []
for item in items: for item in items:
files.append(item.text()) 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() 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) # 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) # 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?", 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: if save_data == QMessageBox.Yes:
dialog = QFileDialog() dialog = QFileDialog()
dialog.setFileMode(QFileDialog.Directory) dialog.setFileMode(QFileDialog.Directory)
folder = dialog.getExistingDirectory(self, 'Choose path for results') folder = dialog.getExistingDirectory(self, 'Choose path for results')
for plate in exp.plates: for plate in exp.plates:
plate.write_tm_table('{}/plate_{}_04_tm.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_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_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_raw_table('{}/plate_{}_01_raw_data.csv'.format(folder, str(plate.id)))
if exp.avg_plate: if exp.avg_plate:
exp.avg_plate.write_avg_tm_table('{}/plate_{}_05_tm_avg.csv'.format(folder, str(exp.avg_plate.id))) exp.avg_plate.write_avg_tm_table('{}/plate_{}_05_tm_avg.csv'.format(folder, str(exp.avg_plate.id)))
#plot(plate, self) #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.progressBar.setEnabled(False)
self.statusBar.showMessage("Finished!") self.statusBar.showMessage("Finished!")
@ -135,6 +162,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
QApplication.quit() QApplication.quit()
pyqtSlot() pyqtSlot()
def on_actionQuit_triggered(self): def on_actionQuit_triggered(self):
""" """
Slot documentation goes here. Slot documentation goes here.

View file

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>388</width> <width>808</width>
<height>642</height> <height>646</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -35,7 +35,7 @@
<property name="checkable"> <property name="checkable">
<bool>false</bool> <bool>false</bool>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label_instrument"> <widget class="QLabel" name="label_instrument">
<property name="text"> <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> <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>
<property name="title"> <property name="title">
<string>Cutoff</string> <string>&amp;Cutoff</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
@ -406,14 +406,44 @@
</layout> </layout>
</widget> </widget>
</item> </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> </layout>
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="0" column="1">
<widget class="QDialogButtonBox" name="buttonBox_process"> <widget class="QTabWidget" name="tabWidget">
<property name="standardButtons"> <property name="currentIndex">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> <number>3</number>
</property> </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> </widget>
</item> </item>
</layout> </layout>
@ -423,7 +453,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>388</width> <width>808</width>
<height>29</height> <height>29</height>
</rect> </rect>
</property> </property>
@ -444,7 +474,7 @@
<locale language="English" country="UnitedStates"/> <locale language="English" country="UnitedStates"/>
</property> </property>
<property name="title"> <property name="title">
<string>Help</string> <string>Hel&amp;p</string>
</property> </property>
<addaction name="actionAbout"/> <addaction name="actionAbout"/>
<addaction name="actionAbout_Qt"/> <addaction name="actionAbout_Qt"/>
@ -465,7 +495,7 @@
</action> </action>
<action name="actionAbout_Qt"> <action name="actionAbout_Qt">
<property name="icon"> <property name="icon">
<iconset resource="icons.qrc"> <iconset>
<normaloff>:/qtlogo.svg</normaloff>:/qtlogo.svg</iconset> <normaloff>:/qtlogo.svg</normaloff>:/qtlogo.svg</iconset>
</property> </property>
<property name="text"> <property name="text">
@ -473,6 +503,14 @@
</property> </property>
</action> </action>
</widget> </widget>
<customwidgets>
<customwidget>
<class>MplWidget</class>
<extends>QWidget</extends>
<header>mplwidget</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources> <resources>
<include location="icons.qrc"/> <include location="icons.qrc"/>
</resources> </resources>

25
ui/mplwidget.py Normal file
View file

@ -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)