diff --git a/BDSMathlib.py b/BDSMathlib.py index 317d3c5..59f78d1 100644 --- a/BDSMathlib.py +++ b/BDSMathlib.py @@ -12,16 +12,18 @@ import libyaff def id_to_color( id ): colors = [ - QColor(54, 22, 115), - QColor(160, 16, 36), - QColor(45, 142, 15), + QColor(255, 255, 255), QColor(168, 149, 17), + QColor(45, 142, 15), + QColor(160, 16, 36), + QColor(54, 22, 115), QColor(36, 10, 85), QColor(118, 8, 23), QColor(31, 105, 7), QColor(124, 109, 8), ] - return colors[id%len(colors)] + chosen_color = colors[id%len(colors)] + return chosen_color class FitFunctionCreator(QObject): diff --git a/ConductivityGroupBox.py b/ConductivityGroupBox.py index e2eca12..2d76d43 100644 --- a/ConductivityGroupBox.py +++ b/ConductivityGroupBox.py @@ -2,8 +2,8 @@ # Form implementation generated from reading ui file 'ConductivityGroupBox.ui' # -# Created: Tue Jul 29 08:56:48 2014 -# by: PyQt4 UI code generator 4.11.1 +# Created: Tue Sep 23 21:38:12 2014 +# by: PyQt4 UI code generator 4.11.1 # # WARNING! All changes made in this file will be lost! @@ -12,21 +12,19 @@ from PyQt4 import QtCore, QtGui try: _fromUtf8 = QtCore.QString.fromUtf8 except AttributeError: - def _fromUtf8( s ): + def _fromUtf8(s): return s try: _encoding = QtGui.QApplication.UnicodeUTF8 - - def _translate( context, text, disambig ): + def _translate(context, text, disambig): return QtGui.QApplication.translate(context, text, disambig, _encoding) except AttributeError: - def _translate( context, text, disambig ): + def _translate(context, text, disambig): return QtGui.QApplication.translate(context, text, disambig) - class Ui_ConductivityGroupBox(object): - def setupUi( self, ConductivityGroupBox ): + def setupUi(self, ConductivityGroupBox): ConductivityGroupBox.setObjectName(_fromUtf8("ConductivityGroupBox")) ConductivityGroupBox.resize(253, 156) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) @@ -63,7 +61,7 @@ class Ui_ConductivityGroupBox(object): self.checkBox_3.setText(_fromUtf8("")) self.checkBox_3.setChecked(True) self.checkBox_3.setObjectName(_fromUtf8("checkBox_3")) - self.gridLayout.addWidget(self.checkBox_3, 3, 3, 1, 1, QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) + self.gridLayout.addWidget(self.checkBox_3, 3, 3, 1, 1, QtCore.Qt.AlignHCenter|QtCore.Qt.AlignVCenter) self.label_2 = QtGui.QLabel(ConductivityGroupBox) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) @@ -137,25 +135,18 @@ class Ui_ConductivityGroupBox(object): QtCore.QObject.connect(self.removeButton, QtCore.SIGNAL(_fromUtf8("clicked()")), ConductivityGroupBox.hide) QtCore.QMetaObject.connectSlotsByName(ConductivityGroupBox) - def retranslateUi( self, ConductivityGroupBox ): + def retranslateUi(self, ConductivityGroupBox): ConductivityGroupBox.setWindowTitle(_translate("ConductivityGroupBox", "GroupBox", None)) ConductivityGroupBox.setTitle(_translate("ConductivityGroupBox", "Conductivity", None)) self.pwrSigma_sd.setText(_translate("ConductivityGroupBox", "TextLabel", None)) - self.label_2.setText(_translate("ConductivityGroupBox", - "

σ\'(DC)

", - None)) + self.label_2.setText(_translate("ConductivityGroupBox", "

σ\'(DC)

", None)) self.label.setText(_translate("ConductivityGroupBox", "Fix", None)) self.removeButton.setText(_translate("ConductivityGroupBox", "Remove", None)) self.label_4.setText(_translate("ConductivityGroupBox", "α", None)) self.rSigma_sd.setText(_translate("ConductivityGroupBox", "TextLabel", None)) - self.rSigma.setToolTip(_translate("ConductivityGroupBox", - "

DC conductivity, should only be seen in the imaginary permitivity. If there is a Jonscher type of Universal Dielectric Response, the ratio of σ"/σ\'(DC) is a constant

