#!/usr/bin/env python # -*- encoding: utf-8 -*- import os import sys import re import signal from PyQt4.QtCore import * from PyQt4.QtGui import * import matplotlib from mathlib import fit_anneal, fit_lbfgsb, fit_odr, hn matplotlib.use('agg') #from matplotlibWidget import PlotWidget from matplotlib import pyplot from matplotlib.colors import hex2color #matplotlib.rc_file("default.mplrc") import numpy as N import QDSMain from data import Data, Conductivity, conductivity, Peak import pyqtgraph as pg #import yaff class AppWindow(QMainWindow): def __init__(self, parent=None): super(AppWindow, self).__init__(parent) self.ui = QDSMain.Ui_MainWindow() self.ui.setupUi(self) self.picked_artist = None self.data = None self.Conductivity = None self._lines = dict() self.peakId = 0 self.peakBoxes = {} ## menubar fileMenu = self.menuBar().addMenu("File") openFile = QAction("&Open", self) openFile.setShortcut(QKeySequence.Open) openFile.triggered.connect(self.openFile) fileMenu.addAction(openFile) saveFile = QAction("&Save Fit Result", self) saveFile.setShortcut(QKeySequence.Save) saveFile.triggered.connect(self.saveFitResult) fileMenu.addAction(saveFile) # fitting methods fitMenu = self.menuBar().addMenu("Standard Fits") # lm fit_lmAction = QAction("&Levenberg-Marquardt", self) fit_lmAction.setShortcut(QKeySequence("Ctrl+F")) fitMenu.addAction(fit_lmAction) # lbfgsb fit_lbfgsbAction = QAction("&L-BFGS-B", self) fitMenu.addAction(fit_lbfgsbAction) # Simulated Annealing fit_annealAction = QAction("&Simulated Annealing", self) fitMenu.addAction(fit_annealAction) # YAFF yaffMenu = self.menuBar().addMenu("YAFF") start_yaff = QAction("&Startparam.", self) yaffMenu.addAction(start_yaff) fit_yaff = QAction("&Fit", self) yaffMenu.addAction(fit_yaff) self.signalMapper = QSignalMapper(self) for i, fit_action in enumerate([fit_lmAction, fit_lbfgsbAction, fit_annealAction ]): self.signalMapper.setMapping(fit_action, i) fit_action.triggered.connect(self.signalMapper.map) self.signalMapper.mapped.connect(self.fitData) # save fitted values #self.ui.actionSave_FitResult.triggered.connect(self.saveFitResult)# replaced by menu self.data = Data() self.fit_boundary = pg.LinearRegionItem(brush=QColor(254,254,254,10)) self.ui.graphicsView.addItem(self.data.data_curve) self.ui.graphicsView.addItem(self.data.fitted_curve) self.ui.graphicsView.addItem(self.fit_boundary) self.ui.graphicsView.setLogMode(x=True, y=True) self.ui.graphicsView.showGrid(x=True, y=True) self.ui.graphicsView.setLabel("bottom","Frequency",units="Hz") self.ui.graphicsView.setLabel("left", "Dielectric loss", units="Debye") self.peak_box_layout = QGridLayout() self.ui.scrollAreaWidgetContents.setLayout(self.peak_box_layout) def mousePressEvent(self, evt): pos = evt.pos() if self.ui.graphicsView.sceneRect().contains(pos): # translate position to data coordinates data_pos = self.ui.graphicsView.plotItem.vb.mapSceneToView(pos) if self.ui.actionAdd_Peak.isChecked() and not self.ui.actionAdd_Cond.isChecked(): self.addPeak(data_pos) self.ui.actionAdd_Peak.setChecked(False) if self.ui.actionAdd_Cond.isChecked() and not self.ui.actionAdd_Peak.isChecked(): self.addCond(data_pos) self.ui.actionAdd_Cond.setChecked(False) def saveFitResult(self): """ Saving fit parameters to fitresults.log including temperature """ self.saveFitFigure() if not os.path.exists("fitresults.log"): f = open("fitresults.log", "w") else: f = open("fitresults.log", "a") # write header f.write('# T ') parfmt = "%.2f" # T formatting # if self.Conductivity != None: pass# always true f.write("%8s %8s %8s " % ("e_s", "sig", "pow_sig")) parfmt += " %.3g %.3g %.2f " # conductivity formatting for i, pb in enumerate(self.peakBoxes): enum_peak = ("e_inf_%i" % i, "tau_%i" % i, "alpha_%i" % i, "beta_%i" % i) f.write("%8s %8s %8s %8s " % enum_peak) parfmt += " %.3g %.3g %.2f %.2f" # peak formatting f.write("high_lim lower_lim") # TODO: store limits f.write('\n') f.flush() #f.write("%3.2f "%(self.data.meta["T"])) pars = list(self.fitresult) pars.insert(0, self.data.meta["T"]) N.savetxt(f, N.array([pars, ]), fmt=parfmt, delimiter=" ") f.close() def saveFitFigure(self): fig = pyplot.Figure(figsize=(3.54, 2.75)) font = {'family' : 'sans serif', 'weight' : 'normal', 'size' : 16} matplotlib.rc('font', **font) print self.data.epsilon_fit.shape, type(self.data.epsilon_fit) pyplot.loglog(self.data.frequency, self.data.epsilon.imag, 'bo', markersize=4, label="Data") pyplot.loglog(self.data.frequency, self.data.epsilon_fit, 'r-', lw=2, label="Fit") for i,peak in enumerate(self.peakBoxes): f,eps = peak.get_data() color = hex2color(str(peak.get_color().name())) pyplot.loglog(f,eps, ls="--", color=color , lw=1.5, label="Peak %i"%i) if self.Conductivity != None: f,eps = self.Conductivity.get_conductivity() color = hex2color(str(self.Conductivity.get_color().name())) pyplot.loglog(f,eps, ls="-.", color=color, lw=1.5, label="Cond.") f,eps = self.Conductivity.get_epsilon_static() pyplot.loglog(f,eps, ls=":", color=color, lw=1.5, label=r'$\epsilon_0$') pyplot.legend(title="T=%.1f K"%(self.data.meta["T"]) ) pyplot.grid() pyplot.xlabel('f/Hz') pyplot.ylabel('eps"') pyplot.savefig("test.png") fig.clear() def set_fit_xlimits(self, xmin, xmax): self.data.fit_limits = (xmin, xmax, None, None) self.updatePlot() def addCond(self, pos): if self.Conductivity != None: return self.statusBar().showMessage("Click on graph") self.Conductivity = Conductivity(mpl=self.ui.graphicsView, limits=self.data.fit_limits) self.Conductivity.changedData.connect(self.updatePlot) self.Conductivity.setParameter(0, 1 / (10**pos.x() / 10**pos.y() / 2 / N.pi), 1.0) self.ui.scrollAreaWidgetContents.layout().addWidget(self.Conductivity.widget) self.Conductivity.widget.ui.removeButton.clicked.connect(self.delCond) def delCond(self): self.cond_param = None self.cond = None self.ui.graphicsView.removeItem(self.Conductivity.mpl_line) self.ui.graphicsView.removeItem(self.Conductivity.mpl_line_static) del self.Conductivity self.Conductivity = None self.updatePlot() def addPeak(self, pos): self.peakId += 1 self.statusBar().showMessage("Select Peak Position") peak = Peak(id=self.peakId, mpl=self.ui.graphicsView, limits=self.data.fit_limits) # connect to delPeak peak.widget.ui.removeButton.clicked.connect(self.delPeak) peak.changedData.connect(self.updatePlot) peak.setParameter(delta_eps=10**pos.y(), tau=1 / (10**pos.x()/2/N.pi), a=1, b=1) self.peakBoxes[peak] = None wdgt_num = self.peak_box_layout.rowCount() for i,pb in enumerate(self.peakBoxes.keys()): self.peak_box_layout.addWidget(pb.widget, i+wdgt_num, 0) #self.ui.scrollArea.resize() # self.updatePlot() def delPeak(self): deletePeaks = [] for i in xrange(self.peak_box_layout.count()): print i for i, peak in enumerate(self.peakBoxes.keys()): if peak.widget.isHidden(): self.ui.graphicsView.removeItem(peak.mpl_line) deletePeaks.append(peak) for peak in deletePeaks: self.peakBoxes.pop(peak) self.updatePlot() def fitData(self, method): if self.Conductivity != None: start_parameter = list(self.Conductivity.getParameter()) fixed_params = [i for i in self.Conductivity.getFixed()] else: start_parameter = [0, 0, 1] fixed_params = [0, 0, 0] for pb in self.peakBoxes.keys(): [start_parameter.append(i) for i in pb.getParameter()] [fixed_params.append(i) for i in pb.getFixed()] log10fmin, log10fmax = self.fit_boundary.getRegion() xmin,xmax,ymin,ymax = self.data.fit_limits self.data.fit_limits = [10**log10fmin, 10**log10fmax,ymin,ymax] fit_methods = [fit_odr, fit_lbfgsb, fit_anneal] print "StartParameter", start_parameter print "FixedParameter", fixed_params print "Limits (xmin, xmax, ymin, ymax)", self.data.fit_limits _freq, _fit = self.data.get_data() result = fit_methods[method](_freq, _fit.imag, start_parameter, fixed_params) self.fitresult = result for i, pb in enumerate(self.peakBoxes.keys()): delta_eps, tau, a, b = result[3 + i * 4:3 + (i + 1) * 4] pb.setParameter(delta_eps, tau, a, b) e_static, sigma, sigma_N = result[:3] if self.Conductivity != None: self.Conductivity.setParameter(e_static, sigma, sigma_N) #print "*** FIT RESULTS ***" #print u"\u03c3" #print u"\u0394\u03b5" self.updatePlot() def openFile(self): path = unicode(QFileDialog.getOpenFileName(self, "Open file")) #path = "MCM42PG0_199.96K.dat" # TODO anaylize file (LF,MF, HF) and act accordingly data = N.loadtxt(path, skiprows=4) self.setWindowTitle(os.path.basename(path)) numpat = re.compile('\d+\.\d+') try: Temp = None for line in open(path).readlines(): if re.search("Fixed", line) or re.search("Temp", line): print "Found line with Fixed or Temp" Temp = float(re.search(numpat, line).group()) print "Temperature found in file:", Temp break if Temp == None: raise ValueError except: Temp = QInputDialog.getDouble(self, "No temperature found in data set", "Temperature/K:", value=0.00)[0] # mask the data to values > 0 (loglog plot) mask = (data[:, 1] > 0) & (data[:, 2] > 0) #& (data[:,2]>1e-3) & (data[:,0] > 1e-2) _freq = data[mask, 0] _die_stor = data[mask, 1] _die_loss = data[mask, 2] self.data.set_data(_freq, _die_stor, _die_loss) self.data.meta["T"] = Temp self.fit_boundary.setRegion([N.log10(_freq.min()), N.log10(_freq.max())]) self.updatePlot() def updatePlot(self): nu = self.data.frequency fit = N.zeros(len(nu)) for peak in self.peakBoxes.keys(): params = peak.getParameter() fit += hn(params, nu) #fit += peak.get_data()[1] if self.Conductivity != None: print "Cond. given" params = self.Conductivity.getParameter()[1:] fit += conductivity(params, nu) fit += self.Conductivity.getParameter()[0] # eps static self.data.epsilon_fit = fit[:] self.data.data_curve.setData(self.data.frequency, self.data.epsilon.imag) if len(self.peakBoxes) > 0 and self.Conductivity != None: self.data.fitted_curve.setData(nu, fit) def sigint_handler(*args): """Handler for the SIGINT signal (CTRL + C). """ sys.stderr.write('\r') if QMessageBox.question(None, '', "Are you sure you want to quit?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) == QMessageBox.Yes: QApplication.quit() if __name__ == '__main__': signal.signal(signal.SIGINT, sigint_handler) app = QApplication(sys.argv) timer = QTimer() timer.start(1000) # Check every second for Strg-c on Cmd line timer.timeout.connect(lambda: None) main = AppWindow() main.showMaximized() main.raise_() sys.exit(app.exec_())