install script, good progress with constraint listings and editing

This commit is contained in:
Stefan Kögl 2012-11-18 15:14:17 +01:00
parent f4478533d0
commit f662ce3b52
12 changed files with 640 additions and 413 deletions

0
reflowctl/__init__.py Normal file
View File

589
reflowctl/reflowctl_gui.py Executable file
View File

@ -0,0 +1,589 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys, os, random, copy
from operator import attrgetter
import xml.etree.ElementTree as etree
import pylab
from PyQt4 import QtGui, QtCore
from numpy import arange, sin, pi, array, linspace, arange
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from matplotlib.lines import Line2D
from matplotlib.path import Path
import matplotlib.patches as patches
#from mpltools import annotation
progname = os.path.basename(sys.argv[0])
progversion = "0.1"
PSTEP_COLORS = ("lightgreen", "yellow", "orange", "red")
class State(object):
def __init__(self, name, temp):
self.name = name
self.temp = temp
class Solder(object):
def __init__(self):
self.psteps = []
self.durations = list()
self.rates = list()
self.name = None
#start = self.add_state("start", 25)
#ps = self.add_state("preheat start", 150)
#pe = self.add_state("preheat end", 185)
#tal = self.add_state("tal", 220)
#peak = self.add_state("peak", 250)
#end = self.add_state("end", 25)
#self.add_duration((ps, pe), 100)
#self.add_duration((tal, peak, tal), 100)
#self.add_rate((start, ps), 1)
#self.add_rate((ps, pe), 1)
#self.add_rate((pe, tal), 1)
#self.add_rate((tal, end), -2)
def __unicode__(self):
return unicode(self.name)
def __str__(self):
return self.name
def color(self, index):
return PSTEP_COLORS[index]
def add_state(self, name, temp):
s = State(name, temp)
self.psteps.append(s)
return s
def add_rate(self, states, rate):
self.rates.append((states, rate))
def add_duration(self, states, duration):
self.durations.append((states, duration))
def get_state(self, name):
for i in self.psteps:
if i.name == name:
return i
return None
def calc_profile(self):
x = list()
y = list()
duration_points = dict()
rate_points = dict()
self.time = 0
used_steps = set()
for ix, pstep in enumerate(self.psteps):
#print "-- ", repr(pstep.name), pstep.temp, pstep.used, self.time, x, y
if pstep != self.psteps[0] and pstep not in used_steps:
ix = self.psteps.index(pstep)
raise Exception("step %r not connected to step %r or step %r" % (pstep.name, self.psteps[ix-1].name, self.psteps[ix+1].name))
psteps = None
duration = None
for sts, dur in self.durations:
if sts[0] == pstep:
duration = dur
psteps = sts
break
if pstep not in used_steps:
used_steps.add(pstep)
x.append(self.time)
y.append(pstep.temp)
if duration is not None:
if len(psteps) == 3:
used_steps.add(psteps[1])
used_steps.add(psteps[2])
self.time += duration / 2
x.append(self.time)
y.append(psteps[1].temp)
#print "3er duration", (self.time, psteps[1].temp)
self.time += duration / 2
x.append(self.time)
y.append(psteps[2].temp)
duration_points[ix] = (x[-3:], y[-3:])
#print "3er duration", (self.time, psteps[2].temp)
else:
y.append(psteps[1].temp)
used_steps.add(psteps[1])
self.time += duration
x.append(self.time)
duration_points[ix] = (x[-2:], y[-2:])
#print "2er duration", (self.time, psteps[1].temp)
else:
for ex, (sts, rate) in enumerate(self.rates):
if sts[0] == pstep:
used_steps.add(sts[1])
duration = (sts[1].temp - pstep.temp) / rate
self.time += duration
x.append(self.time)
y.append(sts[1].temp)
#print "rate", (self.time, sts[1].temp)
rate_points[ex] = (x[-2:], y[-2:])
return array(map(float, x)), array(map(float, y)), max(x), max(y), duration_points, rate_points
@staticmethod
def unpack(filename):
xmltree = etree.parse(filename)
root = xmltree.getroot()
s = Solder()
s.name = root[0].attrib["name"]
for state in root[0].findall("state"):
s.add_state(state.attrib["name"], int(state.attrib["temperature"]))
for duration in root[0].findall("duration"):
states = list()
for state in duration:
states.append(s.get_state(state.attrib["name"]))
s.add_duration(states, int(duration.attrib["value"]))
for rate in root[0].findall("rate"):
#print rate
states = list()
for state in rate:
states.append(s.get_state(state.attrib["name"]))
s.add_rate(states, int(rate.attrib["value"]))
return s
def serialize(self, pstep_list):
return ", ".join(map(attrgetter("name"), pstep_list))
class SolderListModel(QtCore.QAbstractListModel):
def __init__(self, parent=None, *args):
""" datain: a list where each item is a row
"""
super(SolderListModel, self).__init__(parent, *args)
dirname = os.path.join(os.path.dirname(__file__), "solder_types")
dirlisting = os.listdir(dirname)
self.listdata = []
for p in dirlisting:
#try:
self.listdata.append(Solder.unpack(os.path.join(dirname, p)))
#except Exception:
#pass
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.listdata)
def headerData(self, col, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return QtCore.QVariant("Solder Paste")
return QtCore.QVariant()
def data(self, index, role):
if index.isValid() and role == QtCore.Qt.DisplayRole:
return QtCore.QVariant(self.listdata[index.row()].name)
else:
return QtCore.QVariant()
class PStepModel(QtCore.QAbstractTableModel):
def __init__(self, parent=None, *args):
super(PStepModel, self).__init__(parent, *args)
self.psteps = list()
self.headerdata = [u"Name", u"Temperature (°C)"]
def headerData(self, col, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return QtCore.QVariant(self.headerdata[col])
return QtCore.QVariant()
def rowCount(self, parent):
return len(self.psteps)
def columnCount(self, parent):
return 2
def data(self, index, role):
if not index.isValid():
return QtCore.QVariant()
if role == QtCore.Qt.DisplayRole:
col = index.column()
if col == 0:
return QtCore.QVariant(self.psteps[index.row()].name)
else:
return QtCore.QVariant(self.psteps[index.row()].temp)
if index.column() == 0 and role == QtCore.Qt.DecorationRole:
p = QtGui.QPixmap(10,10)
cr = row = index.row()
color = index.row() in (0, len(self.psteps)-1) and QtGui.QColor("black") or QtGui.QColor(PSTEP_COLORS[cr-1])
p.fill(color)
return p
return QtCore.QVariant()
def remove_pstep(self, index):
del self.psteps[index]
self.reset()
def add_pstep(self, index, pstep):
self.psteps.insert(index, pstep)
self.reset()
def setSteps(self, steps):
assert isinstance(steps, list)
self.psteps = steps
self.reset()
class MyDynamicMplCanvas(FigureCanvas):
"""A canvas that updates itself every second with a new plot."""
def __init__(self, parent, myapp, width, height, dpi):
self.fig = Figure(figsize=(width, height), dpi=dpi)
super(MyDynamicMplCanvas, self).__init__(self.fig)
self.axes = self.fig.add_subplot(111)
## We want the axes cleared every time plot() is called
self.axes.set_axis_bgcolor('black')
self.axes.set_title(u'reflow profile', size=12)
self.axes.set_xlabel(u'time (seconds)', size=12)
self.axes.set_ylabel(u'temperature (°C)', size=12)
#pylab.setp(self.axes.get_xticklabels(), fontsize=8)
#pylab.setp(self.axes.get_yticklabels(), fontsize=8)
self.setParent(parent)
self.myapp = myapp
self.solder = None
self.plot_data, = self.axes.plot([], linewidth=1.0, color=(0,0,1), zorder=10)
self.selection_data, = self.axes.plot([], linewidth=1.0, color=(1,1,1), zorder=5)
FigureCanvas.setSizePolicy(self,
QtGui.QSizePolicy.Expanding,
QtGui.QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
timer = QtCore.QTimer(self)
self.counter = list()
QtCore.QObject.connect(timer, QtCore.SIGNAL("timeout()"), self.update_figure)
timer.start(1000)
def update_figure(self):
#Build a list of 4 random integers between 0 and 10 (both inclusive)
x, y, xmax, ymax, duration_points, rate_points = self.solder.calc_profile()
lines = list()
legend = list()
#for states, value in self.durations.iteritems():
#annotation.slope_marker((states[0])
self.fig.lines = lines
self.axes.set_xbound(lower=0, upper=xmax + 20)
self.axes.set_ybound(lower=0, upper=ymax + 20)
self.axes.set_ymargin(0)
self.axes.set_xmargin(0)
self.axes.set_yticks([state.temp for state in self.solder.psteps])
self.axes.set_xticks(x)
self.plot_data.set_xdata(x)
self.plot_data.set_ydata(y)
self.plot_data.set_zorder(20)
duration_widget = self.myapp.duration_widget
#self.selection_data.set_xdata(array(da))
#self.selection_data.set_ydata(array(db))
for ix, i in enumerate(self.solder.psteps[1:-1]):
line = Line2D([0, xmax + 20], [i.temp, i.temp],
transform=self.axes.transData, figure=self.fig, color=self.solder.color(ix), label="name", zorder=1)
lines.append(line)
self.axes.legend(("Estimated profile",))
self.draw()
# contraint_list | label - checkboxes
# label - value
class ConstraintWidget(QtGui.QWidget):
def __init__(self, name):
super(ConstraintWidget, self).__init__()
self.name = name
self.solder = None
self.value = QtGui.QSpinBox(self)
self.value.setRange(-300, 400)
self.constraint_model = QtGui.QStringListModel(self) # constraint selection
self.all_psteps = PStepModel(self) # pstep selection pool
self.selected_psteps = PStepModel(self) # selected psteps
#self.all_psteps.setSteps(self.solder.psteps)
self.add_button = QtGui.QPushButton("Add", self)
self.remove_button = QtGui.QPushButton("Remove", self)
bg = QtGui.QWidget(self)
gbl = QtGui.QVBoxLayout(bg)
gbl.addWidget(self.add_button)
gbl.addWidget(self.remove_button)
gbl.addStretch(5)
gbl.addWidget(self.value)
self.constraint_list_view = QtGui.QListView(self)
self.constraint_list_view.setModel(self.constraint_model)
self.all_psteps_view = QtGui.QListView(self)
self.all_psteps_view.setModel(self.all_psteps)
self.selected_psteps_view = QtGui.QListView(self)
self.selected_psteps_view.setModel(self.selected_psteps)
#self.left = QtGui.QWidget(self)
#gl = QtGui.QGridLayout(self.left)
#gl.addWidget(QtGui.QLabel(u"Steps"), 0,0)
#gl.addWidget(QtGui.QLabel(name), 1,0)
#gl.addWidget(self.checkboxes_group, 0, 1)
#gl.addWidget(self.value, 1, 1)
#self.gl = gl
h = QtGui.QHBoxLayout()
h.addWidget(self.constraint_list_view)
h.addWidget(self.all_psteps_view)
h.addWidget(bg)
h.addWidget(self.selected_psteps_view)
self.setLayout(h)
self.connect(
self.constraint_list_view,
QtCore.SIGNAL("clicked(QModelIndex)"),
self.constraint_clicked)
self.connect(self.add_button, QtCore.SIGNAL("clicked()"), self.add_constraint)
self.connect(self.remove_button, QtCore.SIGNAL("clicked()"), self.remove_constraint)
def add_constraint(self):
raise NotImplementedError()
def remove_constraint(self):
raise NotImplementedError()
def setData(self, solder):
self.solder = solder
#for k,v in self.checkboxes.iteritems():
#self.cl.removeWidget(v)
#self.checkboxes = dict()
self.all_psteps.setSteps(self.solder.psteps)
#for i in solder.psteps:
#cb = QtGui.QCheckBox(self, checked=False)
#label = QtGui.QLabel(i.name, self)
#label.setBuddy(cb)
#self.checkboxes[i] = cb
##self.cl.addWidget(label)
##self.cl.addWidget(cb)
self.getConstraints()
def getConstraints(self):
raise NotImplementedError()
def constraint_clicked(self, index):
#for cb in self.checkboxes.itervalues():
#cb.setChecked(False)
self.handle_clicked(index)
def handle_clicked(self, index):
raise NotImplementedError()
class DurationConstraintWidget(ConstraintWidget):
def getConstraints(self):
tmp = QtCore.QStringList()
for ix in xrange(len(self.solder.durations)):
tmp << unicode(ix + 1)
self.constraint_model.setStringList(tmp)
k, t = self.solder.durations[0]
self.value.setValue(t)
self.constraint_list_view.setCurrentIndex(self.constraint_model.index(0, 0))
def add_constraint(self):
self.selected_psteps.psteps.append(self.all_psteps.psteps[self.all_psteps_view.currentIndex().row()])
self.selected_psteps.reset()
#self.selected_psteps_view.setCurrentIndex(QtCore.QModelIndex())
self.selected_psteps_view.clearSelection()
def remove_constraint(self):
del self.selected_psteps.psteps[self.selected_psteps_view.currentIndex().row()]
self.selected_psteps.reset()
#self.selected_psteps_view.setCurrentIndex(QtCore.QModelIndex())
self.selected_psteps_view.clearSelection()
def handle_clicked(self, index):
psteps, value = self.solder.durations[index.row()]
self.selected_psteps.setSteps(psteps)
self.value.setValue(value)
class RateConstraintWidget(ConstraintWidget):
def getConstraints(self):
tmp = QtCore.QStringList()
for ix in xrange(len(self.solder.durations)):
tmp << unicode(ix + 1)
self.constraint_model.setStringList(tmp)
k, t = self.solder.rates[0]
self.value.setValue(t)
self.constraint_list_view.setCurrentIndex(self.constraint_model.index(0, 0))
def handle_clicked(self, index):
psteps, value = self.solder.durations[index.row()]
self.selected_psteps.setSteps(psteps)
self.value.setValue(value)
class ApplicationWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.setWindowTitle("application main window")
self.file_menu = QtGui.QMenu('&File', self)
self.file_menu.addAction('&Quit', self.fileQuit,
QtCore.Qt.CTRL + QtCore.Qt.Key_Q)
self.file_menu.addAction('&Save plot', self.save_plot,
QtCore.Qt.CTRL + QtCore.Qt.Key_S)
self.menuBar().addMenu(self.file_menu)
self.help_menu = QtGui.QMenu('&Help', self)
self.menuBar().addSeparator()
self.menuBar().addMenu(self.help_menu)
self.help_menu.addAction('&About', self.about)
self.main_widget = QtGui.QWidget(self)
self.profile_widget = QtGui.QWidget(self)
self.steps_box = QtGui.QGroupBox(self)
self.tab_widget = QtGui.QTabWidget(self)
self.duration_widget = DurationConstraintWidget(u"Duration (s)")
self.rate_widget = RateConstraintWidget(u"Rate (°C/s)")
self.tab_widget.addTab(self.duration_widget, u"Duration (s)")
self.tab_widget.addTab(self.rate_widget, u"Rate (°C/s)")
self.dpi = 100
pl = QtGui.QHBoxLayout(self.profile_widget)
sl = QtGui.QVBoxLayout(self.steps_box)
self.solder_model = SolderListModel(self)
self.pstep_model = PStepModel(self)
self.pstep_view = QtGui.QTableView()
self.pstep_view.setModel(self.pstep_model)
self.pstep_view.verticalHeader().setVisible(False)
self.pstep_view.resizeColumnsToContents()
self.solder_view = QtGui.QListView()
self.solder_view.setModel(self.solder_model)
self.connect(
self.solder_view,
QtCore.SIGNAL("clicked(QModelIndex)"),
self.solder_selected)
pl.addWidget(self.solder_view, 1)
pl.addWidget(self.pstep_view, 2)
pl.addWidget(self.tab_widget, 7)
#pl.addWidget(self.duration_widget)
#pl.addWidget(self.rate_widget)
l = QtGui.QVBoxLayout(self.main_widget)
self.dc = MyDynamicMplCanvas(self, self, width=5, height=4, dpi=self.dpi)
self.solder_view.setCurrentIndex(self.solder_model.index(0,0))
self.solder_selected(self.solder_model.index(0,0))
l.addWidget(self.profile_widget, 2)
l.addWidget(self.dc, 8)
self.main_widget.setFocus()
self.setCentralWidget(self.main_widget)
self.statusBar().showMessage("I'm in reflow heaven", 2000)
def solder_selected(self, index):
if index.isValid():
self.dc.solder = self.solder_model.listdata[index.row()]
self.pstep_model.setSteps(self.dc.solder.psteps)
self.pstep_view.resizeColumnsToContents()
self.duration_widget.setData(self.dc.solder)
self.rate_widget.setData(self.dc.solder)
def save_plot(self):
file_choices = "PNG (*.png)|*.png"
filename = QtGui.QFileDialog.getSaveFileName(self, 'Save File', 'qtplot.png')
print type(filename), dir(filename)
self.dc.print_figure(str(filename), dpi=self.dpi)
def fileQuit(self):
self.close()
def closeEvent(self, ce):
self.fileQuit()
def about(self):
QtGui.QMessageBox.about(self, "About %s" % progname,
u"%(prog)s version %(version)s\n" \
u"Copyright \N{COPYRIGHT SIGN} 2012 Stefan Kögl\n\n" \
u"reflowctl frontend" % {"prog": progname, "version": progversion})
def main():
qApp = QtGui.QApplication(sys.argv)
aw = ApplicationWindow()
aw.setWindowTitle("%s" % progname)
aw.show()
sys.exit(qApp.exec_())
if __name__ == '__main__':
main()

View File

@ -1,413 +0,0 @@
# -*- coding: utf-8 -*-
#!/usr/bin/python
import sys, os, random
import xml.etree.ElementTree as etree
import pylab
from PyQt4 import QtGui, QtCore
from numpy import arange, sin, pi, array, linspace, arange
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from matplotlib.lines import Line2D
from matplotlib.path import Path
import matplotlib.patches as patches
from scipy.interpolate import *
progname = os.path.basename(sys.argv[0])
progversion = "0.1"
class State(object):
def __init__(self, name, temp):
self.name = name
self.temp = temp
class Solder(object):
def __init__(self):
self.psteps = []
self.durations = dict()
self.rates = dict()
self.name = None
#start = self.add_state("start", 25)
#ps = self.add_state("preheat start", 150)
#pe = self.add_state("preheat end", 185)
#tal = self.add_state("tal", 220)
#peak = self.add_state("peak", 250)
#end = self.add_state("end", 25)
#self.add_duration((ps, pe), 100)
#self.add_duration((tal, peak, tal), 100)
#self.add_rate((start, ps), 1)
#self.add_rate((ps, pe), 1)
#self.add_rate((pe, tal), 1)
#self.add_rate((tal, end), -2)
def __unicode__(self):
return unicode(self.name)
def __str__(self):
return self.name
def add_state(self, name, temp):
s = State(name, temp)
self.psteps.append(s)
return s
def add_rate(self, states, rate):
self.rates[states] = rate
def add_duration(self, states, duration):
self.durations[states] = duration
def get_state(self, name):
for i in self.psteps:
if i.name == name:
return i
return None
def calc_profile(self):
x = list()
y = list()
self.time = 0
used_steps = set()
for pstep in self.psteps:
#print "-- ", repr(pstep.name), pstep.temp, pstep.used, self.time, x, y
if pstep != self.psteps[0] and pstep not in used_steps:
ix = self.psteps.index(pstep)
raise Exception("step %r not connected to step %r or step %r" % (pstep.name, self.psteps[ix-1].name, self.psteps[ix+1].name))
psteps = None
duration = None
for sts, dur in self.durations.iteritems():
if sts[0] == pstep:
duration = dur
psteps = sts
break
if pstep not in used_steps:
used_steps.add(pstep)
x.append(self.time)
y.append(pstep.temp)
if duration is not None:
if len(psteps) == 3:
used_steps.add(psteps[1])
used_steps.add(psteps[2])
self.time += duration / 2
x.append(self.time)
y.append(psteps[1].temp)
#print "3er duration", (self.time, psteps[1].temp)
self.time += duration / 2
x.append(self.time)
y.append(psteps[2].temp)
#print "3er duration", (self.time, psteps[2].temp)
else:
y.append(psteps[1].temp)
used_steps.add(psteps[1])
self.time += duration
x.append(self.time)
#print "2er duration", (self.time, psteps[1].temp)
else:
for sts, rate in self.rates.iteritems():
if sts[0] == pstep:
used_steps.add(sts[1])
duration = (sts[1].temp - pstep.temp) / rate
self.time += duration
x.append(self.time)
y.append(sts[1].temp)
#print "rate", (self.time, sts[1].temp)
return array(map(float, x)), array(map(float, y)), max(x), max(y)
@staticmethod
def unpack(filename):
xmltree = etree.parse(filename)
root = xmltree.getroot()
s = Solder()
s.name = root[0].attrib["name"]
for state in root[0].findall("state"):
s.add_state(state.attrib["name"], int(state.attrib["temperature"]))
for duration in root[0].findall("duration"):
states = list()
for state in duration:
states.append(s.get_state(state.attrib["name"]))
s.add_duration(tuple(states), int(duration.attrib["value"]))
for rate in root[0].findall("rate"):
#print rate
states = list()
for state in rate:
states.append(s.get_state(state.attrib["name"]))
s.add_rate(tuple(states), int(rate.attrib["value"]))
return s
class SolderListModel(QtCore.QAbstractListModel):
def __init__(self, parent=None, *args):
""" datain: a list where each item is a row
"""
super(SolderListModel, self).__init__(parent, *args)
self.listdata = [Solder.unpack(os.path.join("solder_types", p)) for p in os.listdir("solder_types")]
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.listdata)
def data(self, index, role):
if index.isValid() and role == QtCore.Qt.DisplayRole:
return QtCore.QVariant(self.listdata[index.row()].name)
else:
return QtCore.QVariant()
class PStepModel(QtCore.QAbstractTableModel):
def __init__(self, parent=None, *args):
super(PStepModel, self).__init__(parent, *args)
self.psteps = list()
def rowCount(self, parent):
return len(self.psteps)
def columnCount(self, parent):
return 2
def data(self, index, role):
if not index.isValid():
return QtCore.QVariant()
elif role != QtCore.Qt.DisplayRole:
return QtCore.QVariant()
col = index.column()
if col == 0:
return QtCore.QVariant(self.psteps[index.row()].name)
else:
return QtCore.QVariant(self.psteps[index.row()].temperature)
def removeRows(self, start, _count, _parent):
print type(start), type(_count)
self.beginRemoveRows(_parent, start, start + _count)
self.psteps[:start].extend(self.psteps[start + _count:])
self.endRemoveRows()
class MyDynamicMplCanvas(FigureCanvas):
"""A canvas that updates itself every second with a new plot."""
def __init__(self, parent=None, width=5, height=4, dpi=100):
self.fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = self.fig.add_subplot(111)
# We want the axes cleared every time plot() is called
self.axes.set_axis_bgcolor('black')
self.axes.set_title(u'reflow profile', size=12)
self.axes.set_xlabel(u'time (seconds)', size=12)
self.axes.set_ylabel(u'temperature (°C)', size=12)
pylab.setp(self.axes.get_xticklabels(), fontsize=8)
pylab.setp(self.axes.get_yticklabels(), fontsize=8)
super(MyDynamicMplCanvas, self).__init__(self.fig)
self.setParent(parent)
self.solder = None
self.compute_initial_figure()
FigureCanvas.setSizePolicy(self,
QtGui.QSizePolicy.Expanding,
QtGui.QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
timer = QtCore.QTimer(self)
self.counter = list()
QtCore.QObject.connect(timer, QtCore.SIGNAL("timeout()"), self.update_figure)
timer.start(1000)
def compute_initial_figure(self):
"""test foo bar"""
#start_rate = 1
#start_temp = 25
#start_period = None
## warmup
#warmup_rate = 1
#warmup_temp = 155
#preheat_period = None
## preheat start
#preheat_start_rate = 1
#preheat_start_temp = 155
#preheat_start_period = 100
## preheat end
#preheat_end_rate = 1
#preheat_end_temp = 185
#preheat_end_period = None
#tal_rate = 1
#tal_temp = 220
#tal_duration = 60
#peak_temp = 250
#peak_rate = 1
#x, y = self.solder.calc_profile()
#print "x", repr(x)
#print "y", repr(y)
#dtp_min = 99999.
#dtp_max = 0.
#dtpi = -1
#dtn_min = -99999.
#dtn_max = 0.
#dtni = -1
#for i in xrange(1, len(y)):
#tmp = (y[i] - y[i-1]) / (x[i] - x[i-1])
#if tmp > 0:
#if tmp < dtp_min:
#dtp_min = tmp
#dtpi = i
#elif tmp > dtp_max:
#dtp_max = tmp
#dtpi = i
#elif tmp < 0:
#if tmp > dtn_min:
#dtn_min = tmp
#dtni = i
#elif tmp < dtn_max:
#dtn_max = tmp
#dtni = i
#print "max negative", dtn_min, dtn_max, dtni
#print "max positive", dtp_min, dtp_max, dtpi
self.plot_data, = self.axes.plot([], linewidth=1.0, color=(0,0,1))
#self.axes.plot(p1x, p1y, 'r-o')
def update_figure(self):
# Build a list of 4 random integers between 0 and 10 (both inclusive)
x, y, xmax, ymax = self.solder.calc_profile()
lines = list()
legend = list()
cols = ("lightgreen", "yellow", "orange", "red")
for ix, i in enumerate(self.solder.psteps[1:-1]):
line = Line2D([0, xmax + 20], [i.temp, i.temp],
transform=self.axes.transData, figure=self.fig, color=cols[ix], label="name")
lines.append(line)
self.fig.lines = lines
self.axes.set_xbound(lower=0, upper=xmax + 20)
self.axes.set_ybound(lower=0, upper=ymax + 20)
#self.axes.grid(True, color='gray')
pylab.setp(self.axes.get_xticklabels(), visible=True)
self.plot_data.set_xdata(x)
self.plot_data.set_ydata(y)
self.axes.legend(("Estimated profile",))
self.draw()
class ApplicationWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.setWindowTitle("application main window")
self.file_menu = QtGui.QMenu('&File', self)
self.file_menu.addAction('&Quit', self.fileQuit,
QtCore.Qt.CTRL + QtCore.Qt.Key_Q)
self.file_menu.addAction('&Save plot', self.save_plot,
QtCore.Qt.CTRL + QtCore.Qt.Key_S)
self.menuBar().addMenu(self.file_menu)
self.help_menu = QtGui.QMenu('&Help', self)
self.menuBar().addSeparator()
self.menuBar().addMenu(self.help_menu)
self.help_menu.addAction('&About', self.about)
self.main_widget = QtGui.QWidget(self)
self.profile_widget = QtGui.QWidget(self)
self.steps_box = QtGui.QGroupBox(self)
self.dpi = 100
pl = QtGui.QHBoxLayout(self.profile_widget)
sl = QtGui.QVBoxLayout(self.steps_box)
self.solder_model = SolderListModel(self)
self.pstep_model = PStepModel(self)
self.solder_view = QtGui.QListView()
self.pstep_view = QtGui.QTableView()
self.solder_view.setModel(self.solder_model)
self.pstep_view.setModel(self.pstep_model)
self.connect(self.solder_view, QtCore.SIGNAL("clicked(QModelIndex)"), self.solder_selected)
pl.addWidget(self.solder_view)
pl.addWidget(self.pstep_view)
l = QtGui.QVBoxLayout(self.main_widget)
self.dc = MyDynamicMplCanvas(self.main_widget, width=5, height=4, dpi=self.dpi)
self.dc.solder = self.solder_model.listdata[0]
l.addWidget(self.profile_widget, 1)
l.addWidget(self.dc, 10)
self.main_widget.setFocus()
self.setCentralWidget(self.main_widget)
self.statusBar().showMessage("I'm in reflow heaven", 2000)
def solder_selected(self, index):
if index.isValid():
self.dc.solder = self.solder_model.listdata[index.row()]
self.pstep_model.removeRows(0, self.pstep_model.rowCount(QtCore.QModelIndex()))
self.pstep_model.insertRows()
def save_plot(self):
file_choices = "PNG (*.png)|*.png"
filename = QtGui.QFileDialog.getSaveFileName(self, 'Save File', 'qtplot.png')
print type(filename), dir(filename)
self.dc.print_figure(str(filename), dpi=self.dpi)
def fileQuit(self):
self.close()
def closeEvent(self, ce):
self.fileQuit()
def about(self):
QtGui.QMessageBox.about(self, "About %s" % progname,
u"""%(prog)s version %(version)s
Copyright \N{COPYRIGHT SIGN} 2012 Stefan Kögl
reflowctl frontend"""
% {"prog": progname, "version": progversion})
qApp = QtGui.QApplication(sys.argv)
aw = ApplicationWindow()
aw.setWindowTitle("%s" % progname)
aw.show()
sys.exit(qApp.exec_())

51
setup.py Normal file
View File

@ -0,0 +1,51 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
from distribute_setup import use_setuptools
use_setuptools()
import sys
from setuptools import find_packages, setup
if sys.version_info >= (3,):
extras['use_2to3'] = True
extras['convert_2to3_doctests'] = ['src/your/module/README.txt']
#extra['use_2to3_fixers'] = ['your.fixers']
setup(
name='reflowctl_gui',
version='0.1',
packages=find_packages(),
include_package_data = True,
install_requires=["numpy", "matplotlib"],
# installing unzipped
zip_safe = False,
# predefined extension points, e.g. for plugins
entry_points = """
[console_scripts]
reflowctl_gui = reflowctl.reflowctl_gui:main
""",
# pypi metadata
author = "Stefan Kögl",
# FIXME: add author email
author_email = "",
description = "paludis useflag management",
# FIXME: add long_description
long_description = """
""",
# FIXME: add license
license = "GPL",
# FIXME: add keywords
keywords = "",
# FIXME: add download url
url = "",
)