Skip to content

Commit

Permalink
Merge branch 'master' into subprocess-termination
Browse files Browse the repository at this point in the history
* master: (44 commits)
  Revert "conda: restrict binutils-or1k-linux dependency to linux."
  manual/installing: refresh
  use https for m-labs.hk
  gui/log: top cell alignment
  master/log: do not break lines
  conda: fix pyqt package name
  gui/applets: log warning if IPC address not in command
  applets: make sure pyqtgraph imports qt5
  applets: avoid argparse subparser mess
  examples/histogram: artiq -> artiq.experiment
  gui/applets: save dock UID in state
  setup.py: give up trying to check for PyQt
  setup.py: fix PyQt5 package name
  Use Qt5
  applets: fix error message text
  applets: handle dataset mutations
  applets: properly name docks to support state save/restore
  applets: clean shutdown
  protocols/pyon: set support
  protocols/pyon: remove FlatFileDB
  ...
jordens committed Feb 11, 2016

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
2 parents 912274c + fcf7a6b commit 6434a9c
Showing 25 changed files with 898 additions and 550 deletions.
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
@@ -12,6 +12,6 @@ nanosecond timing resolution and sub-microsecond latency.
Technologies employed include Python, Migen, MiSoC/mor1kx, LLVM and llvmlite.

Website:
http://m-labs.hk/artiq
https://m-labs.hk/artiq

Copyright (C) 2014-2016 M-Labs Limited. Licensed under GNU GPL version 3.
4 changes: 2 additions & 2 deletions artiq/applets/big_number.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python3.5

from quamash import QtWidgets
from PyQt5 import QtWidgets

from artiq.applets.simple import SimpleApplet

@@ -11,7 +11,7 @@ def __init__(self, args):
self.setDigitCount(args.digit_count)
self.dataset_name = args.dataset

def data_changed(self, data, mod):
def data_changed(self, data, mods):
try:
n = float(data[self.dataset_name][1])
except (KeyError, ValueError, TypeError):
40 changes: 40 additions & 0 deletions artiq/applets/plot_hist.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env python3.5

import numpy as np
import PyQt5 # make sure pyqtgraph imports Qt5
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()
60 changes: 60 additions & 0 deletions artiq/applets/plot_xy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env python3.5

import numpy as np
import PyQt5 # make sure pyqtgraph imports Qt5
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()
143 changes: 105 additions & 38 deletions artiq/applets/plot_xy_hist.py
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 PyQt5 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()
Loading

0 comments on commit 6434a9c

Please sign in to comment.