diff --git a/src/qcodes_loop/data/hdf5_format.py b/src/qcodes_loop/data/hdf5_format.py index 58be4fd3..814da1d3 100644 --- a/src/qcodes_loop/data/hdf5_format.py +++ b/src/qcodes_loop/data/hdf5_format.py @@ -285,7 +285,9 @@ def _create_dataarray_dset(self, array, group): name = array.array_id # Create the hdf5 dataset - dset = group.create_dataset(array.array_id, (0, 1), maxshape=(None, 1)) + dset = group.create_dataset( + array.array_id, (0, 1), maxshape=(None, 1), dtype="f4" + ) dset.attrs["label"] = _encode_to_utf8(str(label)) dset.attrs["name"] = _encode_to_utf8(str(name)) dset.attrs["unit"] = _encode_to_utf8(str(array.unit or "")) diff --git a/src/qcodes_loop/measure.py b/src/qcodes_loop/measure.py index 1c93e808..d9d27cb0 100644 --- a/src/qcodes_loop/measure.py +++ b/src/qcodes_loop/measure.py @@ -2,6 +2,7 @@ from datetime import datetime from typing import Optional +import numpy as np from qcodes.metadatable import Metadatable from qcodes.parameters import Parameter from qcodes.utils import full_class @@ -101,7 +102,9 @@ def run(self, use_threads=False, quiet=False, station=None, **kwargs): # The original return was an array, so take off the extra dim. # (This ensures the outer dim length was 1, otherwise this # will raise a ValueError.) - array.ndarray.shape = array.ndarray.shape[1:] + array.ndarray = np.reshape( + array.ndarray, array.ndarray.shape[1:], copy=False + ) # TODO: DataArray.shape masks ndarray.shape, and a user *could* # change it, thinking they were reshaping the underlying array, diff --git a/src/qcodes_loop/plots/qcmatplotlib.py b/src/qcodes_loop/plots/qcmatplotlib.py index 32c40f5b..dff36c4d 100644 --- a/src/qcodes_loop/plots/qcmatplotlib.py +++ b/src/qcodes_loop/plots/qcmatplotlib.py @@ -84,11 +84,21 @@ def __getitem__(self, key): def _init_plot(self, subplots=None, figsize=None, num=None): import matplotlib.pyplot as plt + # When reusing an existing figure window (e.g. via clear()), matplotlib + # ignores figure-level kwargs such as figsize and emits a warning. In + # that case we leave figsize out of the plt.subplots call and apply it + # to the figure directly afterwards. + reuse_figure = num is not None and plt.fignum_exists(num) + if isinstance(subplots, Mapping): if figsize is None: figsize = (6, 4) self.fig, self.subplots = plt.subplots( - figsize=figsize, num=num, squeeze=False, clear=True, **subplots + figsize=None if reuse_figure else figsize, + num=num, + squeeze=False, + clear=True, + **subplots, ) else: # Format subplots as tuple (nrows, ncols) @@ -106,9 +116,16 @@ def _init_plot(self, subplots=None, figsize=None, num=None): figsize = self.default_figsize(subplots) self.fig, self.subplots = plt.subplots( - *subplots, num=num, figsize=figsize, squeeze=False, clear=True + *subplots, + num=num, + figsize=None if reuse_figure else figsize, + squeeze=False, + clear=True, ) + if reuse_figure and figsize is not None: + self.fig.set_size_inches(figsize) + # squeeze=False ensures that subplots is always a 2D array independent # of the number of subplots. # However the qcodes api assumes that subplots is always a 1D array diff --git a/src/qcodes_loop/tests/test_plots.py b/src/qcodes_loop/tests/test_plots.py index afe2757a..83e86a68 100644 --- a/src/qcodes_loop/tests/test_plots.py +++ b/src/qcodes_loop/tests/test_plots.py @@ -37,6 +37,19 @@ def setUp(self): def tearDown(self): pass + @classmethod + def tearDownClass(cls): + # The remote pyqtgraph process spawns daemon threads that forward the + # child's stdout/stderr to sys.stdout/stderr. If the process is left + # running until interpreter shutdown, those threads can try to write to + # a stdout that pytest has already closed, raising + # "ValueError: I/O operation on closed file". Shut the process down here, + # while stdout is still valid. + if not noQtPlot and QtPlot.proc is not None: + QtPlot.proc.join() + QtPlot.proc = None + QtPlot.rpg = None + def test_creation(self): """ Simple test function which created a QtPlot window