-
Notifications
You must be signed in to change notification settings - Fork 201
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
14 changed files
with
742 additions
and
500 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
#!/usr/bin/env python3.5 | ||
|
||
import numpy as np | ||
import pyqtgraph | ||
|
||
from artiq.applets.simple import SimpleApplet | ||
|
||
|
||
class HistogramPlot(pyqtgraph.PlotWidget): | ||
def __init__(self, args): | ||
pyqtgraph.PlotWidget.__init__(self) | ||
self.args = args | ||
|
||
def data_changed(self, data, mods): | ||
try: | ||
y = data[self.args.y][1] | ||
if self.args.x is None: | ||
x = None | ||
else: | ||
x = data[self.args.x][1] | ||
except KeyError: | ||
return | ||
if x is None: | ||
x = list(range(len(y)+1)) | ||
|
||
if len(y) and len(x) == len(y) + 1: | ||
self.clear() | ||
self.plot(x, y, stepMode=True, fillLevel=0, | ||
brush=(0, 0, 255, 150)) | ||
|
||
|
||
def main(): | ||
applet = SimpleApplet(HistogramPlot) | ||
applet.add_dataset("y", "Y values") | ||
applet.add_dataset("x", "Bin boundaries", required=False) | ||
applet.run() | ||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
#!/usr/bin/env python3.5 | ||
|
||
import numpy as np | ||
import pyqtgraph | ||
|
||
from artiq.applets.simple import SimpleApplet | ||
|
||
|
||
class XYPlot(pyqtgraph.PlotWidget): | ||
def __init__(self, args): | ||
pyqtgraph.PlotWidget.__init__(self) | ||
self.args = args | ||
|
||
def data_changed(self, data, mods): | ||
try: | ||
y = data[self.args.y][1] | ||
except KeyError: | ||
return | ||
x = data.get(self.args.x, (False, None))[1] | ||
if x is None: | ||
x = list(range(len(y))) | ||
error = data.get(self.args.error, (False, None))[1] | ||
fit = data.get(self.args.fit, (False, None))[1] | ||
|
||
if not len(y) or len(y) != len(x): | ||
return | ||
if error is not None and hasattr(error, "__len__"): | ||
if not len(error): | ||
error = None | ||
elif len(error) != len(y): | ||
return | ||
if fit is not None: | ||
if not len(fit): | ||
fit = None | ||
elif len(fit) != len(y): | ||
return | ||
|
||
self.clear() | ||
self.plot(x, y, pen=None, symbol="x") | ||
if error is not None: | ||
# See https://github.com/pyqtgraph/pyqtgraph/issues/211 | ||
if hasattr(error, "__len__") and not isinstance(error, np.ndarray): | ||
error = np.array(error) | ||
errbars = pg.ErrorBarItem(x=np.array(x), y=np.array(y), height=error) | ||
self.addItem(errbars) | ||
if fit is not None: | ||
self.plot(x, fit) | ||
|
||
|
||
def main(): | ||
applet = SimpleApplet(XYPlot) | ||
applet.add_dataset("y", "Y values") | ||
applet.add_dataset("x", "X values", required=False) | ||
applet.add_dataset("error", "Error bars for each X value", required=False) | ||
applet.add_dataset("fit", "Fit values for each X value", required=False) | ||
applet.run() | ||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,69 +1,136 @@ | ||
#!/usr/bin/env python3.5 | ||
|
||
from pyqtgraph.Qt import QtGui, QtCore | ||
import pyqtgraph as pg | ||
|
||
import numpy as np | ||
from quamash import QtWidgets | ||
import pyqtgraph | ||
|
||
from artiq.applets.simple import SimpleApplet | ||
|
||
|
||
def _compute_ys(histogram_bins, histograms_counts): | ||
bin_centers = np.empty(len(histogram_bins)-1) | ||
for i in range(len(bin_centers)): | ||
bin_centers[i] = (histogram_bins[i] + histogram_bins[i+1])/2 | ||
|
||
ys = np.empty(histograms_counts.shape[0]) | ||
for n, counts in enumerate(histograms_counts): | ||
ys[n] = sum(bin_centers*counts)/sum(counts) | ||
return ys | ||
|
||
class XYHistPlot: | ||
def __init__(self): | ||
self.graphics_window = pg.GraphicsWindow(title="XY/Histogram") | ||
self.graphics_window.resize(1000,600) | ||
self.graphics_window.setWindowTitle("XY/Histogram") | ||
|
||
self.xy_plot = self.graphics_window.addPlot() | ||
# pyqtgraph.GraphicsWindow fails to behave like a regular Qt widget | ||
# and breaks embedding. Do not use as top widget. | ||
class XYHistPlot(QtWidgets.QSplitter): | ||
def __init__(self, args): | ||
QtWidgets.QSplitter.__init__(self) | ||
self.resize(1000,600) | ||
self.setWindowTitle("XY/Histogram") | ||
|
||
self.xy_plot = pyqtgraph.PlotWidget() | ||
self.insertWidget(0, self.xy_plot) | ||
self.xy_plot_data = None | ||
self.arrow = None | ||
self.selected_index = None | ||
|
||
self.hist_plot = self.graphics_window.addPlot() | ||
self.hist_plot = pyqtgraph.PlotWidget() | ||
self.insertWidget(1, self.hist_plot) | ||
self.hist_plot_data = None | ||
|
||
def set_data(self, xs, histograms_bins, histograms_counts): | ||
ys = np.empty_like(xs) | ||
ys.fill(np.nan) | ||
for n, (bins, counts) in enumerate(zip(histograms_bins, | ||
histograms_counts)): | ||
bin_centers = np.empty(len(bins)-1) | ||
for i in range(len(bin_centers)): | ||
bin_centers[i] = (bins[i] + bins[i+1])/2 | ||
ys[n] = sum(bin_centers*counts)/sum(bin_centers) | ||
self.args = args | ||
|
||
def _set_full_data(self, xs, histogram_bins, histograms_counts): | ||
self.xy_plot.clear() | ||
self.hist_plot.clear() | ||
self.xy_plot_data = None | ||
self.hist_plot_data = None | ||
self.arrow = None | ||
self.selected_index = None | ||
|
||
self.histogram_bins = histogram_bins | ||
|
||
ys = _compute_ys(self.histogram_bins, histograms_counts) | ||
self.xy_plot_data = self.xy_plot.plot(x=xs, y=ys, | ||
pen=None, | ||
symbol="x", symbolSize=20) | ||
self.xy_plot_data.sigPointsClicked.connect(self.point_clicked) | ||
for point, bins, counts in zip(self.xy_plot_data.scatter.points(), | ||
histograms_bins, histograms_counts): | ||
point.histogram_bins = bins | ||
self.xy_plot_data.sigPointsClicked.connect(self._point_clicked) | ||
for index, (point, counts) in ( | ||
enumerate(zip(self.xy_plot_data.scatter.points(), | ||
histograms_counts))): | ||
point.histogram_index = index | ||
point.histogram_counts = counts | ||
|
||
self.hist_plot_data = self.hist_plot.plot( | ||
stepMode=True, fillLevel=0, | ||
brush=(0, 0, 255, 150)) | ||
stepMode=True, fillLevel=0, | ||
brush=(0, 0, 255, 150)) | ||
|
||
def _set_partial_data(self, xs, histograms_counts): | ||
ys = _compute_ys(self.histogram_bins, histograms_counts) | ||
self.xy_plot_data.setData(x=xs, y=ys, | ||
pen=None, | ||
symbol="x", symbolSize=20) | ||
for index, (point, counts) in ( | ||
enumerate(zip(self.xy_plot_data.scatter.points(), | ||
histograms_counts))): | ||
point.histogram_index = index | ||
point.histogram_counts = counts | ||
|
||
def point_clicked(self, data_item, spot_items): | ||
def _point_clicked(self, data_item, spot_items): | ||
spot_item = spot_items[0] | ||
position = spot_item.pos() | ||
if self.arrow is None: | ||
self.arrow = pg.ArrowItem(angle=-120, tipAngle=30, baseAngle=20, | ||
headLen=40, tailLen=40, tailWidth=8, | ||
pen=None, brush="y") | ||
self.arrow = pyqtgraph.ArrowItem( | ||
angle=-120, tipAngle=30, baseAngle=20, headLen=40, | ||
tailLen=40, tailWidth=8, pen=None, brush="y") | ||
self.arrow.setPos(position) | ||
# NB: temporary glitch if addItem is done before setPos | ||
self.xy_plot.addItem(self.arrow) | ||
else: | ||
self.arrow.setPos(position) | ||
self.hist_plot_data.setData(x=spot_item.histogram_bins, | ||
self.selected_index = spot_item.histogram_index | ||
self.hist_plot_data.setData(x=self.histogram_bins, | ||
y=spot_item.histogram_counts) | ||
|
||
def _can_use_partial(self, mods): | ||
if self.hist_plot_data is None: | ||
return False | ||
for mod in mods: | ||
if mod["action"] != "setitem": | ||
return False | ||
if mod["path"] == [self.args.xs, 1]: | ||
if mod["key"] == self.selected_index: | ||
return False | ||
elif mod["path"][:2] == [self.args.histograms_counts, 1]: | ||
if len(mod["path"]) > 2: | ||
index = mod["path"][2] | ||
else: | ||
index = mod["key"] | ||
if index == self.selected_index: | ||
return False | ||
else: | ||
return False | ||
return True | ||
|
||
def data_changed(self, data, mods): | ||
try: | ||
xs = data[self.args.xs][1] | ||
histogram_bins = data[self.args.histogram_bins][1] | ||
histograms_counts = data[self.args.histograms_counts][1] | ||
except KeyError: | ||
return | ||
if self._can_use_partial(mods): | ||
self._set_partial_data(xs, histograms_counts) | ||
else: | ||
self._set_full_data(xs, histogram_bins, histograms_counts) | ||
|
||
|
||
def main(): | ||
app = QtGui.QApplication([]) | ||
plot = XYHistPlot() | ||
plot.set_data(np.array([1, 2, 3, 4, 1]), | ||
np.array([[1, 2, 3], [1, 2, 3], [1, 2, 3], [40, 70, 100], [4, 7, 10, 20]]), | ||
np.array([[1, 1], [2, 3], [10, 20], [3, 1], [100, 67, 102]])) | ||
app.exec_() | ||
|
||
if __name__ == '__main__': | ||
applet = SimpleApplet(XYHistPlot) | ||
applet.add_dataset("xs", "1D array of point abscissas") | ||
applet.add_dataset("histogram_bins", | ||
"1D array of histogram bin boundaries") | ||
applet.add_dataset("histograms_counts", | ||
"2D array of histogram counts, for each point") | ||
applet.run() | ||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,289 @@ | ||
import logging | ||
import asyncio | ||
import sys | ||
import shlex | ||
from functools import partial | ||
|
||
from quamash import QtCore, QtGui, QtWidgets | ||
from pyqtgraph import dockarea | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class AppletDock(dockarea.Dock): | ||
def __init__(self, token, name, command): | ||
dockarea.Dock.__init__(self, "applet" + str(token), | ||
label="Applet: " + name, | ||
closable=True) | ||
self.setMinimumSize(QtCore.QSize(500, 400)) | ||
self.token = token | ||
self.applet_name = name | ||
self.command = command | ||
|
||
def rename(self, name): | ||
self.applet_name = name | ||
self.label.setText("Applet: " + name) | ||
|
||
async def start(self): | ||
command = self.command.format(python=sys.executable, | ||
embed_token=self.token) | ||
logger.debug("starting command %s for %s", command, self.applet_name) | ||
try: | ||
self.process = await asyncio.create_subprocess_exec( | ||
*shlex.split(command)) | ||
except: | ||
logger.warning("Applet %s failed to start", self.applet_name, | ||
exc_info=True) | ||
|
||
def capture(self, win_id): | ||
logger.debug("capturing window 0x%x for %s", win_id, self.applet_name) | ||
self.captured_window = QtGui.QWindow.fromWinId(win_id) | ||
self.captured_widget = QtWidgets.QWidget.createWindowContainer( | ||
self.captured_window) | ||
self.addWidget(self.captured_widget) | ||
|
||
async def terminate(self): | ||
if hasattr(self, "captured_window"): | ||
self.captured_window.close() | ||
self.captured_widget.deleteLater() | ||
del self.captured_window | ||
del self.captured_widget | ||
if hasattr(self, "process"): | ||
try: | ||
await asyncio.wait_for(self.process.wait(), 2.0) | ||
except: | ||
logger.warning("Applet %s failed to exit, killing", | ||
self.applet_name) | ||
try: | ||
self.process.kill() | ||
except ProcessLookupError: | ||
pass | ||
await self.process.wait() | ||
del self.process | ||
|
||
async def restart(self): | ||
await self.terminate() | ||
await self.start() | ||
|
||
|
||
_templates = [ | ||
("Big number", "{python} -m artiq.applets.big_number " | ||
"--embed {embed_token} NUMBER_DATASET"), | ||
("Histogram", "{python} -m artiq.applets.plot_hist " | ||
"--embed {embed_token} COUNTS_DATASET " | ||
"--x BIN_BOUNDARIES_DATASET"), | ||
("XY", "{python} -m artiq.applets.plot_xy " | ||
"--embed {embed_token} Y_DATASET --x X_DATASET " | ||
"--error ERROR_DATASET --fit FIT_DATASET"), | ||
("XY + Histogram", "{python} -m artiq.applets.plot_xy_hist " | ||
"--embed {embed_token} X_DATASET " | ||
"HIST_BIN_BOUNDARIES_DATASET " | ||
"HISTS_COUNTS_DATASET"), | ||
] | ||
|
||
|
||
class AppletsDock(dockarea.Dock): | ||
def __init__(self, manager): | ||
self.manager = manager | ||
self.token_to_checkbox = dict() | ||
|
||
dockarea.Dock.__init__(self, "Applets") | ||
self.setMinimumSize(QtCore.QSize(850, 450)) | ||
|
||
self.table = QtWidgets.QTableWidget(0, 3) | ||
self.table.setHorizontalHeaderLabels(["Enable", "Name", "Command"]) | ||
self.table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) | ||
self.table.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) | ||
self.table.horizontalHeader().setStretchLastSection(True) | ||
self.table.horizontalHeader().setResizeMode( | ||
QtGui.QHeaderView.ResizeToContents) | ||
self.table.verticalHeader().setResizeMode( | ||
QtGui.QHeaderView.ResizeToContents) | ||
self.table.verticalHeader().hide() | ||
self.table.setTextElideMode(QtCore.Qt.ElideNone) | ||
self.addWidget(self.table) | ||
|
||
self.table.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) | ||
new_action = QtGui.QAction("New applet", self.table) | ||
new_action.triggered.connect(self.new) | ||
self.table.addAction(new_action) | ||
templates_menu = QtGui.QMenu() | ||
for name, template in _templates: | ||
action = QtGui.QAction(name, self.table) | ||
action.triggered.connect(partial(self.new_template, template)) | ||
templates_menu.addAction(action) | ||
restart_action = QtGui.QAction("New applet from template", self.table) | ||
restart_action.setMenu(templates_menu) | ||
self.table.addAction(restart_action) | ||
restart_action = QtGui.QAction("Restart selected applet", self.table) | ||
restart_action.setShortcut("CTRL+R") | ||
restart_action.setShortcutContext(QtCore.Qt.WidgetShortcut) | ||
restart_action.triggered.connect(self.restart) | ||
self.table.addAction(restart_action) | ||
delete_action = QtGui.QAction("Delete selected applet", self.table) | ||
delete_action.setShortcut("DELETE") | ||
delete_action.setShortcutContext(QtCore.Qt.WidgetShortcut) | ||
delete_action.triggered.connect(self.delete) | ||
self.table.addAction(delete_action) | ||
|
||
self.table.cellChanged.connect(self.cell_changed) | ||
|
||
def cell_changed(self, row, column): | ||
if column == 0: | ||
item = self.table.item(row, column) | ||
if item.checkState() == QtCore.Qt.Checked: | ||
command = self.table.item(row, 2) | ||
if command: | ||
command = command.text() | ||
name = self.table.item(row, 1) | ||
if name is None: | ||
name = "" | ||
else: | ||
name = name.text() | ||
token = self.manager.create(name, command) | ||
item.applet_token = token | ||
self.token_to_checkbox[token] = item | ||
else: | ||
token = getattr(item, "applet_token", None) | ||
if token is not None: | ||
# cell_changed is emitted at row creation | ||
self.manager.delete(token) | ||
elif column == 1 or column == 2: | ||
new_value = self.table.item(row, column).text() | ||
token = getattr(self.table.item(row, 0), "applet_token", None) | ||
if token is not None: | ||
if column == 1: | ||
self.manager.rename(token, new_value) | ||
else: | ||
self.manager.set_command(token, new_value) | ||
|
||
def disable_token(self, token): | ||
checkbox_item = self.token_to_checkbox[token] | ||
checkbox_item.applet_token = None | ||
del self.token_to_checkbox[token] | ||
checkbox_item.setCheckState(QtCore.Qt.Unchecked) | ||
|
||
def new(self): | ||
row = self.table.rowCount() | ||
self.table.insertRow(row) | ||
checkbox = QtWidgets.QTableWidgetItem() | ||
checkbox.setFlags(QtCore.Qt.ItemIsSelectable | | ||
QtCore.Qt.ItemIsUserCheckable | | ||
QtCore.Qt.ItemIsEnabled) | ||
checkbox.setCheckState(QtCore.Qt.Unchecked) | ||
self.table.setItem(row, 0, checkbox) | ||
self.table.setItem(row, 1, QtWidgets.QTableWidgetItem()) | ||
self.table.setItem(row, 2, QtWidgets.QTableWidgetItem()) | ||
return row | ||
|
||
def new_template(self, template): | ||
row = self.new() | ||
self.table.item(row, 2).setText(template) | ||
|
||
def restart(self): | ||
selection = self.table.selectedRanges() | ||
if selection: | ||
row = selection[0].topRow() | ||
token = getattr(self.table.item(row, 0), "applet_token", None) | ||
if token is not None: | ||
asyncio.ensure_future(self.manager.restart(token)) | ||
|
||
def delete(self): | ||
selection = self.table.selectedRanges() | ||
if selection: | ||
row = selection[0].topRow() | ||
token = getattr(self.table.item(row, 0), "applet_token", None) | ||
if token is not None: | ||
self.manager.delete(token) | ||
self.table.removeRow(row) | ||
|
||
def save_state(self): | ||
state = [] | ||
for row in range(self.table.rowCount()): | ||
enabled = self.table.item(row, 0).checkState() == QtCore.Qt.Checked | ||
name = self.table.item(row, 1).text() | ||
command = self.table.item(row, 2).text() | ||
state.append((enabled, name, command)) | ||
return state | ||
|
||
def restore_state(self, state): | ||
for enabled, name, command in state: | ||
row = self.new() | ||
item = QtWidgets.QTableWidgetItem() | ||
item.setText(name) | ||
self.table.setItem(row, 1, item) | ||
item = QtWidgets.QTableWidgetItem() | ||
item.setText(command) | ||
self.table.setItem(row, 2, item) | ||
if enabled: | ||
self.table.item(row, 0).setCheckState(QtCore.Qt.Checked) | ||
|
||
|
||
class AppletManagerRPC: | ||
def __init__(self, parent): | ||
self.parent = parent | ||
|
||
def embed(self, token, win_id): | ||
self.parent.embed(token, win_id) | ||
|
||
|
||
class AppletManager: | ||
def __init__(self, dock_area): | ||
self.dock_area = dock_area | ||
self.main_dock = AppletsDock(self) | ||
self.rpc = AppletManagerRPC(self) | ||
self.applet_docks = dict() | ||
self.workaround_pyqtgraph_bug = False | ||
|
||
def embed(self, token, win_id): | ||
if token not in self.applet_docks: | ||
logger.warning("Ignored incorrect embed token %d for winid 0x%x", | ||
token, win_id) | ||
return | ||
self.applet_docks[token].capture(win_id) | ||
|
||
def create(self, name, command): | ||
token = next(iter(set(range(len(self.applet_docks) + 1)) | ||
- self.applet_docks.keys())) | ||
dock = AppletDock(token, name, command) | ||
self.applet_docks[token] = dock | ||
# If a dock is floated and then dock state is restored, pyqtgraph | ||
# leaves a "phantom" window open. | ||
if self.workaround_pyqtgraph_bug: | ||
self.dock_area.addDock(dock) | ||
else: | ||
self.dock_area.floatDock(dock) | ||
asyncio.ensure_future(dock.start()) | ||
dock.sigClosed.connect(partial(self.on_dock_closed, token)) | ||
return token | ||
|
||
def on_dock_closed(self, token): | ||
asyncio.ensure_future(self.applet_docks[token].terminate()) | ||
self.main_dock.disable_token(token) | ||
del self.applet_docks[token] | ||
|
||
def delete(self, token): | ||
# This in turns calls on_dock_closed and main_dock.disable_token | ||
self.applet_docks[token].close() | ||
|
||
def rename(self, token, name): | ||
self.applet_docks[token].rename(name) | ||
|
||
def set_command(self, token, command): | ||
self.applet_docks[token].command = command | ||
|
||
async def restart(self, token): | ||
await self.applet_docks[token].restart() | ||
|
||
async def stop(self): | ||
for dock in self.applet_docks.values(): | ||
await dock.terminate() | ||
|
||
def save_state(self): | ||
return self.main_dock.save_state() | ||
|
||
def restore_state(self, state): | ||
self.workaround_pyqtgraph_bug = True | ||
self.main_dock.restore_state(state) | ||
self.workaround_pyqtgraph_bug = False |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
from time import sleep | ||
|
||
import numpy as np | ||
|
||
from artiq import * | ||
|
||
|
||
class Histograms(EnvExperiment): | ||
"""Histograms demo""" | ||
def build(self): | ||
pass | ||
|
||
def run(self): | ||
nbins = 50 | ||
npoints = 20 | ||
|
||
bin_boundaries = np.linspace(-10, 30, nbins + 1) | ||
self.set_dataset("hd_bins", bin_boundaries, | ||
broadcast=True, save=False) | ||
|
||
xs = np.empty(npoints) | ||
xs.fill(np.nan) | ||
xs = self.set_dataset("hd_xs", xs, | ||
broadcast=True, save=False) | ||
|
||
counts = np.empty((npoints, nbins)) | ||
counts = self.set_dataset("hd_counts", counts, | ||
broadcast=True, save=False) | ||
|
||
for i in range(npoints): | ||
histogram, _ = np.histogram(np.random.normal(i, size=1000), | ||
bin_boundaries) | ||
counts[i] = histogram | ||
xs[i] = i % 8 | ||
sleep(0.3) |