Skip to content

Commit

Permalink
Annotator improvements (#27)
Browse files Browse the repository at this point in the history
* Fix: device annotator use left and right button to insert label and ano

* Fix: add device annotator
Fix: add tooltip explaining left and right click

* Fix: make device annotator label and formatter configurable

* Fix: use formatter in placeholder string

* Fix: rename loop parameter

* fix: make it possible to remove annotation/label

* Fix: mark parameters red in device annotator if sweept
  • Loading branch information
jenshnielsen committed Aug 7, 2017
1 parent 17716d4 commit a02db1c
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 27 deletions.
102 changes: 80 additions & 22 deletions qcodes/utils/qcodes_device_annotator.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,30 @@ def __init__(self, folder, station):
self.setLayout(grid)

self.imageCanvas = qt.QLabel()
self.imageCanvas.setToolTip("Left click to insert a label and right click to insert an annotation.")
self.loadButton = qt.QPushButton('Load image')
self.labelButton = qt.QRadioButton("Insert Label")
self.labelButton.setChecked(True)
self.annotButton = qt.QRadioButton('Place annotation')

self.okButton = qt.QPushButton('Save and close')

self.removeButton = qt.QPushButton('Remove')
self.removeButton.setToolTip("Remove annotation and label for this parameter")
self.labeltitle = qt.QLabel('Label:')
self.labelfield = qt.QLineEdit()
self.labelfield.setText('')
self.labelfield.setToolTip("String to be used as label. Defaults to instrument_parameter")
self.formattertitle = qt.QLabel('Formatter:')
self.formatterfield = qt.QLineEdit()
self.formatterfield.setText('')
self.formatterfield.setToolTip("Formatter to be used for this parameter:\n"
"Uses new style python formatters. I.e.\n"
"':.4f' standard formatter with 4 digits after the decimal point\n"
"':.2e' exponential formatter with 2 digits after the decimal point\n"
"Leave blank for default. \n"
"See www.pyformat.info for more examples")
self.loadButton.clicked.connect(self.loadimage)
self.imageCanvas.mousePressEvent = self.set_label_or_annotation
self.imageCanvas.setStyleSheet('background-color: white')
self.okButton.clicked.connect(self.saveAndClose)
self.removeButton.clicked.connect(self.remove_label_and_annotation)

self.treeView = qt.QTreeView()
self.model = gui.QStandardItemModel()
Expand All @@ -51,10 +64,14 @@ def __init__(self, folder, station):
self.treeView.setModel(self.model)
self.treeView.sortByColumn(0, core.Qt.AscendingOrder)
self.treeView.setSortingEnabled(True)
self.treeView.clicked.connect(self.selection_changed)
grid.addWidget(self.imageCanvas, 0, 0, 4, 6)
grid.addWidget(self.loadButton, 4, 0)
grid.addWidget(self.labelButton, 4, 1)
grid.addWidget(self.annotButton, 4, 2)
grid.addWidget(self.labeltitle, 4, 1)
grid.addWidget(self.labelfield, 4, 2)
grid.addWidget(self.formattertitle, 4, 4)
grid.addWidget(self.formatterfield, 4, 5)
grid.addWidget(self.removeButton, 4, 8)
grid.addWidget(self.okButton, 4, 9)
grid.addWidget(self.treeView, 0, 6, 4, 4)

Expand Down Expand Up @@ -95,9 +112,21 @@ def loadimage(self):
self.imageCanvas.setMaximumWidth(width)
self.imageCanvas.setMaximumHeight(height)

def set_label_or_annotation(self, event):

def selection_changed(self):
if not self.treeView.selectedIndexes():
return
selected = self.treeView.selectedIndexes()[0]
selected_instrument = selected.parent().data()
selected_parameter = selected.data()
self.labelfield.setText("{}_{} ".format(selected_instrument, selected_parameter))

def set_label_or_annotation(self, event):
insertlabel = False
insertannotation = False
if event.button() == core.Qt.LeftButton:
insertlabel = True
elif event.button() == core.Qt.RightButton:
insertannotation = True
# verify valid
if not self.treeView.selectedIndexes():
return
Expand All @@ -113,12 +142,29 @@ def set_label_or_annotation(self, event):
if selected_parameter not in self._data[selected_instrument].keys():
self._data[selected_instrument][selected_parameter] = {}

if self.labelButton.isChecked():
if insertlabel:
self._data[selected_instrument][selected_parameter]['labelpos'] = (self.click_x, self.click_y)
elif self.annotButton.isChecked():
self._data[selected_instrument][selected_parameter]['labelstring'] = self.labelfield.text()
elif insertannotation:
self._data[selected_instrument][selected_parameter]['annotationpos'] = (self.click_x, self.click_y)
self._data[selected_instrument][selected_parameter]['value'] = 'NaN'
if self.formatterfield.text():
formatstring = '{' + self.formatterfield.text() + "}"
self._data[selected_instrument][selected_parameter]['annotationformatter'] = formatstring
self._data[selected_instrument][selected_parameter]['value'] = formatstring
else:
self._data[selected_instrument][selected_parameter]['value'] = 'NaN'

# draw it
self.imageCanvas, _ = self._renderImage(self._data,
self.imageCanvas,
self.filename)

def remove_label_and_annotation(self):
selected = self.treeView.selectedIndexes()[0]
selected_instrument = selected.parent().data()
selected_parameter = selected.data()
if selected_parameter in self._data[selected_instrument].keys():
self._data[selected_instrument][selected_parameter] = {}
# draw it
self.imageCanvas, _ = self._renderImage(self._data,
self.imageCanvas,
Expand Down Expand Up @@ -170,13 +216,19 @@ def _renderImage(data, canvas, filename, title=None):
title)

for instrument, parameters in data.items():
for parameter, positions in parameters.items():

if 'labelpos' in positions:
label_string = "{}_{} ".format(instrument, parameter)
(lx, ly) = positions['labelpos']
painter.setBrush(gui.QColor(255, 255, 255, 100))
for parameter, paramsettings in parameters.items():

if 'labelpos' in paramsettings:
if paramsettings.get('labelstring'):
label_string = paramsettings.get('labelstring')
else:
label_string = "{}_{} ".format(instrument, parameter)
if paramsettings.get('update'):
#parameters that are sweeped should be red.
painter.setBrush(gui.QColor(255, 0, 0, 100))
else:
painter.setBrush(gui.QColor(255, 255, 255, 100))
(lx, ly) = paramsettings['labelpos']
textfont = gui.QFont('Decorative', label_size)
textwidth = gui.QFontMetrics(textfont).width(label_string)
rectangle_start_x = lx - spacing
Expand All @@ -195,9 +247,9 @@ def _renderImage(data, canvas, filename, title=None):
core.Qt.AlignCenter,
label_string)

