diff --git a/.hgignore b/.hgignore index 2c9154d..60ab3cb 100644 --- a/.hgignore +++ b/.hgignore @@ -1,2 +1,3 @@ syntax: glob *.pyc +.idea diff --git a/ConductivityGroupBox.py b/ConductivityGroupBox.py index 48a017a..249e6da 100644 --- a/ConductivityGroupBox.py +++ b/ConductivityGroupBox.py @@ -2,8 +2,8 @@ # Form implementation generated from reading ui file 'ConductivityGroupBox.ui' # -# Created: Wed Jul 10 18:57:09 2013 -# by: PyQt4 UI code generator 4.10.2 +# Created: Fri Feb 21 17:15:59 2014 +# by: PyQt4 UI code generator 4.10.3 # # WARNING! All changes made in this file will be lost! @@ -26,7 +26,7 @@ except AttributeError: class Ui_ConductivityGroupBox(object): def setupUi(self, ConductivityGroupBox): ConductivityGroupBox.setObjectName(_fromUtf8("ConductivityGroupBox")) - ConductivityGroupBox.resize(289, 168) + ConductivityGroupBox.resize(255, 150) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -37,7 +37,7 @@ class Ui_ConductivityGroupBox(object): self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2")) self.gridLayout = QtGui.QGridLayout() self.gridLayout.setSizeConstraint(QtGui.QLayout.SetFixedSize) - self.gridLayout.setSpacing(5) + self.gridLayout.setSpacing(1) self.gridLayout.setContentsMargins(0, 0, -1, -1) self.gridLayout.setObjectName(_fromUtf8("gridLayout")) self.checkBox_2 = QtGui.QCheckBox(ConductivityGroupBox) @@ -73,6 +73,7 @@ class Ui_ConductivityGroupBox(object): sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.pushButton_2.sizePolicy().hasHeightForWidth()) self.pushButton_2.setSizePolicy(sizePolicy) + self.pushButton_2.setAutoRepeat(True) self.pushButton_2.setObjectName(_fromUtf8("pushButton_2")) self.gridLayout.addWidget(self.pushButton_2, 1, 3, 1, 1) self.label_2 = QtGui.QLabel(ConductivityGroupBox) @@ -90,6 +91,8 @@ class Ui_ConductivityGroupBox(object): sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.pushButton_5.sizePolicy().hasHeightForWidth()) self.pushButton_5.setSizePolicy(sizePolicy) + self.pushButton_5.setMinimumSize(QtCore.QSize(50, 0)) + self.pushButton_5.setAutoRepeat(True) self.pushButton_5.setObjectName(_fromUtf8("pushButton_5")) self.gridLayout.addWidget(self.pushButton_5, 3, 2, 1, 1) self.pushButton_6 = QtGui.QPushButton(ConductivityGroupBox) @@ -98,6 +101,7 @@ class Ui_ConductivityGroupBox(object): sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.pushButton_6.sizePolicy().hasHeightForWidth()) self.pushButton_6.setSizePolicy(sizePolicy) + self.pushButton_6.setAutoRepeat(True) self.pushButton_6.setObjectName(_fromUtf8("pushButton_6")) self.gridLayout.addWidget(self.pushButton_6, 3, 3, 1, 1) self.lineEdit_2 = QtGui.QLineEdit(ConductivityGroupBox) @@ -137,6 +141,8 @@ class Ui_ConductivityGroupBox(object): sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.pushButton_3.sizePolicy().hasHeightForWidth()) self.pushButton_3.setSizePolicy(sizePolicy) + self.pushButton_3.setMinimumSize(QtCore.QSize(50, 0)) + self.pushButton_3.setAutoRepeat(True) self.pushButton_3.setObjectName(_fromUtf8("pushButton_3")) self.gridLayout.addWidget(self.pushButton_3, 2, 2, 1, 1) self.pushButton_4 = QtGui.QPushButton(ConductivityGroupBox) @@ -145,6 +151,7 @@ class Ui_ConductivityGroupBox(object): sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.pushButton_4.sizePolicy().hasHeightForWidth()) self.pushButton_4.setSizePolicy(sizePolicy) + self.pushButton_4.setAutoRepeat(True) self.pushButton_4.setObjectName(_fromUtf8("pushButton_4")) self.gridLayout.addWidget(self.pushButton_4, 2, 3, 1, 1) self.pushButton_1 = QtGui.QPushButton(ConductivityGroupBox) @@ -153,6 +160,8 @@ class Ui_ConductivityGroupBox(object): sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.pushButton_1.sizePolicy().hasHeightForWidth()) self.pushButton_1.setSizePolicy(sizePolicy) + self.pushButton_1.setMinimumSize(QtCore.QSize(50, 0)) + self.pushButton_1.setAutoRepeat(True) self.pushButton_1.setAutoDefault(False) self.pushButton_1.setDefault(False) self.pushButton_1.setFlat(False) diff --git a/ConductivityGroupBox.ui b/ConductivityGroupBox.ui index c6cf3b8..a2626f0 100644 --- a/ConductivityGroupBox.ui +++ b/ConductivityGroupBox.ui @@ -6,8 +6,8 @@ 0 0 - 289 - 168 + 255 + 150 @@ -41,7 +41,7 @@ 0 - 5 + 1 @@ -106,6 +106,9 @@ + + + true + @@ -132,9 +135,18 @@ 0 + + + 50 + 0 + + - + + true + @@ -148,6 +160,9 @@ + + + true + @@ -219,9 +234,18 @@ 0 + + + 50 + 0 + + - + + true + @@ -235,6 +259,9 @@ + + + true + @@ -245,9 +272,18 @@ 0 + + + 50 + 0 + + - + + true + false diff --git a/ConductivityWidget.py b/ConductivityWidget.py index 9d08760..1978014 100644 --- a/ConductivityWidget.py +++ b/ConductivityWidget.py @@ -34,7 +34,7 @@ class ConductivityWidget(QGroupBox): self.signalMapper.mapped.connect(self.changeValues) def changeValues(self, num): - logstep = 1.29154967 # 10 log even steps per decade + logstep = 10**0.05 # 10 log even steps per decade linstep = 0.05 # 0-3 down/up for d_eps and tau, respectively # 4-7 down, up for a, b diff --git a/PeakGroupBox.py b/PeakGroupBox.py index 9bb2071..eb28b6d 100644 --- a/PeakGroupBox.py +++ b/PeakGroupBox.py @@ -2,8 +2,8 @@ # Form implementation generated from reading ui file 'PeakGroupBox.ui' # -# Created: Wed Jul 10 18:57:09 2013 -# by: PyQt4 UI code generator 4.10.2 +# Created: Fri Feb 21 17:15:59 2014 +# by: PyQt4 UI code generator 4.10.3 # # WARNING! All changes made in this file will be lost! @@ -68,6 +68,7 @@ class Ui_PeakGroupBox(object): sizePolicy.setHeightForWidth(self.pushButton_7.sizePolicy().hasHeightForWidth()) self.pushButton_7.setSizePolicy(sizePolicy) self.pushButton_7.setMinimumSize(QtCore.QSize(56, 0)) + self.pushButton_7.setAutoRepeat(True) self.pushButton_7.setObjectName(_fromUtf8("pushButton_7")) self.gridLayout.addWidget(self.pushButton_7, 4, 2, 1, 1) self.label_2 = QtGui.QLabel(PeakGroupBox) @@ -96,6 +97,7 @@ class Ui_PeakGroupBox(object): self.pushButton_1.setSizePolicy(sizePolicy) self.pushButton_1.setMinimumSize(QtCore.QSize(56, 0)) self.pushButton_1.setBaseSize(QtCore.QSize(0, 0)) + self.pushButton_1.setAutoRepeat(True) self.pushButton_1.setAutoDefault(False) self.pushButton_1.setDefault(False) self.pushButton_1.setFlat(False) @@ -109,6 +111,7 @@ class Ui_PeakGroupBox(object): sizePolicy.setHeightForWidth(self.pushButton_6.sizePolicy().hasHeightForWidth()) self.pushButton_6.setSizePolicy(sizePolicy) self.pushButton_6.setMinimumSize(QtCore.QSize(56, 0)) + self.pushButton_6.setAutoRepeat(True) self.pushButton_6.setObjectName(_fromUtf8("pushButton_6")) self.gridLayout.addWidget(self.pushButton_6, 3, 3, 1, 1) self.label = QtGui.QLabel(PeakGroupBox) @@ -127,6 +130,7 @@ class Ui_PeakGroupBox(object): sizePolicy.setHeightForWidth(self.pushButton_5.sizePolicy().hasHeightForWidth()) self.pushButton_5.setSizePolicy(sizePolicy) self.pushButton_5.setMinimumSize(QtCore.QSize(56, 0)) + self.pushButton_5.setAutoRepeat(True) self.pushButton_5.setObjectName(_fromUtf8("pushButton_5")) self.gridLayout.addWidget(self.pushButton_5, 3, 2, 1, 1) self.removeButton = QtGui.QPushButton(PeakGroupBox) @@ -146,6 +150,7 @@ class Ui_PeakGroupBox(object): sizePolicy.setHeightForWidth(self.pushButton_8.sizePolicy().hasHeightForWidth()) self.pushButton_8.setSizePolicy(sizePolicy) self.pushButton_8.setMinimumSize(QtCore.QSize(56, 0)) + self.pushButton_8.setAutoRepeat(True) self.pushButton_8.setObjectName(_fromUtf8("pushButton_8")) self.gridLayout.addWidget(self.pushButton_8, 4, 3, 1, 1) self.label_3 = QtGui.QLabel(PeakGroupBox) @@ -165,6 +170,7 @@ class Ui_PeakGroupBox(object): sizePolicy.setHeightForWidth(self.pushButton_4.sizePolicy().hasHeightForWidth()) self.pushButton_4.setSizePolicy(sizePolicy) self.pushButton_4.setMinimumSize(QtCore.QSize(56, 0)) + self.pushButton_4.setAutoRepeat(True) self.pushButton_4.setObjectName(_fromUtf8("pushButton_4")) self.gridLayout.addWidget(self.pushButton_4, 2, 3, 1, 1) self.label_1 = QtGui.QLabel(PeakGroupBox) @@ -207,6 +213,7 @@ class Ui_PeakGroupBox(object): sizePolicy.setHeightForWidth(self.pushButton_3.sizePolicy().hasHeightForWidth()) self.pushButton_3.setSizePolicy(sizePolicy) self.pushButton_3.setMinimumSize(QtCore.QSize(56, 0)) + self.pushButton_3.setAutoRepeat(True) self.pushButton_3.setObjectName(_fromUtf8("pushButton_3")) self.gridLayout.addWidget(self.pushButton_3, 2, 2, 1, 1) self.label_4 = QtGui.QLabel(PeakGroupBox) @@ -229,6 +236,7 @@ class Ui_PeakGroupBox(object): sizePolicy.setHeightForWidth(self.pushButton_2.sizePolicy().hasHeightForWidth()) self.pushButton_2.setSizePolicy(sizePolicy) self.pushButton_2.setMinimumSize(QtCore.QSize(56, 0)) + self.pushButton_2.setAutoRepeat(True) self.pushButton_2.setObjectName(_fromUtf8("pushButton_2")) self.gridLayout.addWidget(self.pushButton_2, 1, 3, 1, 1) self.gridLayout.setColumnStretch(1, 1) diff --git a/PeakGroupBox.ui b/PeakGroupBox.ui index d3d7ef8..0ea599e 100644 --- a/PeakGroupBox.ui +++ b/PeakGroupBox.ui @@ -108,6 +108,9 @@ - + + true + @@ -168,6 +171,9 @@ - + + true + false @@ -199,6 +205,9 @@ + + + true + @@ -234,6 +243,9 @@ - + + true + @@ -275,6 +287,9 @@ + + + true + @@ -313,6 +328,9 @@ + + + true + @@ -402,6 +420,9 @@ - + + true + @@ -447,6 +468,9 @@ + + + true + diff --git a/PeakWidget.py b/PeakWidget.py index 7248ad3..a46a0f1 100644 --- a/PeakWidget.py +++ b/PeakWidget.py @@ -67,9 +67,8 @@ class PeakWidget(QGroupBox): self.setTitle("Peak %i" % id) def setColor(self, color): - r, g, b = color palette = self.palette() - palette.setColor(QPalette.Foreground, QColor(r, g, b)) + palette.setColor(QPalette.Foreground, color) self.setPalette(palette) def peakParameter(self): diff --git a/QDS.py b/QDS.py index d8931f2..560935b 100755 --- a/QDS.py +++ b/QDS.py @@ -7,110 +7,28 @@ import signal from PyQt4.QtCore import * from PyQt4.QtGui import * +import matplotlib -from mathlib import fit_anneal, fit_lbfgsb, fit_odr, hn, id_to_color -from matplotlibWidget import PlotWidget +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 -import PeakWidget -from data import Data, Conductivity, conductivity + +from data import Data, Conductivity, conductivity, Peak +import pyqtgraph as pg + #import yaff - -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() - - - - - -def tau_peak(f, a, b): - tau = (N.sin(N.pi * a / 2. / (b + 1)) / N.sin(N.pi * a * b / 2. / (b + 1))) ** (1 / a) - tau /= 2 * N.pi * f - return tau - - - - - - - - - - - - - - - - - - - - - - - -class Peak(QObject): - changedData = pyqtSignal() - - def __init__(self, id=None, mpl=None): - QObject.__init__(self) - super(Peak, self).__init__() - - self.color = id_to_color(id) - self.widget = PeakWidget.PeakWidget() - self.widget.setId(id) - self.widget.setColor(map(int, [255 * i for i in self.color])) - self.widget.changedTable.connect(self.updatePeak) - self.mpl = mpl - self.mpl_line = None - - - def getParameter(self): - p = self.widget.peakParameter() - return p - - def getFixed(self): - p = self.widget.fixedParameter() - return p - - def setParameter(self, delta_eps=None, tau=None, a=None, b=None): - self.widget.updateTable(delta_eps, tau, a, b) - self.updatePeak() - - def updatePeak(self): - # get current axis limits - x_min, x_max = self.mpl.canvas.axes.get_xlim() - y_min, y_max = self.mpl.canvas.axes.get_ylim() - - nu = N.logspace(N.log10(x_min), N.log10(x_max), 2048) - y = hn(self.getParameter(), nu) - # clip data to axes limits - mask = (y < y_max) & (y > y_min) - y = y[mask] - nu = nu[mask] - if self.mpl_line == None: - self.mpl_line, = self.mpl.canvas.axes.loglog(nu, y, '--', label="Peak %i" % (self.widget.id), - animated=True) # peak - self.mpl_line.set_color(self.color) - else: - self.mpl_line.set_xdata(nu) - self.mpl_line.set_ydata(y) - self.changedData.emit() - - class AppWindow(QMainWindow): def __init__(self, parent=None): super(AppWindow, self).__init__(parent) @@ -132,6 +50,13 @@ class AppWindow(QMainWindow): 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 @@ -159,39 +84,41 @@ class AppWindow(QMainWindow): self.signalMapper.mapped.connect(self.fitData) # save fitted values - self.ui.actionSave_FitResult.triggered.connect(self.saveFitResult) - # the plot area, a matplotlib widget - self.mplWidget = PlotWidget(self.ui.mplWidget) - self.mplWidget.canvas.draw() - self.mplWidget.updateGeometry() - # what to do with CIDs? - self.cid = [] - self.cid.append(self.mplWidget.canvas.mpl_connect("button_press_event", self.mpl_button_press)) - self.cid.append(self.mplWidget.canvas.mpl_connect("pick_event", self.mpl_button_pick)) - self.cid.append(self.mplWidget.canvas.mpl_connect("button_release_event", self.mpl_button_release)) - #self.cid.append(self.mplWidget.canvas.mpl_connect("resize_event", self.myresizeEvent)) - self.mplWidget.toolbar.spanSelectedTrigger.connect(self.set_fit_xlimits) + #self.ui.actionSave_FitResult.triggered.connect(self.saveFitResult)# replaced by menu - def resizeEvent(self, evt): - """resizing the main window executes this method - TODO: FIX RESIZEING keeping mainwindow maximised for now - :param evt: - """ - self.mplWidget.canvas.draw() - self.mplWidget._bg_cache = self.mplWidget.canvas.copy_from_bbox(self.mplWidget.canvas.axes.bbox) - for line in self.mplWidget.canvas.axes.get_lines(): - line.set_animated(False) - self.mplWidget.canvas.draw() - for line in self.mplWidget.canvas.axes.get_lines(): - line.set_animated(True) + 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: @@ -215,44 +142,56 @@ class AppWindow(QMainWindow): 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'$\eps_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 mpl_button_release(self, event): - ax = self.mplWidget.canvas.axes - if self.picked_artist: - if not event.inaxes: # moved outside the plot, add back to original position - ax.add_artist(self.picked_artist) - else: # we move one of the three points determinig the peak - self.picked_artist.set_xdata(event.xdata) - self.picked_artist.set_ydata(event.ydata) - ax.add_artist(self.picked_artist) - for peak in self.peakBoxes.keys(): - peak.updatePeak() - self.picked_artist = None - self.mplWidget.canvas.draw_idle() - - def mpl_button_pick(self, event): - self.picked_artist = event.artist - event.artist.remove() - self.mplWidget.canvas.draw_idle() def addCond(self, pos): if self.Conductivity != None: return self.statusBar().showMessage("Click on graph") - self.Conductivity = Conductivity(mpl=self.mplWidget) + self.Conductivity = Conductivity(mpl=self.ui.graphicsView, limits=self.data.fit_limits) self.Conductivity.changedData.connect(self.updatePlot) - self.Conductivity.setParameter(0, 1 / (pos[0] / pos[1] / 2 / N.pi), 1.0) + 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.Conductivity.mpl_line.remove() - self.Conductivity.mpl_line_static.remove() + 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() @@ -262,27 +201,27 @@ class AppWindow(QMainWindow): self.peakId += 1 self.statusBar().showMessage("Select Peak Position") - peak = Peak(id=self.peakId, mpl=self.mplWidget) + 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.setParameter(delta_eps=pos[1], tau=1 / (2. * N.pi * pos[0]), a=1, b=1) - 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 - for pb in self.peakBoxes.keys(): - self.ui.scrollAreaWidgetContents.layout().addWidget(pb.widget) - self.updatePlot() + 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.ui.scrollAreaWidgetContents.layout().count()): + for i in xrange(self.peak_box_layout.count()): print i for i, peak in enumerate(self.peakBoxes.keys()): if peak.widget.isHidden(): - peak.mpl_line.remove() + self.ui.graphicsView.removeItem(peak.mpl_line) deletePeaks.append(peak) for peak in deletePeaks: self.peakBoxes.pop(peak) @@ -300,6 +239,9 @@ class AppWindow(QMainWindow): [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 @@ -318,27 +260,12 @@ class AppWindow(QMainWindow): #print u"\u0394\u03b5" self.updatePlot() - def mpl_button_press(self, event): - """ - Handles the clicks on the matplotlib figure canvas - """ - if self.ui.actionAdd_Peak.isChecked() and event.inaxes: - x, y = event.xdata, event.ydata - self.addPeak((x, y)) - self.ui.actionAdd_Peak.setChecked(False) - self.statusBar().clear() - if self.ui.actionAdd_Cond.isChecked() and event.inaxes: - x, y = event.xdata, event.ydata - self.addCond((x, y)) - self.ui.actionAdd_Cond.setChecked(False) - self.statusBar().clear() - def openFile(self): - ax = self.mplWidget.canvas.axes - ax.clear() 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 @@ -356,93 +283,40 @@ class AppWindow(QMainWindow): _freq = data[mask, 0] _die_stor = data[mask, 1] _die_loss = data[mask, 2] - # clear the figure - ax.clear() - #if self.data != None: - # self.data.remove_curves() - self.data = Data(_freq, _die_stor, _die_loss) + self.data.set_data(_freq, _die_stor, _die_loss) self.data.meta["T"] = Temp - self.data.data_curve, = ax.loglog(self.data.frequency, - self.data.epsilon.imag, - 'b.', - markersize=4, - label="Data", - animated=True) - ax.set_xlabel("Frequency/Hz", fontsize=16) - #ax.set_ylabel(u'\u03B5"', fontsize=16) - ax.set_ylabel(u'e"', fontsize=16) + self.fit_boundary.setRegion([N.log10(_freq.min()), N.log10(_freq.max())]) - ax.autoscale(True) - ax.set_xlim(_freq.min()/3, _freq.max()*3) - - self.legend = ax.legend(title="T=%.2f" % Temp) - for line in ax.get_lines(): - line.set_animated(False) - ax.grid() - self.mplWidget.canvas.draw() - # weird behaviour need to draw all first, then set_animated the redraw - for line in ax.get_lines(): - line.set_animated(True) - self.legend.set_animated(True) - ax.autoscale(False) - self.mplWidget._bg_cache = self.mplWidget.canvas.copy_from_bbox(ax.bbox) self.updatePlot() + def updatePlot(self): - ax = self.mplWidget.canvas.axes 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 - # clip data to axes limits - y_min, y_max = ax.get_ylim() - mask = (fit < y_max) & (fit > y_min) - #mask = N.ones(len(fit), dtype="bool") - if self.data.fitted_curve == None: - self.data.fitted_curve, = ax.loglog(nu[mask], fit[mask], - 'k-', - alpha=0.5, - label="Sum", - animated=True) - else: - self.data.fitted_curve.set_xdata(nu[mask]) - self.data.fitted_curve.set_ydata(fit[mask]) - # handling of fit limit bars - # if self.mplWidget._axvlims != []: - # [axv.remove() for axv in self.mplWidget._axvlims] - # self.mplWidget._axvlims = [] - # if self.mplWidget._axvname != []: - # [axvname.remove() for axvname in self.mplWidget._axvname] - # self.mplWidget._axvname = [] - #print self.mplWidget._axvlims - if self.mplWidget._axvlims == []: - for i,xlim in enumerate(self.data.fit_limits[:2]): - self.mplWidget._axvlims.append(ax.axvline(xlim, color="k", ls="--", alpha=0.5, animated=True)) - self.mplWidget._axvname.append(ax.text(xlim, y_min*3. , "%.3g"%xlim, - horizontalalignment='center', - verticalalignment='center', - animated=True) ) - else: - for i,xlim in enumerate(self.data.fit_limits[:2]): - self.mplWidget._axvlims[i].set_xdata(xlim) - self.mplWidget._axvname[i].set_x(xlim) - self.mplWidget._axvname[i].set_text("%.3g"%xlim) + 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) - self.mplWidget.canvas.restore_region(self.mplWidget._bg_cache) - self.legend = ax.legend(title="T=%.2f" % (self.data.meta["T"])) - self.legend.set_animated(True) - for animated_artist in ax.findobj(match=lambda x: x.get_animated()): - #print "updatePlot: animated artist:",animated_artist - ax.draw_artist(animated_artist) - self.mplWidget.canvas.blit(ax.bbox) +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) diff --git a/QDSMain.py b/QDSMain.py index 8ebf11e..164f509 100644 --- a/QDSMain.py +++ b/QDSMain.py @@ -2,8 +2,8 @@ # Form implementation generated from reading ui file 'QDSMain.ui' # -# Created: Wed Jul 10 18:57:09 2013 -# by: PyQt4 UI code generator 4.10.2 +# Created: Fri Feb 21 17:15:59 2014 +# by: PyQt4 UI code generator 4.10.3 # # WARNING! All changes made in this file will be lost! @@ -26,7 +26,7 @@ except AttributeError: class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName(_fromUtf8("MainWindow")) - MainWindow.resize(1228, 700) + MainWindow.resize(956, 699) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Maximum, QtGui.QSizePolicy.Maximum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -41,20 +41,11 @@ class Ui_MainWindow(object): self.centralwidget.setObjectName(_fromUtf8("centralwidget")) self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget) self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) - self.horizontalLayout = QtGui.QHBoxLayout() - self.horizontalLayout.setSizeConstraint(QtGui.QLayout.SetDefaultConstraint) - self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) - self.mplWidget = QtGui.QWidget(self.centralwidget) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.mplWidget.sizePolicy().hasHeightForWidth()) - self.mplWidget.setSizePolicy(sizePolicy) - self.mplWidget.setMinimumSize(QtCore.QSize(600, 400)) - self.mplWidget.setObjectName(_fromUtf8("mplWidget")) - self.horizontalLayout.addWidget(self.mplWidget) - self.scrollArea = QtGui.QScrollArea(self.centralwidget) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Expanding) + self.splitter = QtGui.QSplitter(self.centralwidget) + self.splitter.setOrientation(QtCore.Qt.Horizontal) + self.splitter.setObjectName(_fromUtf8("splitter")) + self.scrollArea = QtGui.QScrollArea(self.splitter) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.scrollArea.sizePolicy().hasHeightForWidth()) @@ -64,16 +55,20 @@ class Ui_MainWindow(object): self.scrollArea.setWidgetResizable(True) self.scrollArea.setObjectName(_fromUtf8("scrollArea")) self.scrollAreaWidgetContents = QtGui.QWidget() - self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 298, 568)) + self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 298, 572)) self.scrollAreaWidgetContents.setObjectName(_fromUtf8("scrollAreaWidgetContents")) - self.verticalLayout_2 = QtGui.QVBoxLayout(self.scrollAreaWidgetContents) - self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2")) self.scrollArea.setWidget(self.scrollAreaWidgetContents) - self.horizontalLayout.addWidget(self.scrollArea) - self.verticalLayout.addLayout(self.horizontalLayout) + self.graphicsView = PlotWidget(self.splitter) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(3) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.graphicsView.sizePolicy().hasHeightForWidth()) + self.graphicsView.setSizePolicy(sizePolicy) + self.graphicsView.setObjectName(_fromUtf8("graphicsView")) + self.verticalLayout.addWidget(self.splitter) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtGui.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 1228, 22)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 956, 22)) self.menubar.setObjectName(_fromUtf8("menubar")) MainWindow.setMenuBar(self.menubar) self.statusbar = QtGui.QStatusBar(MainWindow) @@ -116,4 +111,5 @@ class Ui_MainWindow(object): self.actionSave_FitResult.setText(_translate("MainWindow", "Save Fit", None)) self.actionSave_FitResult.setToolTip(_translate("MainWindow", "Save Fit Result", None)) +from pyqtgraph import PlotWidget import images_rc diff --git a/QDSMain.ui b/QDSMain.ui index 3f0010b..05a4883 100644 --- a/QDSMain.ui +++ b/QDSMain.ui @@ -6,8 +6,8 @@ 0 0 - 1228 - 700 + 956 + 699 @@ -28,63 +28,52 @@ - - - QLayout::SetDefaultConstraint + + + Qt::Horizontal - - - - - 0 - 0 - - - - - 600 - 400 - + + + + 0 + 0 + + + + + 300 + 0 + + + + + 210 + 16777215 + + + + true + + + + + 0 + 0 + 298 + 572 + - - - - - - 0 - 0 - - - - - 300 - 0 - - - - - 210 - 16777215 - - - - true - - - - - 0 - 0 - 298 - 568 - - - - - - - + + + + + 3 + 0 + + + + @@ -93,7 +82,7 @@ 0 0 - 1228 + 956 22 @@ -156,6 +145,13 @@ + + + PlotWidget + QGraphicsView +
pyqtgraph
+
+
diff --git a/data.py b/data.py index 26cc089..ae515c2 100644 --- a/data.py +++ b/data.py @@ -1,14 +1,23 @@ -from PyQt4.QtCore import QObject, pyqtSignal +from PyQt4.QtCore import QObject, pyqtSignal, Qt +from PyQt4.QtGui import QColor import numpy as N +import PeakWidget import conductivityWidget +import pyqtgraph as pg +from PyQt4.QtCore import * +from mathlib import id_to_color, hn class Data: - def __init__(self, frequency, die_real, die_imag): + def __init__(self, frequency=N.zeros(1), die_real=N.zeros(1), die_imag=N.zeros(1)): self.frequency = frequency self.epsilon = die_real + 1j * die_imag - self.data_curve = None # mpl object - self.fitted_curve = None # mpl object + self.epsilon_fit = die_real*0 + 1j * die_imag*0 + myPen = pg.mkPen(width=3, color=(255,255,127)) + + self.data_curve = pg.PlotDataItem(x=[N.nan], y=[N.nan],pen=QColor(0,0,0,0), symbol='o', + symbolBrush=(255,127,0,127)) + self.fitted_curve = pg.PlotDataItem(N.array([N.nan]), N.array([N.nan]), pen=myPen) self.length = len(frequency) self.meta = dict() self.fit_limits = (frequency.min(), frequency.max(), die_imag.min(), die_imag.max()) @@ -17,6 +26,14 @@ class Data: #self.remove_curves() pass #def set_fit_limits(self, limits=(None,None,None,None)): + + def set_data(self,f,e_real,e_imag): + self.frequency = f + self.epsilon = e_real + 1j*e_imag + self.epsilon_fit = 0*e_real + 1j*e_imag*0 + self.fit_limits = (f.min(), f.max(), e_imag.min(), e_imag.max()) + self.data_curve.setData(f,e_imag) + def get_data(self): """ @@ -28,22 +45,32 @@ class Data: def remove_curves(self): print "remove data_curve" - if self.data_curve is not None: self.data_curve.remove() + #if self.data_curve is not None: self.data_curve.remove() print "remove fitted_curve" - if self.fitted_curve is not None: self.fitted_curve.remove() + #if self.fitted_curve is not None: self.fitted_curve.remove() class Conductivity(QObject): changedData = pyqtSignal() - def __init__(self, mpl=None): + def __init__(self, mpl=None, limits=None): QObject.__init__(self) super(Conductivity, self) self.widget = conductivityWidget.ConductivityWidget() self.widget.changedTable.connect(self.updateData) - self.mpl_line = None - self.mpl_line_static = None + myPen = pg.mkPen( style=Qt.DashLine, width=1) + self.color=QColor("black") + + self.mpl_line = pg.PlotDataItem(x=N.array([N.nan]), y=N.array([N.nan]), pen=myPen) + self.mpl_line_static = pg.PlotDataItem(x=N.array([N.nan]), y=N.array([N.nan]), pen=myPen) self.mpl = mpl + self.mpl.addItem(self.mpl_line) + self.mpl.addItem(self.mpl_line_static) + self.limits = limits + + self.frequency = None + self.conductivity = None + self.epsilon_static = None def getParameter(self): @@ -60,9 +87,7 @@ class Conductivity(QObject): def updateData(self): # get current axis limits - x_min, x_max = self.mpl.canvas.axes.get_xlim() - y_min, y_max = self.mpl.canvas.axes.get_ylim() - + x_min, x_max, y_min, y_max = self.limits nu = N.logspace(N.log10(x_min), N.log10(x_max), 1024) eps_static, sigma, sigma_N = self.getParameter() y = conductivity([sigma, sigma_N], nu) @@ -71,26 +96,79 @@ class Conductivity(QObject): mask_static = (y_static < y_max) & (y_static > y_min) # clip data to axes limits mask = (y < y_max) & (y > y_min) - #mask = mask_static = N.ones(1024, dtype='bool') - if self.mpl_line == None: - self.mpl_line, = self.mpl.canvas.axes.loglog(nu[mask], y[mask], 'k--', label="Cond.", animated=True) # peak - else: - self.mpl_line.set_xdata(nu[mask]) - self.mpl_line.set_ydata(y[mask]) - - if self.mpl_line_static == None: - self.mpl_line_static, = self.mpl.canvas.axes.loglog(nu[mask_static], - y_static[mask_static], - 'k:', - label=r"$\epsilon_S$", - animated=True) # peak - else: - self.mpl_line_static.set_xdata(nu[mask_static]) - self.mpl_line_static.set_ydata(y_static[mask_static]) + self.frequency = nu[mask] + self.conductivity = y[mask] + self.epsilon_static = y_static[mask] + self.mpl_line.setData(x=nu[mask], y=y[mask], label="Cond.") + self.mpl_line_static.setData(x=nu[mask_static], y=y_static[mask_static]) self.changedData.emit() + def get_color(self): + return self.color + + def get_conductivity(self): + return self.frequency, self.conductivity + def get_epsilon_static(self): + return self.frequency, self.epsilon_static + def conductivity(p, nu): c = p[0] / (2 * N.pi * nu) ** p[1] - return c \ No newline at end of file + return c + + +class Peak(QObject): + changedData = pyqtSignal() + + def __init__(self, id=None, mpl=None, limits=None): + QObject.__init__(self) + super(Peak, self).__init__() + + + self.widget = PeakWidget.PeakWidget() + self.widget.setId(id) + self.color = id_to_color(id) + self.widget.setColor(self.color) + self.widget.changedTable.connect(self.updatePeak) + self.mpl = mpl + self.limits = limits + + myPen = pg.mkPen( style=Qt.DashLine, width=2, color=self.color) + self.mpl_line = pg.PlotDataItem(x=N.array([N.nan]),y=N.array([N.nan]), pen=myPen) + self.mpl.addItem(self.mpl_line) + self.frequency = None + self.epsilon = None + + def getParameter(self): + p = self.widget.peakParameter() + return p + + def getFixed(self): + p = self.widget.fixedParameter() + return p + + def setParameter(self, delta_eps=None, tau=None, a=None, b=None): + self.widget.updateTable(delta_eps, tau, a, b) + self.updatePeak() + + def updatePeak(self): + # get current axis limits +# x_min, x_max = self.mpl.canvas.axes.get_xlim() +# y_min, y_max = self.mpl.canvas.axes.get_ylim() + x_min,x_max, y_min, y_max = self.limits + nu = N.logspace(N.log10(x_min), N.log10(x_max), 2048) + y = hn(self.getParameter(), nu) + # clip data to axes limits + mask = (y < y_max) & (y > y_min) + y = y[mask] + nu = nu[mask] + self.frequency = nu[:] + self.epsilon = y[:] + self.mpl_line.setData(x=nu, y=y) + self.changedData.emit() + + def get_color(self): + return self.color + def get_data(self): + return self.frequency,self.epsilon \ No newline at end of file diff --git a/images_rc.py b/images_rc.py index c30653f..0db5c38 100644 --- a/images_rc.py +++ b/images_rc.py @@ -2,8 +2,8 @@ # Resource object code # -# Created: Mi. Jul 10 18:57:09 2013 -# by: The Resource Compiler for PyQt (Qt v4.8.4) +# Created: Fr. Feb. 21 17:15:59 2014 +# by: The Resource Compiler for PyQt (Qt v4.8.5) # # WARNING! All changes made in this file will be lost! diff --git a/mathlib.py b/mathlib.py index 42fcdc7..c6818b4 100644 --- a/mathlib.py +++ b/mathlib.py @@ -3,7 +3,7 @@ import matplotlib import numpy as N from scipy import optimize as opt, optimize, odr #from QDS import mini_func, multi_hn - +from PyQt4.QtGui import QColor __author__ = 'markusro' @@ -59,7 +59,7 @@ def fit_lbfgsb(x, y, p0, fixed): def fit_odr(x, y, p0, fixed): - dat = odr.Data(x, y, 1.0 / y) + dat = odr.Data(x, y, 1.0 / y**2) mod = odr.Model(multi_hn) fit = odr.ODR(dat, mod, p0, ifixx=(0,), ifixb=fixed, maxit=2000) fit.run() @@ -82,8 +82,16 @@ def id_to_color(id): """ colors = ['b', 'r', 'g', 'c', 'm', 'y', 'k'] - conv = matplotlib.colors.ColorConverter() - return conv.to_rgb(colors[id % len(colors)]) + colors = [QColor(54,22,115), + QColor(160,16,36), + QColor(45,142,15), + QColor(168,149,17), + QColor(36,10,85), + QColor(118,8,23), + QColor(31,105,7), + QColor(124,109,8), + ] + return colors[id % len(colors)] def mini_func(p, x, y): @@ -110,4 +118,10 @@ def multi_hn(p, nu): e_loss += 2 * delta_eps * (1 + 2 * (om * tau) ** a * N.cos(N.pi * a / 2.) + (om * tau) ** (2. * a) ) ** ( -b / 2.) * N.sin(b * Phi) #e_stor = delta_eps * (1+ 2*(om*tau)**a * N.cos(N.pi*a/2.) + (om*tau)**(2.*a) )**(-b/2.)*N.cos(b*Phi) - return e_loss \ No newline at end of file + return e_loss + + +def tau_peak(f, a, b): + tau = (N.sin(N.pi * a / 2. / (b + 1)) / N.sin(N.pi * a * b / 2. / (b + 1))) ** (1 / a) + tau /= 2 * N.pi * f + return tau \ No newline at end of file