summaryrefslogtreecommitdiff
path: root/silx/gui/data/DataViews.py
diff options
context:
space:
mode:
Diffstat (limited to 'silx/gui/data/DataViews.py')
-rw-r--r--silx/gui/data/DataViews.py365
1 files changed, 288 insertions, 77 deletions
diff --git a/silx/gui/data/DataViews.py b/silx/gui/data/DataViews.py
index 1ad997b..ef69441 100644
--- a/silx/gui/data/DataViews.py
+++ b/silx/gui/data/DataViews.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -35,11 +35,13 @@ from silx.gui import qt, icons
from silx.gui.data.TextFormatter import TextFormatter
from silx.io import nxdata
from silx.gui.hdf5 import H5Node
-from silx.io.nxdata import NXdata, get_attr_as_string
+from silx.io.nxdata import get_attr_as_string
+from silx.gui.plot.Colormap import Colormap
+from silx.gui.plot.actions.control import ColormapAction
__authors__ = ["V. Valls", "P. Knobel"]
__license__ = "MIT"
-__date__ = "03/10/2017"
+__date__ = "23/01/2018"
_logger = logging.getLogger(__name__)
@@ -47,7 +49,9 @@ _logger = logging.getLogger(__name__)
# DataViewer modes
EMPTY_MODE = 0
PLOT1D_MODE = 10
-PLOT2D_MODE = 20
+IMAGE_MODE = 20
+PLOT2D_MODE = 21
+COMPLEX_IMAGE_MODE = 22
PLOT3D_MODE = 30
RAW_MODE = 40
RAW_ARRAY_MODE = 41
@@ -56,6 +60,13 @@ RAW_SCALAR_MODE = 43
RAW_HEXA_MODE = 44
STACK_MODE = 50
HDF5_MODE = 60
+NXDATA_MODE = 70
+NXDATA_INVALID_MODE = 71
+NXDATA_SCALAR_MODE = 72
+NXDATA_CURVE_MODE = 73
+NXDATA_XYVSCATTER_MODE = 74
+NXDATA_IMAGE_MODE = 75
+NXDATA_STACK_MODE = 76
def _normalizeData(data):
@@ -77,7 +88,7 @@ def _normalizeComplex(data):
absolute value.
Else returns the input data."""
if hasattr(data, "dtype"):
- isComplex = numpy.issubdtype(data.dtype, numpy.complex)
+ isComplex = numpy.issubdtype(data.dtype, numpy.complexfloating)
else:
isComplex = isinstance(data, numbers.Complex)
if isComplex:
@@ -97,7 +108,7 @@ class DataInfo(object):
self.isComplex = False
self.isBoolean = False
self.isRecord = False
- self.isNXdata = False
+ self.hasNXdata = False
self.shape = tuple()
self.dim = 0
self.size = 0
@@ -105,9 +116,10 @@ class DataInfo(object):
if data is None:
return
- if silx.io.is_group(data) and nxdata.is_valid_nxdata(data):
- self.isNXdata = True
- nxd = nxdata.NXdata(data)
+ if silx.io.is_group(data):
+ nxd = nxdata.get_default(data)
+ if nxd is not None:
+ self.hasNXdata = True
if isinstance(data, numpy.ndarray):
self.isArray = True
@@ -121,7 +133,7 @@ class DataInfo(object):
self.interpretation = get_attr_as_string(data, "interpretation")
else:
self.interpretation = None
- elif self.isNXdata:
+ elif self.hasNXdata:
self.interpretation = nxd.interpretation
else:
self.interpretation = None
@@ -132,12 +144,12 @@ class DataInfo(object):
self.isVoid = data.dtype.fields is None
self.isNumeric = numpy.issubdtype(data.dtype, numpy.number)
self.isRecord = data.dtype.fields is not None
- self.isComplex = numpy.issubdtype(data.dtype, numpy.complex)
+ self.isComplex = numpy.issubdtype(data.dtype, numpy.complexfloating)
self.isBoolean = numpy.issubdtype(data.dtype, numpy.bool_)
- elif self.isNXdata:
+ elif self.hasNXdata:
self.isNumeric = numpy.issubdtype(nxd.signal.dtype,
numpy.number)
- self.isComplex = numpy.issubdtype(nxd.signal.dtype, numpy.complex)
+ self.isComplex = numpy.issubdtype(nxd.signal.dtype, numpy.complexfloating)
self.isBoolean = numpy.issubdtype(nxd.signal.dtype, numpy.bool_)
else:
self.isNumeric = isinstance(data, numbers.Number)
@@ -147,7 +159,7 @@ class DataInfo(object):
if hasattr(data, "shape"):
self.shape = data.shape
- elif self.isNXdata:
+ elif self.hasNXdata:
self.shape = nxd.signal.shape
else:
self.shape = tuple()
@@ -172,6 +184,12 @@ class DataView(object):
"""Priority returned when the requested data can't be displayed by the
view."""
+ _defaultColormap = None
+ """Store a default colormap shared with all the views"""
+
+ _defaultColorDialog = None
+ """Store a default color dialog shared with all the views"""
+
def __init__(self, parent, modeId=None, icon=None, label=None):
"""Constructor
@@ -187,6 +205,32 @@ class DataView(object):
icon = qt.QIcon()
self.__icon = icon
+ @staticmethod
+ def defaultColormap():
+ """Returns a shared colormap as default for all the views.
+
+ :rtype: Colormap
+ """
+ if DataView._defaultColormap is None:
+ DataView._defaultColormap = Colormap(name="viridis")
+ return DataView._defaultColormap
+
+ @staticmethod
+ def defaultColorDialog():
+ """Returns a shared color dialog as default for all the views.
+
+ :rtype: ColorDialog
+ """
+ if DataView._defaultColorDialog is None:
+ DataView._defaultColorDialog = ColormapAction._createDialog(qt.QApplication.instance().activeWindow())
+ return DataView._defaultColorDialog
+
+ @staticmethod
+ def _cleanUpCache():
+ """Clean up the cache. Needed for tests"""
+ DataView._defaultColormap = None
+ DataView._defaultColorDialog = None
+
def icon(self):
"""Returns the default icon"""
return self.__icon
@@ -305,6 +349,13 @@ class CompositeDataView(DataView):
"""Add a new dataview to the available list."""
self.__views[dataView] = None
+ def availableViews(self):
+ """Returns the list of registered views
+
+ :rtype: List[DataView]
+ """
+ return list(self.__views.keys())
+
def getBestView(self, data, info):
"""Returns the best view according to priorities."""
views = [(v.getDataPriority(data, info), v) for v in self.__views.keys()]
@@ -374,6 +425,38 @@ class CompositeDataView(DataView):
else:
return view.getDataPriority(data, info)
+ def replaceView(self, modeId, newView):
+ """Replace a data view with a custom view.
+ Return True in case of success, False in case of failure.
+
+ .. note::
+
+ This method must be called just after instantiation, before
+ the viewer is used.
+
+ :param int modeId: Unique mode ID identifying the DataView to
+ be replaced.
+ :param DataViews.DataView newView: New data view
+ :return: True if replacement was successful, else False
+ """
+ oldView = None
+ for view in self.__views:
+ if view.modeId() == modeId:
+ oldView = view
+ break
+ elif isinstance(view, CompositeDataView):
+ # recurse
+ if view.replaceView(modeId, newView):
+ return True
+ if oldView is None:
+ return False
+
+ # replace oldView with new view in dict
+ self.__views = OrderedDict(
+ (newView, None) if view is oldView else (view, idx) for
+ view, idx in self.__views.items())
+ return True
+
class _EmptyView(DataView):
"""Dummy view to display nothing"""
@@ -457,6 +540,8 @@ class _Plot2dView(DataView):
def createWidget(self, parent):
from silx.gui import plot
widget = plot.Plot2D(parent=parent)
+ widget.setDefaultColormap(self.defaultColormap())
+ widget.getColormapAction().setColorDialog(self.defaultColorDialog())
widget.getIntensityHistogramAction().setVisible(True)
widget.setKeepDataAspectRatio(True)
widget.getXAxis().setLabel('X')
@@ -582,13 +667,18 @@ class _ComplexImageView(DataView):
def __init__(self, parent):
super(_ComplexImageView, self).__init__(
parent=parent,
- modeId=PLOT2D_MODE,
+ modeId=COMPLEX_IMAGE_MODE,
label="Complex Image",
icon=icons.getQIcon("view-2d"))
def createWidget(self, parent):
from silx.gui.plot.ComplexImageView import ComplexImageView
widget = ComplexImageView(parent=parent)
+ widget.setColormap(self.defaultColormap(), mode=ComplexImageView.Mode.ABSOLUTE)
+ widget.setColormap(self.defaultColormap(), mode=ComplexImageView.Mode.SQUARE_AMPLITUDE)
+ widget.setColormap(self.defaultColormap(), mode=ComplexImageView.Mode.REAL)
+ widget.setColormap(self.defaultColormap(), mode=ComplexImageView.Mode.IMAGINARY)
+ widget.getPlot().getColormapAction().setColorDialog(self.defaultColorDialog())
widget.getPlot().getIntensityHistogramAction().setVisible(True)
widget.getPlot().setKeepDataAspectRatio(True)
widget.getXAxis().setLabel('X')
@@ -681,6 +771,8 @@ class _StackView(DataView):
def createWidget(self, parent):
from silx.gui import plot
widget = plot.StackView(parent=parent)
+ widget.setColormap(self.defaultColormap())
+ widget.getPlot().getColormapAction().setColorDialog(self.defaultColorDialog())
widget.setKeepDataAspectRatio(True)
widget.setLabels(self.axesNames(None, None))
# hide default option panel
@@ -699,6 +791,8 @@ class _StackView(DataView):
def setData(self, data):
data = self.normalizeData(data)
self.getWidget().setStack(stack=data, reset=self.__resetZoomNextTime)
+ # Override the colormap, while setStack overwrite it
+ self.getWidget().setColormap(self.defaultColormap())
self.__resetZoomNextTime = False
def axesNames(self, data, info):
@@ -736,7 +830,11 @@ class _ScalarView(DataView):
d = self.normalizeData(data)
if silx.io.is_dataset(d):
d = d[()]
- text = self.__formatter.toString(d, data.dtype)
+ dtype = None
+ if data is not None:
+ if hasattr(data, "dtype"):
+ dtype = data.dtype
+ text = self.__formatter.toString(d, dtype)
self.getWidget().setText(text)
def axesNames(self, data, info):
@@ -891,18 +989,111 @@ class _ImageView(CompositeDataView):
def __init__(self, parent):
super(_ImageView, self).__init__(
parent=parent,
- modeId=PLOT2D_MODE,
+ modeId=IMAGE_MODE,
label="Image",
icon=icons.getQIcon("view-2d"))
self.addView(_ComplexImageView(parent))
self.addView(_Plot2dView(parent))
+class _InvalidNXdataView(DataView):
+ """DataView showing a simple label with an error message
+ to inform that a group with @NX_class=NXdata cannot be
+ interpreted by any NXDataview."""
+ def __init__(self, parent):
+ DataView.__init__(self, parent,
+ modeId=NXDATA_INVALID_MODE)
+ self._msg = ""
+
+ def createWidget(self, parent):
+ widget = qt.QLabel(parent)
+ widget.setWordWrap(True)
+ widget.setStyleSheet("QLabel { color : red; }")
+ return widget
+
+ def axesNames(self, data, info):
+ return []
+
+ def clear(self):
+ self.getWidget().setText("")
+
+ def setData(self, data):
+ self.getWidget().setText(self._msg)
+
+ def getDataPriority(self, data, info):
+ data = self.normalizeData(data)
+ if silx.io.is_group(data):
+ nxd = nxdata.get_default(data)
+ nx_class = get_attr_as_string(data, "NX_class")
+
+ if nxd is None:
+ if nx_class == "NXdata":
+ # invalid: could not even be parsed by NXdata
+ self._msg = "Group has @NX_class = NXdata, but could not be interpreted"
+ self._msg += " as valid NXdata."
+ return 100
+ elif nx_class == "NXentry":
+ if "default" not in data.attrs:
+ # no link to NXdata, no problem
+ return DataView.UNSUPPORTED
+ self._msg = "NXentry group provides a @default attribute,"
+ default_nxdata_name = data.attrs["default"]
+ if default_nxdata_name not in data:
+ self._msg += " but no corresponding NXdata group exists."
+ elif get_attr_as_string(data[default_nxdata_name], "NX_class") != "NXdata":
+ self._msg += " but the corresponding item is not a "
+ self._msg += "NXdata group."
+ else:
+ self._msg += " but the corresponding NXdata seems to be"
+ self._msg += " malformed."
+ return 100
+ elif nx_class == "NXroot" or silx.io.is_file(data):
+ if "default" not in data.attrs:
+ # no link to NXentry, no problem
+ return DataView.UNSUPPORTED
+ default_entry_name = data.attrs["default"]
+ if default_entry_name not in data:
+ # this is a problem, but not NXdata related
+ return DataView.UNSUPPORTED
+ default_entry = data[default_entry_name]
+ if "default" not in default_entry.attrs:
+ # no NXdata specified, no problemo
+ return DataView.UNSUPPORTED
+ default_nxdata_name = default_entry.attrs["default"]
+ self._msg = "NXroot group provides a @default attribute "
+ self._msg += "pointing to a NXentry which defines its own "
+ self._msg += "@default attribute, "
+ if default_nxdata_name not in default_entry:
+ self._msg += " but no corresponding NXdata group exists."
+ elif get_attr_as_string(default_entry[default_nxdata_name],
+ "NX_class") != "NXdata":
+ self._msg += " but the corresponding item is not a "
+ self._msg += "NXdata group."
+ else:
+ self._msg += " but the corresponding NXdata seems to be"
+ self._msg += " malformed."
+ return 100
+ else:
+ # Not pretending to be NXdata, no problem
+ return DataView.UNSUPPORTED
+
+ is_scalar = nxd.signal_is_0d or nxd.interpretation in ["scalar", "scaler"]
+ if not (is_scalar or nxd.is_curve or nxd.is_x_y_value_scatter or
+ nxd.is_image or nxd.is_stack):
+ # invalid: cannot be plotted by any widget (I cannot imagine a case)
+ self._msg = "NXdata seems valid, but cannot be displayed "
+ self._msg += "by any existing plot widget."
+ return 100
+
+ return DataView.UNSUPPORTED
+
+
class _NXdataScalarView(DataView):
"""DataView using a table view for displaying NXdata scalars:
0-D signal or n-D signal with *@interpretation=scalar*"""
def __init__(self, parent):
- DataView.__init__(self, parent)
+ DataView.__init__(self, parent,
+ modeId=NXDATA_SCALAR_MODE)
def createWidget(self, parent):
from silx.gui.data.ArrayTableWidget import ArrayTableWidget
@@ -919,14 +1110,17 @@ class _NXdataScalarView(DataView):
def setData(self, data):
data = self.normalizeData(data)
- signal = NXdata(data).signal
+ # data could be a NXdata or an NXentry
+ nxd = nxdata.get_default(data)
+ signal = nxd.signal
self.getWidget().setArrayData(signal,
labels=True)
def getDataPriority(self, data, info):
data = self.normalizeData(data)
- if info.isNXdata:
- nxd = NXdata(data)
+
+ if info.hasNXdata:
+ nxd = nxdata.get_default(data)
if nxd.signal_is_0d or nxd.interpretation in ["scalar", "scaler"]:
return 100
return DataView.UNSUPPORTED
@@ -940,7 +1134,8 @@ class _NXdataCurveView(DataView):
a 1-D signal with one axis whose values are not monotonically increasing.
"""
def __init__(self, parent):
- DataView.__init__(self, parent)
+ DataView.__init__(self, parent,
+ modeId=NXDATA_CURVE_MODE)
def createWidget(self, parent):
from silx.gui.data.NXdataWidgets import ArrayCurvePlot
@@ -956,29 +1151,34 @@ class _NXdataCurveView(DataView):
def setData(self, data):
data = self.normalizeData(data)
- nxd = NXdata(data)
- signal_name = get_attr_as_string(data, "signal")
- group_name = data.name
+ nxd = nxdata.get_default(data)
+ signals_names = [nxd.signal_name] + nxd.auxiliary_signals_names
if nxd.axes_dataset_names[-1] is not None:
x_errors = nxd.get_axis_errors(nxd.axes_dataset_names[-1])
else:
x_errors = None
- self.getWidget().setCurveData(nxd.signal, nxd.axes[-1],
- yerror=nxd.errors, xerror=x_errors,
- ylabel=signal_name, xlabel=nxd.axes_names[-1],
- title="NXdata group " + group_name)
+ # this fix is necessary until the next release of PyMca (5.2.3 or 5.3.0)
+ # see https://github.com/vasole/pymca/issues/144 and https://github.com/vasole/pymca/pull/145
+ if not hasattr(self.getWidget(), "setCurvesData") and \
+ hasattr(self.getWidget(), "setCurveData"):
+ _logger.warning("Using deprecated ArrayCurvePlot API, "
+ "without support of auxiliary signals")
+ self.getWidget().setCurveData(nxd.signal, nxd.axes[-1],
+ yerror=nxd.errors, xerror=x_errors,
+ ylabel=nxd.signal_name, xlabel=nxd.axes_names[-1],
+ title=nxd.title or nxd.signal_name)
+ return
+
+ self.getWidget().setCurvesData([nxd.signal] + nxd.auxiliary_signals, nxd.axes[-1],
+ yerror=nxd.errors, xerror=x_errors,
+ ylabels=signals_names, xlabel=nxd.axes_names[-1],
+ title=nxd.title or signals_names[0])
def getDataPriority(self, data, info):
data = self.normalizeData(data)
- if info.isNXdata:
- nxd = NXdata(data)
- if nxd.is_x_y_value_scatter or nxd.is_unsupported_scatter:
- return DataView.UNSUPPORTED
- if nxd.signal_is_1d and \
- not nxd.interpretation in ["scalar", "scaler"]:
- return 100
- if nxd.interpretation == "spectrum":
+ if info.hasNXdata:
+ if nxdata.get_default(data).is_curve:
return 100
return DataView.UNSUPPORTED
@@ -987,11 +1187,12 @@ class _NXdataXYVScatterView(DataView):
"""DataView using a Plot1D for displaying NXdata 3D scatters as
a scatter of coloured points (1-D signal with 2 axes)"""
def __init__(self, parent):
- DataView.__init__(self, parent)
+ DataView.__init__(self, parent,
+ modeId=NXDATA_XYVSCATTER_MODE)
def createWidget(self, parent):
- from silx.gui.data.NXdataWidgets import ArrayCurvePlot
- widget = ArrayCurvePlot(parent)
+ from silx.gui.data.NXdataWidgets import XYVScatterPlot
+ widget = XYVScatterPlot(parent)
return widget
def axesNames(self, data, info):
@@ -1003,10 +1204,7 @@ class _NXdataXYVScatterView(DataView):
def setData(self, data):
data = self.normalizeData(data)
- nxd = NXdata(data)
- signal_name = get_attr_as_string(data, "signal")
- # signal_errors = nx.errors # not supported
- group_name = data.name
+ nxd = nxdata.get_default(data)
x_axis, y_axis = nxd.axes[-2:]
x_label, y_label = nxd.axes_names[-2:]
@@ -1020,16 +1218,18 @@ class _NXdataXYVScatterView(DataView):
else:
y_errors = None
- self.getWidget().setCurveData(y_axis, x_axis, values=nxd.signal,
- yerror=y_errors, xerror=x_errors,
- ylabel=signal_name, xlabel=x_label,
- title="NXdata group " + group_name)
+ self.getWidget().setScattersData(y_axis, x_axis, values=[nxd.signal] + nxd.auxiliary_signals,
+ yerror=y_errors, xerror=x_errors,
+ ylabel=y_label, xlabel=x_label,
+ title=nxd.title,
+ scatter_titles=[nxd.signal_name] + nxd.auxiliary_signals_names)
def getDataPriority(self, data, info):
data = self.normalizeData(data)
- if info.isNXdata:
- if NXdata(data).is_x_y_value_scatter:
+ if info.hasNXdata:
+ if nxdata.get_default(data).is_x_y_value_scatter:
return 100
+
return DataView.UNSUPPORTED
@@ -1037,11 +1237,14 @@ class _NXdataImageView(DataView):
"""DataView using a Plot2D for displaying NXdata images:
2-D signal or n-D signals with *@interpretation=spectrum*."""
def __init__(self, parent):
- DataView.__init__(self, parent)
+ DataView.__init__(self, parent,
+ modeId=NXDATA_IMAGE_MODE)
def createWidget(self, parent):
from silx.gui.data.NXdataWidgets import ArrayImagePlot
widget = ArrayImagePlot(parent)
+ widget.getPlot().setDefaultColormap(self.defaultColormap())
+ widget.getPlot().getColormapAction().setColorDialog(self.defaultColorDialog())
return widget
def axesNames(self, data, info):
@@ -1053,36 +1256,41 @@ class _NXdataImageView(DataView):
def setData(self, data):
data = self.normalizeData(data)
- nxd = NXdata(data)
- signal_name = get_attr_as_string(data, "signal")
- group_name = data.name
- y_axis, x_axis = nxd.axes[-2:]
- y_label, x_label = nxd.axes_names[-2:]
+ nxd = nxdata.get_default(data)
+ isRgba = nxd.interpretation == "rgba-image"
+
+ # last two axes are Y & X
+ img_slicing = slice(-2, None) if not isRgba else slice(-3, -1)
+ y_axis, x_axis = nxd.axes[img_slicing]
+ y_label, x_label = nxd.axes_names[img_slicing]
self.getWidget().setImageData(
- nxd.signal, x_axis=x_axis, y_axis=y_axis,
- signal_name=signal_name, xlabel=x_label, ylabel=y_label,
- title="NXdata group %s: %s" % (group_name, signal_name))
+ [nxd.signal] + nxd.auxiliary_signals,
+ x_axis=x_axis, y_axis=y_axis,
+ signals_names=[nxd.signal_name] + nxd.auxiliary_signals_names,
+ xlabel=x_label, ylabel=y_label,
+ title=nxd.title, isRgba=isRgba)
def getDataPriority(self, data, info):
data = self.normalizeData(data)
- if info.isNXdata:
- nxd = NXdata(data)
- if nxd.signal_is_2d:
- if nxd.interpretation not in ["scalar", "spectrum", "scaler"]:
- return 100
- if nxd.interpretation == "image":
+
+ if info.hasNXdata:
+ if nxdata.get_default(data).is_image:
return 100
+
return DataView.UNSUPPORTED
class _NXdataStackView(DataView):
def __init__(self, parent):
- DataView.__init__(self, parent)
+ DataView.__init__(self, parent,
+ modeId=NXDATA_STACK_MODE)
def createWidget(self, parent):
from silx.gui.data.NXdataWidgets import ArrayStackPlot
widget = ArrayStackPlot(parent)
+ widget.getStackView().setColormap(self.defaultColormap())
+ widget.getStackView().getPlot().getColormapAction().setColorDialog(self.defaultColorDialog())
return widget
def axesNames(self, data, info):
@@ -1094,26 +1302,27 @@ class _NXdataStackView(DataView):
def setData(self, data):
data = self.normalizeData(data)
- nxd = NXdata(data)
- signal_name = get_attr_as_string(data, "signal")
- group_name = data.name
+ nxd = nxdata.get_default(data)
+ signal_name = nxd.signal_name
z_axis, y_axis, x_axis = nxd.axes[-3:]
z_label, y_label, x_label = nxd.axes_names[-3:]
+ title = nxd.title or signal_name
- self.getWidget().setStackData(
+ widget = self.getWidget()
+ widget.setStackData(
nxd.signal, x_axis=x_axis, y_axis=y_axis, z_axis=z_axis,
signal_name=signal_name,
xlabel=x_label, ylabel=y_label, zlabel=z_label,
- title="NXdata group %s: %s" % (group_name, signal_name))
+ title=title)
+ # Override the colormap, while setStack overwrite it
+ widget.getStackView().setColormap(self.defaultColormap())
def getDataPriority(self, data, info):
data = self.normalizeData(data)
- if info.isNXdata:
- nxd = NXdata(data)
- if nxd.signal_ndim >= 3:
- if nxd.interpretation not in ["scalar", "scaler",
- "spectrum", "image"]:
- return 100
+ if info.hasNXdata:
+ if nxdata.get_default(data).is_stack:
+ return 100
+
return DataView.UNSUPPORTED
@@ -1124,8 +1333,10 @@ class _NXdataView(CompositeDataView):
super(_NXdataView, self).__init__(
parent=parent,
label="NXdata",
+ modeId=NXDATA_MODE,
icon=icons.getQIcon("view-nexus"))
+ self.addView(_InvalidNXdataView(parent))
self.addView(_NXdataScalarView(parent))
self.addView(_NXdataCurveView(parent))
self.addView(_NXdataXYVScatterView(parent))