", - None)) + self.rSigma.setToolTip(_translate("ConductivityGroupBox", "

DC conductivity, should only be seen in the imaginary permitivity. If there is a Jonscher type of Universal Dielectric Response, the ratio of σ"/σ\'(DC) is a constant

", None)) self.subtractConductivityButton.setText(_translate("ConductivityGroupBox", "Hide", None)) - self.label_3.setText( - _translate("ConductivityGroupBox", "

σ"

", None)) - self.iSigma.setToolTip(_translate("ConductivityGroupBox", - "

If there is a Jonscher type of Universal Dielectric Response, the ratio of σ"/σ\'(DC) is a constant

", - None)) + self.label_3.setText(_translate("ConductivityGroupBox", "

σ"

", None)) + self.iSigma.setToolTip(_translate("ConductivityGroupBox", "

If there is a Jonscher type of Universal Dielectric Response, the ratio of σ"/σ\'(DC) is a constant

", None)) self.iSigma_sd.setText(_translate("ConductivityGroupBox", "TextLabel", None)) diff --git a/Container.py b/Container.py index cdfce21..4b0a76f 100644 --- a/Container.py +++ b/Container.py @@ -32,7 +32,6 @@ class BaseObject(QObject): self.limits = limits # private varaibles - #self.functions = Functions() self._color = QColor("white") self._id_label = None @@ -47,6 +46,10 @@ class BaseObject(QObject): self._param_number = 0 self._abort = False + def set_limits(self, limits): + self.limits = limits + self.updateData() + @pyqtSlot(bool) def abort(self, abort=False): self._abort = abort @@ -86,8 +89,9 @@ class BaseObject(QObject): @color.setter def color(self, c): self._color = c - self.data_curve_real.setPen(c) - self.data_curve_imag.setPen(c) + print c + self.data_curve_real.setPen(color=c, style=Qt.DotLine, width=2.5) + self.data_curve_imag.setPen(color=c, style=Qt.DotLine, width=2.5) @property def widget(self): @@ -124,6 +128,7 @@ class BaseObject(QObject): self.changedData.emit() def updateData(self): + self._frequency = np.logspace(np.log10(self.limits[0]), np.log10(self.limits[1]), 256) self._data = self._func(self.getParameter(), self._frequency) self.data_curve_real.setData(x=self._frequency, y=self._data[0]) self.data_curve_imag.setData(x=self._frequency, y=self._data[1]) @@ -190,7 +195,6 @@ class Static(BaseObject): def function( self, p, x ): BaseObject.function(self,p,x) - eps_inf = p[0] static = np.ones( (2,x.size) )*eps_inf static[1,:] *= 0 # set imag part zero diff --git a/ContainerWidgets.py b/ContainerWidgets.py index 34209a1..e21775a 100644 --- a/ContainerWidgets.py +++ b/ContainerWidgets.py @@ -63,6 +63,7 @@ class BaseWidget(QGroupBox): self.errors = [] self.names = [] self.selector_mask = None # TODO: clean up + self.func_type="None" def remove(self): self.removeMe.emit() @@ -149,6 +150,8 @@ class PeakWidget(BaseWidget,QGroupBox): "beta" ] + self.func_type="HN" + self.inputs = [ self.ui.doubleSpinBox_1, self.ui.doubleSpinBox_2, @@ -163,9 +166,6 @@ class PeakWidget(BaseWidget,QGroupBox): self.ui.label_8, ] - - - for dsb in self.inputs: dsb.valueChanged.connect(self.changeValues) @@ -183,7 +183,7 @@ class PeakWidget(BaseWidget,QGroupBox): self.ui.checkBox_3.setChecked(False) self.ui.checkBox_3.setDisabled(False) self.ui.checkBox_4.setChecked(False) - self.ui.checkBox_3.setDisabled(False) + self.ui.checkBox_4.setDisabled(False) self.ui.doubleSpinBox_3.setDisabled(False) self.ui.doubleSpinBox_4.setDisabled(False) @@ -202,8 +202,10 @@ class PeakWidget(BaseWidget,QGroupBox): self.ui.checkBox_3.setChecked(True) self.ui.checkBox_3.setDisabled(True) self.ui.checkBox_4.setChecked(False) + self.func_type = "CD" else: self.ui.doubleSpinBox_3.setDisabled(False) + self.func_type = "HN" def _distrib_debye(self, state): if state: @@ -215,10 +217,12 @@ class PeakWidget(BaseWidget,QGroupBox): self.ui.checkBox_3.setDisabled(True) self.ui.checkBox_4.setChecked(True) self.ui.checkBox_4.setDisabled(True) + self.func_type = "Debye" else: self.ui.doubleSpinBox_3.setDisabled(False) self.ui.doubleSpinBox_4.setDisabled(False) + self.func_type = "HN" def _distrib_cc(self, state): @@ -229,8 +233,12 @@ class PeakWidget(BaseWidget,QGroupBox): self.ui.checkBox_3.setChecked(False) self.ui.checkBox_4.setChecked(True) self.ui.checkBox_4.setDisabled(True) + self.func_type = "CC" + else: self.ui.doubleSpinBox_4.setDisabled(False) + self.func_type = "HN" + def setId(self, id): @@ -291,6 +299,7 @@ class StaticWidget(BaseWidget, QGroupBox): dsb.valueChanged.connect(self.changeValues) self.ui.removeButton.clicked.connect(self.remove) + self.func_type=r"$\epsilon_\infty$" @@ -314,11 +323,12 @@ class ConductivityWidget(BaseWidget, QGroupBox): self.ui.removeButton.clicked.connect(self.remove) #self.ui.subtractConductivityButton.connect(self.subtract) + self.func_type="Cond." self.names = [ - "iSigma", - "rSigma", - "pwrSigma", + "iSig", + "rSig", + "pwrSig", ] self.errors = [self.ui.iSigma_sd, self.ui.rSigma_sd, @@ -350,6 +360,7 @@ class PowerLawWidget(BaseWidget): self.ui.doubleSpinBox_2 = LogFSpinBox(self) self.ui.gridLayout.addWidget(self.ui.doubleSpinBox_2,1,1) self.ui.removeButton.clicked.connect(self.remove) + self.func_type="Power Law" self.names = ["Amp", "pwrAmp"] self.errors = [self.ui.label_5, @@ -371,8 +382,10 @@ class YaffWidget(BaseWidget): def __init__(self, parent=None): #QGroupBox.__init__(self) BaseWidget.__init__(self) - super(YaffWidget, self).__init__(parent) + + self.func_type="YAFF" # Todo wie bei peak für gg gb gge etc. + self.ui = YAFFparameters.Ui_Form() self.ui.setupUi(self) self.ui.doubleSpinBox_1.setParent(None) @@ -473,11 +486,13 @@ class YaffWidget(BaseWidget): @pyqtSlot(int) def change_model(self,ndx): #ndx = self.ui.comboBox.currentIndex() - mask = [ - (0,0,0,0,1,1,1,1,1,1), - (0,0,0,0,1,1,1,1,0,0), - (0,0,0,0,0,0,0,0,1,1), - (0,0,0,0,0,0,0,0,0,0), + mask = [ # 0 show, 1 hide + (0,0,0,0,1,1,1,1,1,1), # GG + (0,0,0,0,1,1,1,1,0,0), # GGe + (0,1,1,1,1,0,0,0,1,1), # Gb + + (0,0,0,0,0,0,0,0,1,1), # GG + Gb + (0,0,0,0,0,0,0,0,0,0), # GGe + Gb ] self.names = [] diff --git a/QDS.py b/QDS.py index 7033e45..1b6c1bb 100755 --- a/QDS.py +++ b/QDS.py @@ -2,10 +2,13 @@ # -*- encoding: utf-8 -*- _author_ = "Markus Rosenstihl" +import hashlib,uuid +import time import os,sys,re,signal import matplotlib matplotlib.use('agg') + from matplotlib import pyplot from matplotlib.colors import hex2color #matplotlib.rc_file("default.mplrc") @@ -15,7 +18,6 @@ from PyQt4.QtCore import * from PyQt4.QtGui import * import numpy as np -import time import pyqtgraph as pg from Container import Conductivity, PowerComplex, Static, Peak, YAFF @@ -48,7 +50,7 @@ class AppWindow(QMainWindow): self._init_menu() self.function_registry = FunctionRegister() - + self.session_id = uuid.uuid4() self.peakId = 0 self.parameterWidget = ParameterWidget() @@ -68,8 +70,11 @@ class AppWindow(QMainWindow): self.ui.pgPlotWidget_imag.addItem(self.fit_boundary_imag) self.ui.pgPlotWidget_real.addItem(self.fit_boundary_real) - self.fit_boundary_imag.sigRegionChanged.connect(self._update_fit_boundary) - self.fit_boundary_real.sigRegionChanged.connect(self._update_fit_boundary) + # fit boundary signals + self.fit_boundary_imag.sigRegionChanged.connect(self._update_fit_boundary_imag) + self.fit_boundary_imag.sigRegionChangeFinished.connect(self.updatePlot) + self.fit_boundary_real.sigRegionChanged.connect(self._update_fit_boundary_real) + self.fit_boundary_real.sigRegionChangeFinished.connect(self.updatePlot) for pltwidgt in (self.ui.pgPlotWidget_real, self.ui.pgPlotWidget_imag): pltwidgt.setLogMode(x=True, y=True) @@ -240,40 +245,86 @@ class AppWindow(QMainWindow): else: f = open("fitresults.log", "a") - # prepare header - header = "# Date: {date}\n".format(date=time.ctime()) - header += "{n1:13}{n2:13}".format(n1="# 0:T", n2="1:invT") + file_id = hashlib.md5(open(self._file_paths[self._current_file_index]).read()).hexdigest() + pre_header = "# Date: {date}\n".format(date=time.strftime("%Y-%m-%d")) + pre_header += "# Time: {time}\n# SessionID={id}\n".format(time=time.strftime("%H:%M:%S"), id=self.session_id) pars = [] - base_filename = os.path.splitext(self.filepath)[0] + base_filename, file_ext = os.path.splitext(self.filepath) # print "Registered Functions (saveFitResult): ",self.function_registry.get_registered_functions() + header = "{n1:13}{n2:13}".format(n1="# 0:T", n2="1:invT") varnum = 2 # T, invT are the first two columns + + # sort peaks by time constant tau + sorted_functions = list() + tau_comp = 0 for i_fcn, fcn in enumerate(self.function_registry.get_registered_functions()): + if fcn.id_string == "hn": + for i,varname in enumerate(fcn.widget.names): + if varname == "tau": + if fcn._beta[i] <= tau_comp: + sorted_functions.append(fcn) + else: + sorted_functions.insert(0,fcn) + tau_comp = fcn._beta[i] + # eps_infty to the front + for a in self.function_registry.get_registered_functions(): + print a.id_string + if a.id_string == "eps_infty": + sorted_functions.insert(0,a) + print a + # sort the rest lexigraphically + for a in self.function_registry.get_registered_functions(): + if a.id_string == "pwr": + sorted_functions.append(a) + print a + for a in self.function_registry.get_registered_functions(): + if a.id_string == "cond": + sorted_functions.append(a) + print a + for a in self.function_registry.get_registered_functions(): + if a.id_string == "yaff": + print a + sorted_functions.append(a) + + print sorted_functions + + for i_fcn, fcn in enumerate(sorted_functions): fit_function_name = fcn.id_string for i, name in enumerate(fcn.widget.names): # get variable names header += "{n:13}{n_sd:13}".format(n="%i:%s"%(varnum, name), n_sd="%i:%s_sd"%(varnum+1, name)) varnum += 2 - # write for each function extra file + # write for each function an extra file fit_filename = "%s_%i.fit"%(base_filename, i_fcn) f_fcn = open(fit_filename, 'w') - f_fcn.write("# %s\n"%fit_function_name) - f_fcn.flush() - np.savetxt(f_fcn, fcn.resampleData(self.data.frequency)) - f_fcn.close() + # retrieve correct function type peak + #if fit_function_name == "hn": + f_fcn.write("# type=%s\n"%fcn.widget.func_type) + f_fcn.write("# SourceID=%s\n"%file_id) + #else: + # f_fcn.write("# type=%s\n"%fit_function_name) for i,par in enumerate(fcn._beta): # params # TODO: ughh if fcn._selector_mask is not None: if fcn._selector_mask[i]: pars.extend([par]) pars.extend([fcn._sd_beta[i]]) + f_fcn.write('# param=%s %e %e\n'%(fcn.widget.names[i], par, fcn._sd_beta[i])) else: pars.extend([par]) pars.extend([fcn._sd_beta[i]]) + f_fcn.write('# param=%s %e %e\n'%(fcn.widget.names[i], par, fcn._sd_beta[i])) + + # finish writing fit function file + f_fcn.flush() + np.savetxt(f_fcn, fcn.resampleData(self.data.frequency)) + f_fcn.close() # append fit limits header header += "%-13s%-13s\n"%("fit_xlow", "fit_xhigh") - # write new header if fit model changed + # write new header if fit model changed TODO: more robust detection if self._last_written_header != header: + f.write(pre_header) f.write(header) f.flush() self._last_written_header = header @@ -387,9 +438,12 @@ class AppWindow(QMainWindow): def addPeak(self, pos): id_list = [ key.id_num for key in - self.function_registry.get_registered_functions().keys() - if key.id_label == 'hn'] + self.function_registry.get_registered_functions() + if key.id_string == 'hn'] + for k in self.function_registry.get_registered_functions(): + print k.id_num,k.id_label self.peakId = 1 + print id_list while self.peakId in id_list: self.peakId += 1 _peak = Peak(id_num=self.peakId, @@ -549,9 +603,12 @@ class AppWindow(QMainWindow): for fcn in self.function_registry.get_registered_functions(): p0.extend(fcn.getParameter()) funcs.append(fcn) + + # calculate parametrized curve self.data.set_fit(p0, funcs) + # replot data and fit, TODO: replot only if measurement data changed self.data.data_curve_real.setData(self.data.frequency, self.data.epsilon.real) self.data.data_curve_imag.setData(self.data.frequency, self.data.epsilon.imag) @@ -569,10 +626,27 @@ class AppWindow(QMainWindow): self.data.fitted_curve_real.setData(freq, intermediate_data[0]) self.data.fitted_curve_imag.setData(freq, intermediate_data[1]) - def _update_fit_boundary( self ): + def _update_fit_boundary_imag( self ): + """ + Update real region when with imag reagion + """ self.fit_boundary_real.setRegion(self.fit_boundary_imag.getRegion()) - self.fit_boundary_imag.setRegion(self.fit_boundary_real.getRegion()) + self._update_fit_boundary() + def _update_fit_boundary_real( self ): + """ + Update imag region when with real reagion + """ + self.fit_boundary_imag.setRegion(self.fit_boundary_real.getRegion()) + self._update_fit_boundary() + + def _update_fit_boundary(self): + """ + Update limits in container. + """ + for container in self.function_registry.get_registered_functions(): + lims = [10**i for i in self.fit_boundary_real.getRegion()] + container.set_limits(lims) def sigint_handler(*args): """ diff --git a/gracedriver.py b/gracedriver.py index 6bba731..7a22093 100644 --- a/gracedriver.py +++ b/gracedriver.py @@ -28,10 +28,9 @@ class grace: np.savetxt(tmp_name, np.array([x, y]).T) #tmp_fd.close() self.cmds.append('READ NXY "%s"\n'%tmp_name) - self.cmds.append('S%i SYMBOL SIZE 0.6\n'%(self.data_counter)) + self.cmds.append('S%i SYMBOL SIZE 0.7\n'%(self.data_counter)) self.cmds.append('S%i SYMBOL COLOR 1\n'%(self.data_counter)) - - + #self.cmds.append('S%i SYMBOL FILL COLOR %i\n'%(self.data_counter, self.data_counter)) self.cmds.append('S%i SYMBOL FILL PATTERN 1\n'%(self.data_counter)) self.cmds.append('S%i SYMBOL 1\n'%(self.data_counter)) # No line @@ -49,6 +48,8 @@ class grace: sym = kwds["sym"] if sym in self.sym_map.keys(): self.cmds.append('S%i SYMBOL %i\n'%(self.data_counter, self.sym_map[sym])) + if sym in ['+', 'x', '*']: + self.cmds.append('S%i SYMBOL COLOR %i\n'%(self.data_counter, self.data_counter)) else: print "Symbol not known: %s"%sym @@ -93,16 +94,20 @@ class grace: if __name__ == "__main__": print "Testing Grace driver" - nums = 50 + np.random.seed(1337) # make it reproducible + nums = 30 gr = grace() - for i in xrange(20): - gr.plot(np.arange(nums), np.random.random(nums), label="label %i"%i, + t = np.linspace(0,1,nums) + for i in xrange(30): + gr.plot(t, i + np.sin(2*np.pi * 3 * t + i*0.33 ) + 0.3*np.random.random(nums), + label="label %i"%i, ls=gr.ls_map.keys()[i%(len(gr.ls_map))], sym=gr.sym_map.keys()[i%(len(gr.sym_map))], ) gr.xlabel(r"xlabel / \xm\sl\N\0") gr.ylabel(r"ylabel / \xt\sS\N\0") gr.save("test.agr") + print "created test.agr" os.system("xmgrace test.agr") print "deleting test.agr" os.remove("test.agr") \ No newline at end of file