if 'annotationpos' in positions:
(ax, ay) = positions['annotationpos']
annotationstring = data[instrument][parameter]['value']
if 'annotationpos' in paramsettings:
(ax, ay) = paramsettings['annotationpos']
annotationstring = paramsettings['value']

textfont = gui.QFont('Decorative', label_size)
textwidth = gui.QFontMetrics(textfont).width(annotationstring)
Expand Down Expand Up @@ -270,7 +322,7 @@ def loadAnnotations(self):
with open(json_filename, 'r') as fid:
self._data = json.load(fid)

def updateValues(self, station):
def updateValues(self, station, sweeptparameters=None):
"""
Update the data with actual voltages from the QDac
"""
Expand All @@ -280,13 +332,19 @@ def updateValues(self, station):
value = station.components[instrument][parameter].get_latest()
try:
floatvalue = float(station.components[instrument][parameter].get_latest())
if floatvalue > 1000 or floatvalue < 0.1:
if self._data[instrument][parameter].get('annotationformatter'):
valuestr = self._data[instrument][parameter].get('annotationformatter').format(floatvalue)
elif floatvalue > 1000 or floatvalue < 0.1:
valuestr = "{:.2e}".format(floatvalue)
else:
valuestr = "{:.2f}".format(floatvalue)
except (ValueError, TypeError):
valuestr = str(value)
self._data[instrument][parameter]['value'] = valuestr
if sweeptparameters:
for sweeptparameter in sweeptparameters:
if sweeptparameter._instrument.name == instrument and sweeptparameter.name == parameter:
self._data[instrument][parameter]['update'] = True

def makePNG(self, counter, path=None, title=None):
"""
Expand Down
10 changes: 5 additions & 5 deletions qcodes/utils/wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,11 +218,11 @@ def _create_plot(i, name, data, counter_two):



def save_device_image():
def save_device_image(sweeptparameters):
counter = CURRENT_EXPERIMENT['provider'].counter
title = "{} #{:03d}".format(CURRENT_EXPERIMENT["sample_name"], counter)
di = CURRENT_EXPERIMENT['device_image']
di.updateValues(CURRENT_EXPERIMENT['station'])
di.updateValues(CURRENT_EXPERIMENT['station'], sweeptparameters)

log.debug(os.path.join(CURRENT_EXPERIMENT["exp_folder"],
'{:03d}'.format(counter)))
Expand Down Expand Up @@ -267,7 +267,7 @@ def do1d(inst_set, start, stop, num_points, delay, *inst_meas):
_save_individual_plots(data, plottables)
if CURRENT_EXPERIMENT.get('device_image'):
log.debug('Saving device image')
save_device_image()
save_device_image((inst_set,))

# add the measurement ID to the logfile
with open(CURRENT_EXPERIMENT['logfile'], 'a') as fid:
Expand Down Expand Up @@ -314,7 +314,7 @@ def do1dDiagonal(inst_set, inst2_set, start, stop, num_points, delay, start2, sl
_save_individual_plots(data, plottables)
pdfplot.save("{}.pdf".format(plot.get_default_title()))
if CURRENT_EXPERIMENT.get('device_image'):
save_device_image()
save_device_image((inst_set, inst2_set))

# add the measurement ID to the logfile
with open(CURRENT_EXPERIMENT['logfile'], 'a') as fid:
Expand Down Expand Up @@ -367,7 +367,7 @@ def do2d(inst_set, start, stop, num_points, delay, inst_set2, start2, stop2, num
_save_individual_plots(data, plottables)
pdfplot.save("{}.pdf".format(plot.get_default_title()))
if CURRENT_EXPERIMENT.get('device_image'):
save_device_image()
save_device_image((inst_set, inst_set2))

# add the measurement ID to the logfile
with open(CURRENT_EXPERIMENT['logfile'], 'a') as fid:
Expand Down

0 comments on commit a02db1c

Please sign in to comment.