qcodespp 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- qcodespp/__init__.py +77 -0
- qcodespp/actions.py +237 -0
- qcodespp/data/__init__.py +0 -0
- qcodespp/data/data_array.py +555 -0
- qcodespp/data/data_set.py +926 -0
- qcodespp/data/format.py +338 -0
- qcodespp/data/gnuplot_format.py +425 -0
- qcodespp/data/hdf5_format.py +537 -0
- qcodespp/data/hdf5_format_hickle.py +63 -0
- qcodespp/data/io.py +241 -0
- qcodespp/data/location.py +171 -0
- qcodespp/instrument_drivers/Keysight/Keysight_34450A.py +9 -0
- qcodespp/instrument_drivers/Keysight/__init__.py +0 -0
- qcodespp/instrument_drivers/Keysight/private/Keysight_344xxA.py +456 -0
- qcodespp/instrument_drivers/Keysight/private/__init__.py +0 -0
- qcodespp/instrument_drivers/Lakeshore/Model_340.py +483 -0
- qcodespp/instrument_drivers/Lakeshore/__init__.py +0 -0
- qcodespp/instrument_drivers/QDevil/159fit_params_high_latest.json +386 -0
- qcodespp/instrument_drivers/QDevil/159fit_params_low_latest.json +386 -0
- qcodespp/instrument_drivers/QDevil/QDAC2.py +3229 -0
- qcodespp/instrument_drivers/QDevil/QDAC2_Array.py +300 -0
- qcodespp/instrument_drivers/QDevil/QSwitch_elab.py +652 -0
- qcodespp/instrument_drivers/QDevil/__init__.py +0 -0
- qcodespp/instrument_drivers/ZI/ZIHF2LI.py +415 -0
- qcodespp/instrument_drivers/ZI/ZIMFLI.py +764 -0
- qcodespp/instrument_drivers/ZI/ZIMFLI_sync.py +108 -0
- qcodespp/instrument_drivers/ZI/ZIUHFLI.py +2179 -0
- qcodespp/instrument_drivers/ZI/__init__.py +1 -0
- qcodespp/instrument_drivers/__init__.py +0 -0
- qcodespp/instrument_drivers/cryogenic/CryogenicSMS120C.py +599 -0
- qcodespp/instrument_drivers/cryogenic/__init__.py +0 -0
- qcodespp/instrument_drivers/instrument_mocks.py +379 -0
- qcodespp/instrument_drivers/multiplexer_instrument.py +287 -0
- qcodespp/instrument_drivers/national_instruments/PXI_4461.py +451 -0
- qcodespp/instrument_drivers/national_instruments/PXI_4462.py +290 -0
- qcodespp/instrument_drivers/national_instruments/PXI_6259.py +436 -0
- qcodespp/instrument_drivers/national_instruments/PXI_6733.py +230 -0
- qcodespp/instrument_drivers/national_instruments/PXI_6733_e.py +243 -0
- qcodespp/instrument_drivers/national_instruments/__init__.py +0 -0
- qcodespp/instrument_drivers/oxford/__init__.py +0 -0
- qcodespp/instrument_drivers/oxford/mercuryiPS_serial.py +658 -0
- qcodespp/instrument_drivers/oxford/triton.py +434 -0
- qcodespp/instrument_drivers/tektronix/Keithley_2000_Scan.py +65 -0
- qcodespp/instrument_drivers/tektronix/Keithley_2182a.py +190 -0
- qcodespp/instrument_drivers/tektronix/Keithley_2400.py +158 -0
- qcodespp/instrument_drivers/tektronix/Keithley_2450.py +242 -0
- qcodespp/instrument_drivers/tektronix/Keithley_2700.py +397 -0
- qcodespp/instrument_drivers/tektronix/Keithley_6500.py +161 -0
- qcodespp/instrument_drivers/tektronix/__init__.py +0 -0
- qcodespp/instrument_drivers/yokogawa/GS200.py +513 -0
- qcodespp/instrument_drivers/yokogawa/__init__.py +0 -0
- qcodespp/loops.py +1342 -0
- qcodespp/measure.py +310 -0
- qcodespp/parameters.py +311 -0
- qcodespp/plotting/RemotePlot.py +469 -0
- qcodespp/plotting/RemotePlotClient.py +367 -0
- qcodespp/plotting/RemoteQtPlotWidgets.py +871 -0
- qcodespp/plotting/__init__.py +0 -0
- qcodespp/plotting/analysis_tools.py +195 -0
- qcodespp/plotting/colors.py +135 -0
- qcodespp/plotting/offline/__init__.py +0 -0
- qcodespp/plotting/offline/datatypes.py +999 -0
- qcodespp/plotting/offline/design.py +906 -0
- qcodespp/plotting/offline/design.ui +1578 -0
- qcodespp/plotting/offline/editor.py +2966 -0
- qcodespp/plotting/offline/filters.py +561 -0
- qcodespp/plotting/offline/fits.py +1171 -0
- qcodespp/plotting/offline/helpers.py +288 -0
- qcodespp/plotting/offline/iconGadget.png +0 -0
- qcodespp/plotting/offline/main.py +55 -0
- qcodespp/plotting/offline/popupwindows.py +1848 -0
- qcodespp/plotting/offline/qcodes_pp_extension.py +328 -0
- qcodespp/plotting/offline/sidebars.py +1108 -0
- qcodespp/station.py +290 -0
- qcodespp/utils/__init__.py +0 -0
- qcodespp/utils/helpers.py +618 -0
- qcodespp/utils/visa_helpers.py +61 -0
- qcodespp/version.py +12 -0
- qcodespp-0.1.0.dist-info/METADATA +91 -0
- qcodespp-0.1.0.dist-info/RECORD +82 -0
- qcodespp-0.1.0.dist-info/WHEEL +4 -0
- qcodespp-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
'''
|
|
2
|
+
Back-end functions used in live plotting. Not intended to be used directly.
|
|
3
|
+
'''
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
import sys
|
|
7
|
+
import os
|
|
8
|
+
import re
|
|
9
|
+
import zmq
|
|
10
|
+
import numpy as np
|
|
11
|
+
import json
|
|
12
|
+
import time
|
|
13
|
+
|
|
14
|
+
from pyqtgraph import dockarea
|
|
15
|
+
|
|
16
|
+
from PyQt5 import QtCore, QtGui, QtWidgets
|
|
17
|
+
from PyQt5.QtWidgets import QWidget, QShortcut, QHBoxLayout
|
|
18
|
+
from PyQt5.QtCore import QBuffer, QIODevice, QByteArray
|
|
19
|
+
from PyQt5.QtCore import QObject, pyqtSlot
|
|
20
|
+
|
|
21
|
+
from RemoteQtPlotWidgets import QtPlot
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
qtapp = QtWidgets.QApplication([])
|
|
25
|
+
|
|
26
|
+
# set app icon
|
|
27
|
+
app_icon = QtGui.QIcon()
|
|
28
|
+
app_icon.addFile('icons/icon_16.png', QtCore.QSize(16,16))
|
|
29
|
+
app_icon.addFile('icons/icon_24.png', QtCore.QSize(24,24))
|
|
30
|
+
app_icon.addFile('icons/icon_32.png', QtCore.QSize(32,32))
|
|
31
|
+
app_icon.addFile('icons/icon_48.png', QtCore.QSize(48,48))
|
|
32
|
+
app_icon.addFile('icons/icon_256.png', QtCore.QSize(256,256))
|
|
33
|
+
qtapp.setWindowIcon(app_icon)
|
|
34
|
+
|
|
35
|
+
class DataSet():
|
|
36
|
+
|
|
37
|
+
def __init__(self, dataset_id):
|
|
38
|
+
self.id = dataset_id
|
|
39
|
+
self.arrays = {}
|
|
40
|
+
self.metadata = {}
|
|
41
|
+
|
|
42
|
+
def add_metadata(self, metadata):
|
|
43
|
+
self.metadata.update(metadata)
|
|
44
|
+
|
|
45
|
+
def get_array(self, array_id, shape=100):
|
|
46
|
+
if not array_id in self.arrays.keys():
|
|
47
|
+
array = self.new_array(array_id, shape=shape)
|
|
48
|
+
return self.arrays[array_id]
|
|
49
|
+
|
|
50
|
+
def new_array(self, array_id, shape):
|
|
51
|
+
self.arrays[array_id] = np.empty(shape=shape)
|
|
52
|
+
self.arrays[array_id][:] = np.nan
|
|
53
|
+
return self.arrays[array_id]
|
|
54
|
+
|
|
55
|
+
def store(self, array_id, indices, values):
|
|
56
|
+
try:
|
|
57
|
+
self.arrays[array_id][indices] = values
|
|
58
|
+
except:
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class ZeroMQ_Listener(QtCore.QObject):
|
|
63
|
+
|
|
64
|
+
message = QtCore.pyqtSignal(str, str, dict)
|
|
65
|
+
|
|
66
|
+
def __init__(self, topic, port):
|
|
67
|
+
|
|
68
|
+
QtCore.QObject.__init__(self)
|
|
69
|
+
|
|
70
|
+
# Socket to talk to server
|
|
71
|
+
context = zmq.Context()
|
|
72
|
+
self.socket = context.socket(zmq.SUB)
|
|
73
|
+
self.socket.connect("tcp://localhost:%s" % (port))
|
|
74
|
+
self.socket.setsockopt(zmq.SUBSCRIBE, bytes(topic.encode('utf-8')))
|
|
75
|
+
|
|
76
|
+
self.poller = zmq.Poller()
|
|
77
|
+
self.poller.register(self.socket, zmq.POLLIN)
|
|
78
|
+
|
|
79
|
+
self.running = True
|
|
80
|
+
|
|
81
|
+
def loop(self):
|
|
82
|
+
while self.running:
|
|
83
|
+
socks = dict(self.poller.poll(500))
|
|
84
|
+
if socks.get(self.socket) == zmq.POLLIN:
|
|
85
|
+
# try:
|
|
86
|
+
parts = self.socket.recv_multipart()
|
|
87
|
+
topic, uuid, msg = parts[:3]
|
|
88
|
+
|
|
89
|
+
topic = topic.decode()
|
|
90
|
+
uuid = uuid.decode()
|
|
91
|
+
data = json.loads(msg.decode())
|
|
92
|
+
|
|
93
|
+
if len(parts) > 3:
|
|
94
|
+
meta = parts[3]
|
|
95
|
+
meta = json.loads(meta.decode())
|
|
96
|
+
arrays = parts[4:]
|
|
97
|
+
|
|
98
|
+
data_arrays = {}
|
|
99
|
+
for m, a in zip(meta, arrays):
|
|
100
|
+
arr = np.frombuffer(
|
|
101
|
+
a, dtype=m['dtype']).reshape(m['shape'])
|
|
102
|
+
|
|
103
|
+
data_arrays[m['array_id']] = arr
|
|
104
|
+
data['add_plot']['data_arrays'] = data_arrays
|
|
105
|
+
|
|
106
|
+
self.message.emit(topic, uuid, data)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class QtPlotWindow(QtWidgets.QWidget):
|
|
110
|
+
|
|
111
|
+
def __init__(self, topic, port, control_port=None, parent=None, theme=((60, 60, 60), 'w'),):
|
|
112
|
+
QtWidgets.QMainWindow.__init__(self, parent)
|
|
113
|
+
self.control_port = control_port
|
|
114
|
+
|
|
115
|
+
self.stores = {}
|
|
116
|
+
self.plots = []
|
|
117
|
+
|
|
118
|
+
self.theme = theme
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
self.set_title('Plot')
|
|
123
|
+
self.title_parts = []
|
|
124
|
+
|
|
125
|
+
self.plot = QtPlot()
|
|
126
|
+
|
|
127
|
+
layout = QHBoxLayout()
|
|
128
|
+
layout.setContentsMargins(0, 0, 0, 0)
|
|
129
|
+
layout.addWidget(self.plot)
|
|
130
|
+
self.setLayout(layout)
|
|
131
|
+
|
|
132
|
+
QShortcut(QtGui.QKeySequence("Ctrl+W"), self, self.close)
|
|
133
|
+
QShortcut(QtGui.QKeySequence("Ctrl+Q"), self, self.close)
|
|
134
|
+
|
|
135
|
+
desktop = QtWidgets.QApplication.desktop()
|
|
136
|
+
screenRect = desktop.screenGeometry(0)
|
|
137
|
+
windowRect = QtCore.QRect(0, 0, 1200, 900)
|
|
138
|
+
windowRect.moveTopRight(screenRect.topRight()-QtCore.QPoint(0, -50))
|
|
139
|
+
self.setGeometry(windowRect)
|
|
140
|
+
|
|
141
|
+
self.thread = QtCore.QThread()
|
|
142
|
+
self.zeromq_listener = ZeroMQ_Listener(topic, port)
|
|
143
|
+
self.zeromq_listener.moveToThread(self.thread)
|
|
144
|
+
|
|
145
|
+
self.thread.started.connect(self.zeromq_listener.loop)
|
|
146
|
+
self.zeromq_listener.message.connect(self.signal_received)
|
|
147
|
+
|
|
148
|
+
QtCore.QTimer.singleShot(0, self.thread.start)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
if self.control_port is not None:
|
|
152
|
+
self.control_context = zmq.Context()
|
|
153
|
+
self.control_socket = self.control_context.socket(zmq.PUB)
|
|
154
|
+
self.control_socket.connect(
|
|
155
|
+
"tcp://localhost:%s" % (self.control_port))
|
|
156
|
+
|
|
157
|
+
# Only way on windows to make it open on top of others...
|
|
158
|
+
# And it doesn't really work :O
|
|
159
|
+
self.setWindowFlags(self.windowFlags() &
|
|
160
|
+
QtCore.Qt.WindowStaysOnTopHint)
|
|
161
|
+
self.setWindowFlags(self.windowFlags() & ~
|
|
162
|
+
QtCore.Qt.WindowStaysOnTopHint)
|
|
163
|
+
self.show()
|
|
164
|
+
|
|
165
|
+
self.update_interval = 1
|
|
166
|
+
self._last_update = time.perf_counter()
|
|
167
|
+
self._do_update = False
|
|
168
|
+
|
|
169
|
+
self.update_timer = QtCore.QTimer()
|
|
170
|
+
self.update_timer.timeout.connect(self.auto_update)
|
|
171
|
+
self.update_timer.start(50)
|
|
172
|
+
|
|
173
|
+
self.control_send({'client_ready': True})
|
|
174
|
+
cwd = os.getcwd()
|
|
175
|
+
self.control_send({'client_dir': str(cwd)})
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def auto_update(self):
|
|
179
|
+
|
|
180
|
+
# if dt < self.update_interval:
|
|
181
|
+
# QtCore.QTimer.singleShot(0. 1, self._auto_update)
|
|
182
|
+
|
|
183
|
+
if self._do_update:
|
|
184
|
+
for plot in self.plots:
|
|
185
|
+
# TODO only update when there is new data
|
|
186
|
+
plot['plot_item'].update_data()
|
|
187
|
+
self._last_update = time.perf_counter()
|
|
188
|
+
self._do_update = False
|
|
189
|
+
|
|
190
|
+
def control_send(self, data):
|
|
191
|
+
if self.control_port is not None:
|
|
192
|
+
self.control_socket.send_json(data)
|
|
193
|
+
|
|
194
|
+
def get_default_title(self):
|
|
195
|
+
self.title_parts = sorted(list(set(self.title_parts)))
|
|
196
|
+
title = ', '.join(self.title_parts)
|
|
197
|
+
if title == '':
|
|
198
|
+
title = 'Plot'
|
|
199
|
+
return title
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def set_title(self, title=None):
|
|
203
|
+
|
|
204
|
+
if title is None:
|
|
205
|
+
title = self.get_default_title()
|
|
206
|
+
|
|
207
|
+
self.setWindowTitle(title)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def signal_received(self, topic, uuid, message):
|
|
211
|
+
if uuid not in self.stores:
|
|
212
|
+
self.stores[uuid] = DataSet(uuid)
|
|
213
|
+
store = self.stores[uuid]
|
|
214
|
+
|
|
215
|
+
for key, msg in message.items():
|
|
216
|
+
if key == 'new_dataset':
|
|
217
|
+
store.add_metadata(msg)
|
|
218
|
+
elif key == 'clear_plot':
|
|
219
|
+
del self.stores
|
|
220
|
+
self.stores = {}
|
|
221
|
+
|
|
222
|
+
for p in self.plots:
|
|
223
|
+
del p
|
|
224
|
+
self.plots = []
|
|
225
|
+
self.title_parts = []
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
self.plot.clear()
|
|
229
|
+
|
|
230
|
+
elif key == 'metadata':
|
|
231
|
+
store.add_metadata(msg)
|
|
232
|
+
|
|
233
|
+
if 'arrays' in msg:
|
|
234
|
+
arrays = msg['arrays']
|
|
235
|
+
for array_id, value in arrays.items():
|
|
236
|
+
store.get_array(array_id, arrays[array_id]['shape'])
|
|
237
|
+
|
|
238
|
+
elif key == 'add_plot':
|
|
239
|
+
data_arrays = msg.get('data_arrays', None)
|
|
240
|
+
for ax in 'xyz':
|
|
241
|
+
array_info = msg.get(ax+'_info', None)
|
|
242
|
+
if array_info is not None:
|
|
243
|
+
array_id = array_info.get('array_id', None)
|
|
244
|
+
if array_info.get('location', None) is not None:
|
|
245
|
+
self.title_parts.append(array_info['location'])
|
|
246
|
+
|
|
247
|
+
if array_id is not None:
|
|
248
|
+
msg[ax] = store.get_array(array_id, array_info['shape'])
|
|
249
|
+
if data_arrays is not None:
|
|
250
|
+
data = data_arrays.get(array_id, None)
|
|
251
|
+
if data is not None:
|
|
252
|
+
msg[ax] = data
|
|
253
|
+
# print(msg)
|
|
254
|
+
pi = self.plot.add(**msg)
|
|
255
|
+
|
|
256
|
+
msg['plot_item'] = pi
|
|
257
|
+
self.plots.append(msg)
|
|
258
|
+
self.set_title()
|
|
259
|
+
|
|
260
|
+
elif key == 'data':
|
|
261
|
+
|
|
262
|
+
if store.arrays == {}:
|
|
263
|
+
return
|
|
264
|
+
ids_values = msg['values']
|
|
265
|
+
loop_indices = tuple(msg['indices'])
|
|
266
|
+
|
|
267
|
+
for array_id, value in ids_values.items():
|
|
268
|
+
store.store(array_id, loop_indices, value)
|
|
269
|
+
self._do_update = True
|
|
270
|
+
|
|
271
|
+
elif key == 'finalize':
|
|
272
|
+
self.save()
|
|
273
|
+
elif key == 'save_screenshot':
|
|
274
|
+
filename, subplot = msg['filename'], msg['subplot']
|
|
275
|
+
print(filename)
|
|
276
|
+
if subplot == 'all':
|
|
277
|
+
for i in range(len(self.plot.area.docks)):
|
|
278
|
+
self.save(filename, i)
|
|
279
|
+
else:
|
|
280
|
+
self.save(filename, subplot)
|
|
281
|
+
elif key == 'set_title':
|
|
282
|
+
self.setWindowTitle(msg)
|
|
283
|
+
elif key == 'set_cmap':
|
|
284
|
+
for dock in self.plot.area.docks.keys():
|
|
285
|
+
self.plot.area.docks[dock].set_cmap(msg)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
else:
|
|
289
|
+
pass
|
|
290
|
+
|
|
291
|
+
self.control_send({'client_ready': True})
|
|
292
|
+
|
|
293
|
+
def update_labels(self):
|
|
294
|
+
# for array_id, plot in self.plots.items():
|
|
295
|
+
pass
|
|
296
|
+
|
|
297
|
+
def save(self, filename=None, subplot=None):
|
|
298
|
+
"""
|
|
299
|
+
Save current plot to filename, by default
|
|
300
|
+
to the location corresponding to the default
|
|
301
|
+
title.
|
|
302
|
+
|
|
303
|
+
Args:
|
|
304
|
+
filename (Optional[str]): Location of the file
|
|
305
|
+
"""
|
|
306
|
+
|
|
307
|
+
if len(self.title_parts)>0:
|
|
308
|
+
default = "{}".format(self.title_parts[-1])
|
|
309
|
+
else:
|
|
310
|
+
default = 'Plot'
|
|
311
|
+
|
|
312
|
+
if (filename is None) or (filename == 'None'):
|
|
313
|
+
filename = default
|
|
314
|
+
|
|
315
|
+
filename = re.sub(r"\.png$", "", filename)
|
|
316
|
+
filename = filename.rstrip('\\')
|
|
317
|
+
filename = filename.rstrip('/')
|
|
318
|
+
if subplot is None:
|
|
319
|
+
image = self.grab()
|
|
320
|
+
else:
|
|
321
|
+
image = self.plot._get_dock(int(subplot)).grab()
|
|
322
|
+
filename = '%s #%d'%(filename, int(subplot))
|
|
323
|
+
|
|
324
|
+
i = 0
|
|
325
|
+
oldfilename = filename
|
|
326
|
+
while os.path.isfile(filename+'.png'):
|
|
327
|
+
filename = oldfilename + '_%d'%i
|
|
328
|
+
i+=1
|
|
329
|
+
self.control_send({'plot_saved': filename+'.png'})
|
|
330
|
+
print(filename+'.png')
|
|
331
|
+
image.save(filename+'.png', "PNG", 0)
|
|
332
|
+
|
|
333
|
+
def closeEvent(self, event):
|
|
334
|
+
self.zeromq_listener.running = False
|
|
335
|
+
self.thread.quit()
|
|
336
|
+
self.thread.wait()
|
|
337
|
+
self.control_send({'client_closed': True})
|
|
338
|
+
event.accept()
|
|
339
|
+
|
|
340
|
+
if __name__ == '__main__':
|
|
341
|
+
import sys
|
|
342
|
+
|
|
343
|
+
control_port = None
|
|
344
|
+
if len(sys.argv) > 1:
|
|
345
|
+
topic = str(sys.argv[1])
|
|
346
|
+
port = str(sys.argv[2])
|
|
347
|
+
control_port = str(sys.argv[3])
|
|
348
|
+
else:
|
|
349
|
+
port, topic = (8883, 'qcodes.plot.b1c4400fea6546afbae3bfead88bc234')
|
|
350
|
+
|
|
351
|
+
mw = QtPlotWindow(topic=topic, port=port, control_port=control_port)
|
|
352
|
+
|
|
353
|
+
# set app icon
|
|
354
|
+
app_icon = QtGui.QIcon()
|
|
355
|
+
app_icon.addFile('icons/icon_16.png', QtCore.QSize(16,16))
|
|
356
|
+
app_icon.addFile('icons/icon_24.png', QtCore.QSize(24,24))
|
|
357
|
+
app_icon.addFile('icons/icon_32.png', QtCore.QSize(32,32))
|
|
358
|
+
app_icon.addFile('icons/icon_48.png', QtCore.QSize(48,48))
|
|
359
|
+
app_icon.addFile('icons/icon_256.png', QtCore.QSize(256,256))
|
|
360
|
+
mw.setWindowIcon(app_icon)
|
|
361
|
+
|
|
362
|
+
# mw.signal_received(topic=topic, uuid=None, message ={'save_screenshot': {'filename': str('./aafsd/asdfnp'), 'subplot': 'all'}})
|
|
363
|
+
|
|
364
|
+
# mw.save()
|
|
365
|
+
|
|
366
|
+
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
|
|
367
|
+
QtWidgets.QApplication.instance().exec_()
|