save, bugs fixed, slope annotations and more

This commit is contained in:
Stefan Kögl 2012-11-21 20:39:22 +01:00
parent 81c5a17241
commit 6d8e7580c0
4 changed files with 198 additions and 80 deletions

View File

@ -18,7 +18,7 @@ from matplotlib.lines import Line2D
from matplotlib.path import Path
import matplotlib.patches as patches
#from mpltools import annotation-
from mpltools import annotation
progname = os.path.basename(sys.argv[0])
progversion = "0.1"
@ -235,6 +235,29 @@ class Solder(object):
return s
def save(self, filename):
if self.changed:
solder_node = etree.Element("solder_type", {"name" : self.name, "description" : self.description})
for temp_level in self.temp_levels:
temp = temp_level.is_env and "$ENV" or str(temp_level.temp)
solder_node.append(etree.Element("state", {"name" : temp_level.name, "temperature" : temp}))
for temp_levels, value in self.durations:
duration = etree.Element("duration", {"value" : str(value)})
for temp_level in temp_levels:
duration.append(etree.Element("state", {"name" : temp_level.name}))
solder_node.append(duration)
for temp_levels, value in self.rates:
rate = etree.Element("rate", {"value" : str(value)})
for temp_level in temp_levels:
rate.append(etree.Element("state", {"name" : temp_level.name}))
solder_node.append(rate)
dirname = os.path.join(os.path.dirname(__file__), "solder_types")
root = etree.Element("xml")
root.append(solder_node)
etree.ElementTree(root).write(os.path.join(dirname, self.name + ".xml"), "UTF-8", True)
self.changed = False
class SolderListModel(QtCore.QAbstractListModel):
@ -243,20 +266,19 @@ class SolderListModel(QtCore.QAbstractListModel):
"""
super(SolderListModel, self).__init__(parent, *args)
dirname = os.path.join(os.path.dirname(__file__), "solder_types")
dirlisting = filter(lambda x: os.path.splitext(x)[1] == ".xml", os.listdir(dirname))
self.listdata = []
for p in dirlisting:
#try:
self.listdata.append(Solder.unpack(os.path.join(dirname, p)))
#except Exception, e:
#print e
#pass
self.reload()
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.listdata)
def reload(self):
dirname = os.path.join(os.path.dirname(__file__), "solder_types")
dirlisting = filter(lambda x: os.path.splitext(x)[1] == ".xml", os.listdir(dirname))
self.listdata = []
for p in dirlisting:
self.listdata.append(Solder.unpack(os.path.join(dirname, p)))
self.listdata.sort(key=lambda x: x.name)
self.reset()
def headerData(self, col, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
@ -265,10 +287,28 @@ class SolderListModel(QtCore.QAbstractListModel):
def data(self, index, role):
if index.isValid() and role == QtCore.Qt.DisplayRole:
return QtCore.QVariant(self.listdata[index.row()].name)
solder = self.listdata[index.row()]
if solder.changed:
return QtCore.QVariant(solder.name + " *")
else:
return QtCore.QVariant(solder.name)
else:
return QtCore.QVariant()
def setData(self, index, variant, role):
if index.isValid() and role == QtCore.Qt.EditRole:
new_name = str(variant.toString())
if new_name and new_name != "":
self.listdata[index.row()].name = new_name
self.listdata[index.row()].changed = True
return True
return False
def flags(self, index):
if not index.isValid():
return 0
return QtCore.Qt.ItemFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable)
def create_solder(self):
solder = Solder("new", "")
@ -279,6 +319,8 @@ class SolderListModel(QtCore.QAbstractListModel):
class TempLevelModel(QtCore.QAbstractTableModel):
solder_changed = QtCore.pyqtSignal()
def __init__(self, parent):
super(TempLevelModel, self).__init__(parent)
self._changed = False
@ -327,7 +369,7 @@ class TempLevelModel(QtCore.QAbstractTableModel):
self.temp_levels[index.row()].name = str(variant.toString())
elif col == 1:
self.temp_levels[index.row()].temp = variant.toInt()[0]
self._changed = True
self.solder_changed.emit()
return True
return False
@ -335,14 +377,14 @@ class TempLevelModel(QtCore.QAbstractTableModel):
tmp = self.temp_levels[index]
del self.temp_levels[index]
self.reset()
self._changed = True
self.solder_changed.emit()
return tmp
def add_temp_level(self, index, temp_level):
self.temp_levels.insert(index.row() + 1, temp_level)
set_colors(self.temp_levels)
self.reset()
self._changed = True
self.solder_changed.emit()
def setTempLevels(self, temp_levels):
assert isinstance(temp_levels, list)
@ -357,12 +399,13 @@ class TempLevelModel(QtCore.QAbstractTableModel):
class Plotter(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(Plotter, self).__init__(self.fig)
self.axes = self.fig.add_subplot(111)
self.axes.set_axis_bgcolor('black')
self.axes.set_axis_bgcolor('white')
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)
@ -383,7 +426,6 @@ class Plotter(FigureCanvas):
timer = QtCore.QTimer(self)
self.counter = list()
QtCore.QObject.connect(timer, QtCore.SIGNAL("timeout()"), self.update_figure)
timer.start(1000)
self.updated = True
@ -391,10 +433,22 @@ class Plotter(FigureCanvas):
def update_figure(self):
if self.updated:
updated = False
self.x, self.y, self.xmax, self.ymax, self.duration_points, self.rate_points = self.solder.calc_profile()
self.axes.patches = list()
self.axes.texts = list()
self.x = list()
self.y = list()
#for states, value in self.durations.iteritems():
#annotation.slope_marker((states[0])
try:
self.x, self.y, self.xmax, self.ymax, self.duration_points, self.rate_points = self.solder.calc_profile()
for ix, (a, b) in enumerate(zip(self.x[:-1], self.y[:-1])):
annotation.slope_marker((a + 10, b), (self.y[ix+1] - b) / (self.x[ix+1] - a), ax=self.axes)
except Exception, e:
self.xmax = 500
self.ymax = 300
self.plot_data.set_xdata(self.x)
self.plot_data.set_ydata(self.y)
self.axes.set_xbound(lower=0, upper=self.xmax + 20)
self.axes.set_ybound(lower=0, upper=self.ymax + 20)
@ -402,11 +456,7 @@ class Plotter(FigureCanvas):
self.axes.set_yticks([state.temp for state in self.solder.temp_levels])
self.axes.set_xticks(self.x)
self.plot_data.set_xdata(self.x)
self.plot_data.set_ydata(self.y)
self.plot_data.set_zorder(20)
duration_widget = self.myapp.duration_widget
#duration_widget = self.myapp.duration_widget
#self.selection_data.set_xdata(array(da))
#self.selection_data.set_ydata(array(db))
@ -421,6 +471,9 @@ class Plotter(FigureCanvas):
self.axes.legend(("Estimated profile",))
self.draw()
def solder_changed(self):
self.solder.changed = True
def setData(self, solder):
self.solder = solder
self.updated = True
@ -430,8 +483,8 @@ class AddRemoveWidget(QtGui.QWidget):
def __init__(self, parent, with_upown=True):
#super(AddRemoveWidget, self).__init__(parent)
QtGui.QWidget.__init__(self, parent)
self.add_button = QtGui.QPushButton("Add")
self.remove_button = QtGui.QPushButton("Remove")
self.add_button = QtGui.QPushButton(QtGui.QIcon.fromTheme("list-add"), "")
self.remove_button = QtGui.QPushButton(QtGui.QIcon.fromTheme("list-remove"), "")
sh = "QPushButton:disabled { background-color: #555555; }"
self.remove_button.setStyleSheet(sh)
@ -442,8 +495,8 @@ class AddRemoveWidget(QtGui.QWidget):
self._layout.addWidget(self.add_button)
self._layout.addWidget(self.remove_button)
if with_upown:
self.up_button = QtGui.QPushButton("Up")
self.down_button = QtGui.QPushButton("Down")
self.up_button = QtGui.QPushButton(QtGui.QIcon.fromTheme("go-up"), "")
self.down_button = QtGui.QPushButton(QtGui.QIcon.fromTheme("go-down"), "")
self._layout.addWidget(self.up_button)
self._layout.addWidget(self.down_button)
self.up_button.setStyleSheet(sh)
@ -490,6 +543,7 @@ class ConstraintListModel(QtCore.QAbstractListModel):
class ConstraintWidget(QtGui.QWidget):
solder_changed = QtCore.pyqtSignal()
def __init__(self, name):
super(ConstraintWidget, self).__init__()
self.name = name
@ -503,11 +557,11 @@ class ConstraintWidget(QtGui.QWidget):
self.controls = AddRemoveValueWidget(self)
self.constraint_controls = AddRemoveWidget(self, False)
self.controls.add_button.setText(u"Add TempLevel")
self.controls.remove_button.setText(u"Remove TempLevel")
self.controls.add_button.setText(u"")
self.controls.remove_button.setText(u"")
self.constraint_controls.add_button.setText(u"Add Constraint")
self.constraint_controls.remove_button.setText(u"Remove Constraint")
self.constraint_controls.add_button.setText(u"")
self.constraint_controls.remove_button.setText(u"")
self.constraint_view = QtGui.QListView(self)
self.constraint_view.setModel(self.constraint_model)
@ -524,6 +578,9 @@ class ConstraintWidget(QtGui.QWidget):
h.addWidget(self.all_temp_levels_view, 3)
h.addWidget(self.controls, 1)
h.addWidget(self.selected_temp_levels_view, 3)
self.controls.add_button.setIcon(QtGui.QIcon.fromTheme("go-next"))
self.controls.remove_button.setIcon(QtGui.QIcon.fromTheme("go-previous"))
self.setLayout(h)
self.connect(
@ -566,12 +623,20 @@ class ConstraintWidget(QtGui.QWidget):
QtCore.SIGNAL("valueChanged(int)"),
self.constraint_value_changed)
self.connect(
self.selected_temp_levels_view,
QtCore.SIGNAL("clicked(QModelIndex)"),
self.selected_temp_levels_clicked)
def setData(self, solder):
self.solder = solder
self.all_temp_levels.setTempLevels(solder.temp_levels)
self._set_data(solder)
self.set_controls()
self.controls.up_button.setEnabled(False)
self.controls.down_button.setEnabled(False)
def set_controls(self):
if not self.constraint_model.constraint_list:
self.controls.value.setEnabled(False)
@ -589,9 +654,16 @@ class ConstraintWidget(QtGui.QWidget):
self.controls.down_button.setEnabled(True)
def selected_temp_levels_clicked(self, index):
if index.isValid():
self.controls.up_button.setEnabled(True)
self.controls.down_button.setEnabled(True)
def add_constraint(self):
self.constraint_model.append_constraint()
self.set_controls()
self.solder_changed.emit()
def _constraint_selected(self, index):
raise NotImplementedError()
@ -601,18 +673,17 @@ class ConstraintWidget(QtGui.QWidget):
def add_temp_level_to_constraint(self):
src_row = self.all_temp_levels_view.currentIndex().row()
dst_row = self.selected_temp_levels_view.currentIndex().row()
temp_level = self.all_temp_levels.temp_levels[src_row]
self.selected_temp_levels.temp_levels.insert(dst_row, temp_level)
#tls.append(temp_level)
#tls.sort(key=attrgetter("temp"))
self.selected_temp_levels.temp_levels.append(temp_level)
self.selected_temp_levels.reset()
self.selected_temp_levels_view.clearSelection()
self.selected_temp_levels_view.setCurrentIndex(self.selected_temp_levels.index(len(self.selected_temp_levels.temp_levels)-1,0))
self.solder_changed.emit()
def remove_temp_level_from_constraint(self):
del self.selected_temp_levels.temp_levels[self.selected_temp_levels_view.currentIndex().row()]
self.selected_temp_levels.reset()
self.selected_temp_levels_view.clearSelection()
self.solder_changed.emit()
def remove_constraint(self):
src_row = self.all_temp_levels_view.currentIndex().row()
@ -620,6 +691,7 @@ class ConstraintWidget(QtGui.QWidget):
self.constraint_model.reset()
self.selected_temp_levels.clear()
self.set_controls()
self.solder_changed.emit()
def constraint_value_changed(self, value):
if self.spinbox_block:
@ -627,9 +699,9 @@ class ConstraintWidget(QtGui.QWidget):
return
src_index = self.constraint_view.currentIndex().row()
self.constraint_model.constraint_list[src_index][1] = value
self.solder_changed.emit()
def slot_temp_level_removed(self, temp_level):
deletes = deque()
ix = 0
for temp_levels, v in self.constraint_model.constraint_list:
@ -639,16 +711,19 @@ class ConstraintWidget(QtGui.QWidget):
for i in deletes:
del self.constraint_model.constraint_list[i]
self.reset()
self.solder_changed.emit()
def temp_level_up(self):
dst_row = self.selected_temp_levels_view.currentIndex().row()
self.selected_temp_levels.temp_levels[dst_row - 1], self.selected_temp_levels.temp_levels[dst_row] = self.selected_temp_levels.temp_levels[dst_row], self.selected_temp_levels.temp_levels[dst_row - 1]
self.selected_temp_levels.reset()
self.solder_changed.emit()
def temp_level_down(self):
dst_row = self.selected_temp_levels_view.currentIndex().row()
self.selected_temp_levels.temp_levels[dst_row], self.selected_temp_levels.temp_levels[dst_row + 1] = self.selected_temp_levels.temp_levels[dst_row + 1], self.selected_temp_levels.temp_levels[dst_row]
self.selected_temp_levels.reset()
self.solder_changed.emit()
class DurationConstraintWidget(ConstraintWidget):
@ -720,9 +795,6 @@ class OvenControlsWidget(QtGui.QWidget):
self.setLayout(layout2)
self.connect(
self.start_button,
QtCore.SIGNAL("clicked()"),
@ -757,10 +829,30 @@ class RateConstraintWidget(ConstraintWidget):
self.selected_temp_levels.setTempLevels([])
self.controls.value.setValue(0)
class SolderWidget(QtGui.QWidget):
def __init__(self, parent, readonly=False):
super(SolderWidget, self).__init__(parent)
self.solder_model = SolderListModel(self)
self.solder_view = QtGui.QListView()
self.solder_view.setModel(self.solder_model)
self.solder_controls = AddRemoveWidget(self, False)
layout = QtGui.QHBoxLayout(self)
layout.addWidget(self.solder_view, 3)
layout.addWidget(self.solder_controls, 1)
self.connect(
self.solder_controls.add_button,
QtCore.SIGNAL("clicked()"),
self.solder_model.create_solder)
self.solder_view.setCurrentIndex(self.solder_model.index(0,0))
class TempLevelWidget(QtGui.QWidget):
temp_level_removed = QtCore.pyqtSignal(TempLevel)
solder_changed = QtCore.pyqtSignal()
def __init__(self, parent, readonly=False):
super(TempLevelWidget, self).__init__(parent)
@ -806,6 +898,14 @@ class TempLevelWidget(QtGui.QWidget):
QtCore.SIGNAL("clicked()"),
self.temp_level_down)
self.connect(
self.temp_level_model,
QtCore.SIGNAL("solder_changed()"),
self._solder_changed)
def _solder_changed(self):
self.solder_changed.emit()
def setData(self, solder):
self.temp_level_model.setTempLevels(solder.temp_levels)
@ -817,34 +917,36 @@ class TempLevelWidget(QtGui.QWidget):
self.temp_level_model.add_temp_level(index, TempLevel("new " + str(self.temp_level_model.rowCount(None)), 0))
self.temp_level_view.setCurrentIndex(self.temp_level_model.index(index.row() + 1, 0))
self.plotter.solder.changed = True
self.solder_changed.emit()
def remove_temp_level(self):
self.temp_level_removed.emit(
self.temp_level_model.remove_temp_level(
self.temp_level_view.currentIndex().row()))
self.plotter.solder.changed = True
self.solder_changed.emit()
def temp_level_up(self):
dst_row = self.temp_level_view.currentIndex().row()
self.temp_level_model.temp_levels[dst_row - 1], self.temp_level_model.temp_levels[dst_row] = self.temp_level_model.temp_levels[dst_row], self.temp_level_model.temp_levels[dst_row - 1]
self.temp_level_model.reset()
self.plotter.solder.changed = True
self.solder_changed.emit()
def temp_level_down(self):
dst_row = self.selected_temp_levels_view.currentIndex().row()
self.temp_level_model.temp_levels[dst_row], self.temp_level_model.temp_levels[dst_row + 1] = self.temp_level_model.temp_levels[dst_row + 1], self.temp_level_model.temp_levels[dst_row]
self.temp_level_model.reset()
self.plotter.solder.changed = True
self.solder_changed.emit()
def temp_level_selected(self, index):
if index.isValid():
row = index.row()
is_env = self.temp_level_model.temp_levels[row].is_env
#is_end = row == len(self.temp_level_model.temp_levels) - 1
#self.controls.add_button.setEnabled(not is_end)
self.controls.remove_button.setEnabled(not is_env)
if not self.readonly:
is_env = self.temp_level_model.temp_levels[row].is_env
#is_end = row == len(self.temp_level_model.temp_levels) - 1
#self.controls.add_button.setEnabled(not is_end)
self.controls.remove_button.setEnabled(not is_env)
class ApplicationWindow(QtGui.QMainWindow):
def __init__(self):
@ -857,16 +959,20 @@ class ApplicationWindow(QtGui.QMainWindow):
self.file_menu = QtGui.QMenu('&File', self)
self.file_menu.addAction('&Create profile header', self.create_header,
QtCore.Qt.CTRL + QtCore.Qt.Key_C)
self.file_menu.addAction('&Save plot', self.save_plot,
self.file_menu.addAction('&Save solder', self.save_solder,
QtCore.Qt.CTRL + QtCore.Qt.Key_S)
self.file_menu.addAction('S&ave plot', self.save_plot,
QtCore.Qt.CTRL + QtCore.Qt.Key_A)
self.file_menu.addAction('&Quit', self.fileQuit,
QtCore.Qt.CTRL + QtCore.Qt.Key_Q)
self.menuBar().addMenu(self.file_menu)
self.view_menu = QtGui.QMenu('&View', self)
self.profile_view_action = self.view_menu.addAction("&Profile View")
self.controls_view_action = self.view_menu.addAction("&Oven Controls View")
self.profile_view_action = self.view_menu.addAction("&Profile View", self.open_profile_view,
QtCore.Qt.CTRL + QtCore.Qt.Key_P)
self.controls_view_action = self.view_menu.addAction("&Oven Controls View", self.open_controls_view,
QtCore.Qt.CTRL + QtCore.Qt.Key_O)
self.view_group = QtGui.QActionGroup(self)
@ -878,13 +984,13 @@ class ApplicationWindow(QtGui.QMainWindow):
self.profile_view_action.setCheckable(True)
self.controls_view_action.setCheckable(True)
self.connect(self.profile_view_action,
QtCore.SIGNAL("triggered()"),
self.open_profile_view)
#self.connect(self.profile_view_action,
#QtCore.SIGNAL("triggered()"),
#self.open_profile_view)
self.connect(self.controls_view_action,
QtCore.SIGNAL("triggered()"),
self.open_controls_view)
#self.connect(self.controls_view_action,
#QtCore.SIGNAL("triggered()"),
#self.open_controls_view)
self.profile_view_action.setChecked(True)
@ -896,11 +1002,7 @@ class ApplicationWindow(QtGui.QMainWindow):
self.help_menu.addAction('&About', self.about)
self.solder_model = SolderListModel(self)
self.solder_view = QtGui.QListView()
self.solder_view.setModel(self.solder_model)
self.solder_controls = AddRemoveWidget(self, False)
self.tab_widget = QtGui.QTabWidget(self)
self.temp_level_widget = TempLevelWidget(self)
@ -914,27 +1016,39 @@ class ApplicationWindow(QtGui.QMainWindow):
self.controls_widget = OvenControlsWidget(self)
self.controls_widget.setVisible(False)
self.connect(
self.solder_view,
self.duration_widget,
QtCore.SIGNAL("solder_changed()"),
self.plotter.solder_changed)
self.connect(
self.rate_widget,
QtCore.SIGNAL("solder_changed()"),
self.plotter.solder_changed)
self.connect(
self.temp_level_widget,
QtCore.SIGNAL("solder_changed()"),
self.plotter.solder_changed)
self.solder_widget = SolderWidget(self)
self.connect(
self.solder_widget.solder_view,
QtCore.SIGNAL("clicked(QModelIndex)"),
self.solder_selected)
self.connect(
self.solder_controls.add_button,
QtCore.SIGNAL("clicked()"),
self.solder_model.create_solder)
self.settings_widget = QtGui.QWidget(self)
pl = QtGui.QHBoxLayout(self.settings_widget)
pl.addWidget(self.solder_view, 1)
pl.addWidget(self.solder_controls, 1)
pl.addWidget(self.tab_widget, 6)
pl.addWidget(self.solder_widget, 1)
pl.addWidget(self.tab_widget, 3)
self.splitter = QtGui.QSplitter(QtCore.Qt.Vertical, self)
self.solder_view.setCurrentIndex(self.solder_model.index(0,0))
self.solder_selected(self.solder_model.index(0,0))
self.solder_selected(self.solder_widget.solder_model.index(0,0))
self.splitter.addWidget(self.settings_widget)
self.splitter.addWidget(self.controls_widget)
@ -943,8 +1057,6 @@ class ApplicationWindow(QtGui.QMainWindow):
self.splitter.setStretchFactor(1, 2)
self.splitter.setStretchFactor(2, 8)
self.solder_controls.hide()
self.setCentralWidget(self.splitter)
self.statusBar().showMessage("I'm in reflow heaven", 2000)
@ -968,7 +1080,7 @@ class ApplicationWindow(QtGui.QMainWindow):
def solder_selected(self, index):
if index.isValid():
solder = self.solder_model.listdata[index.row()]
solder = self.solder_widget.solder_model.listdata[index.row()]
self.temp_level_widget.setData(solder)
self.duration_widget.setData(solder)
self.rate_widget.setData(solder)
@ -991,6 +1103,10 @@ class ApplicationWindow(QtGui.QMainWindow):
filename = QtGui.QFileDialog.getSaveFileName(self, 'Save File', 'qtplot.png')
self.plotter.print_figure(str(filename), dpi=self.dpi)
def save_solder(self):
self.plotter.solder.save("foo")
self.solder_widget.solder_model.reload()
def fileQuit(self):
self.close()

View File

@ -2,8 +2,8 @@
<solder_type name="lead noclean" description="">
<state name="environment temp" temperature="$ENV" />
<state name="preheat start" temperature="150" />
<state name="preheat end" temperature="185" />
<state name="tal" temperature="220" />
<state name="preheat end" temperature="180" />
<state name="tal" temperature="230" />
<state name="peak" temperature="260" />
<duration value="100" >
<state name="preheat start" />

View File

@ -1,7 +1,7 @@
<xml>
<solder_type name="leadfree noclean" description="">
<state name="environment temp" temperature="$ENV" />
<state name="preheat start" temperature="150" />
<state name="preheat start" temperature="130" />
<state name="preheat end" temperature="185" />
<state name="tal" temperature="220" />
<state name="peak" temperature="250" />
@ -9,7 +9,7 @@
<state name="preheat start" />
<state name="preheat end" />
</duration>
<duration value="100" >
<duration value="100">
<state name="tal" />
<state name="peak" />
<state name="tal" />

View File

@ -0,0 +1,2 @@
<?xml version='1.0' encoding='UTF-8'?>
<xml><solder_type description="" name="test kotze"><state name="environment temp" temperature="$ENV" /><state name="preheat start" temperature="150" /><state name="preheat end" temperature="185" /><state name="tal" temperature="220" /><state name="peak" temperature="250" /><duration value="100"><state name="preheat start" /><state name="preheat end" /></duration><duration value="100"><state name="tal" /><state name="peak" /><state name="tal" /></duration><rate value="1"><state name="environment temp" /><state name="preheat start" /></rate><rate value="1"><state name="preheat start" /><state name="preheat end" /></rate><rate value="1"><state name="preheat end" /><state name="tal" /></rate><rate value="-2"><state name="peak" /><state name="environment temp" /></rate></solder_type></xml>