diff --git a/plottr/data/datadict.py b/plottr/data/datadict.py index 01e6491b..845e3e5a 100644 --- a/plottr/data/datadict.py +++ b/plottr/data/datadict.py @@ -1010,7 +1010,10 @@ def validate(self) -> bool: shp = None shpsrc = '' - for n, v in self.data_items(): + + data_items = dict(self.data_items()) + + for n, v in data_items.items(): if type(v['values']) not in [np.ndarray, np.ma.core.MaskedArray]: self[n]['values'] = np.array(v['values']) @@ -1023,6 +1026,17 @@ def validate(self) -> bool: msg += f" {v['values'].shape}, " msg += f"and '{shpsrc}' has {shp}.\n" + if 'axes' in v: + for axis_num, na in enumerate(v['axes']): + # check that the data of the axes matches its use + # if data present + axis_data = data_items[na]['values'] + if axis_data.size > 0: + max_step_along_axes = np.max(np.abs(np.diff(data_items[na]['values'],axis=axis_num))) + if max_step_along_axes == 0: + msg += (f"Malformed data: {na} is expected to be {axis_num}th " + "axis but has no variation along that axis.\n") + if msg != '\n': raise ValueError(msg) @@ -1087,7 +1101,7 @@ def guess_shape_from_datadict(data: DataDict) -> \ def datadict_to_meshgrid(data: DataDict, target_shape: Union[Tuple[int, ...], None] = None, - inner_axis_order: Union[None, List[str]] = None, + inner_axis_order: Union[None, Sequence[str]] = None, use_existing_shape: bool = False) \ -> MeshgridDataDict: """ diff --git a/plottr/node/grid.py b/plottr/node/grid.py index 261cf9d8..88213aca 100644 --- a/plottr/node/grid.py +++ b/plottr/node/grid.py @@ -3,7 +3,6 @@ A node and widget for placing data onto a grid (or not). """ - from enum import Enum, unique from typing import Tuple, Dict, Any, List, Optional, Sequence, cast @@ -490,9 +489,19 @@ def process( inner_axis_order=order, ) elif method is GridOption.metadataShape: - dout = dd.datadict_to_meshgrid( - data, use_existing_shape=True - ) + try: + dout = dd.datadict_to_meshgrid( + data, use_existing_shape=True + ) + except ValueError as err: + if "Malformed data" in str(err): + self.node_logger.warning( + "Shape/Setpoint order does" + " not match data. Falling back to guessing shape" + ) + dout = dd.datadict_to_meshgrid(data) + else: + raise err except GriddingError: dout = data.expand() self.node_logger.info("data could not be gridded. Falling back " diff --git a/test/pytest/test_gridder.py b/test/pytest/test_gridder.py index 026c271f..e2a5dbae 100644 --- a/test/pytest/test_gridder.py +++ b/test/pytest/test_gridder.py @@ -93,12 +93,9 @@ def test_set_grid_with_order(qtbot): assert fc.outputValues()['dataOut']['vals']['axes'] == ['y', 'z', 'x'] # finally, specify manually. omitting inner shape doesn't work + # but will be caught by validation (and no data returned) node.grid = GridOption.specifyShape, dict(shape=(5, 2, 5)) - assert fc.outputValues()['dataOut'].data_vals('vals').shape == (5,2,5) - assert not num.arrays_equal( - fc.outputValues()['dataOut'].data_vals('vals'), - vv.transpose((1,2,0)), - ) + assert fc.outputValues()['dataOut'] is None # but using the right inner axis order should do it node.grid = GridOption.specifyShape, dict(order=['x', 'y', 'z'],