class Hdf5NodeView(CloseEventNotifyingWidget.CloseEventNotifyingWidget): """QWidget displaying data as raw values in a table widget, or as a curve, image or stack in a plot widget. It can also display information related to HDF5 groups (attributes, compression, ...) and interpret a NXdata group to plot its data. The plot features depend on *silx*'s availability. """ def __init__(self, parent=None): CloseEventNotifyingWidget.CloseEventNotifyingWidget.__init__(self, parent) self.mainLayout = qt.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.setSpacing(0) self.viewWidget = DataViewerFrame(self) self.viewWidget.replaceView(DataViews.PLOT1D_MODE, Plot1DViewWithPlugins(self)) self.viewWidget.replaceView(DataViews.PLOT2D_MODE, Plot2DViewWithPlugins(self)) self.viewWidget.replaceView(DataViews.NXDATA_CURVE_MODE, NXdataCurveViewWithPlugins(self)) self.viewWidget.replaceView(DataViews.NXDATA_IMAGE_MODE, NXdataImageViewWithPlugins(self)) self.mainLayout.addWidget(self.viewWidget) def setData(self, dataset): self.viewWidget.setData(dataset)
def __init__(self, file_names=None): qt.QWidget.__init__(self) self.__treeview = silx.gui.hdf5.Hdf5TreeView(self) self.__text = qt.QTextEdit(self) self.__dataViewer = DataViewerFrame(self) vSplitter = qt.QSplitter(qt.Qt.Vertical) vSplitter.addWidget(self.__dataViewer) vSplitter.addWidget(self.__text) vSplitter.setSizes([10, 0]) splitter = qt.QSplitter(self) splitter.addWidget(self.__treeview) splitter.addWidget(vSplitter) splitter.setStretchFactor(1, 1) layout = qt.QVBoxLayout() layout.addWidget(splitter) layout.setStretchFactor(splitter, 1) self.setLayout(layout) # append all files to the tree if not file_names is None: for file_name in file_names: self.__treeview.findHdf5TreeModel().appendFile(file_name) self.__treeview.activated.connect(self.displayData)
def __init__(self, filenames=None): """ :param files_: List of HDF5 or Spec files (pathes or :class:`silx.io.spech5.SpecH5` or :class:`h5py.File` instances) """ qt.QMainWindow.__init__(self) self.setWindowTitle("Silx HDF5 widget example") self.__asyncload = False self.__treeview = silx.gui.hdf5.Hdf5TreeView(self) """Silx HDF5 TreeView""" self.__text = qt.QTextEdit(self) """Widget displaying information""" self.__dataViewer = DataViewerFrame(self) vSpliter = qt.QSplitter(qt.Qt.Vertical) vSpliter.addWidget(self.__dataViewer) vSpliter.addWidget(self.__text) vSpliter.setSizes([10, 0]) spliter = qt.QSplitter(self) spliter.addWidget(self.__treeview) spliter.addWidget(vSpliter) spliter.setStretchFactor(1, 1) main_panel = qt.QWidget(self) layout = qt.QVBoxLayout() layout.addWidget(spliter) layout.addWidget( self.createTreeViewConfigurationPanel(self, self.__treeview)) layout.setStretchFactor(spliter, 1) main_panel.setLayout(layout) self.setCentralWidget(main_panel) # append all files to the tree for file_name in filenames: self.__treeview.findHdf5TreeModel().appendFile(file_name) self.__treeview.activated.connect(self.displayData) self.__treeview.activated.connect( lambda index: self.displayEvent("activated", index)) self.__treeview.clicked.connect( lambda index: self.displayEvent("clicked", index)) self.__treeview.doubleClicked.connect( lambda index: self.displayEvent("doubleClicked", index)) self.__treeview.entered.connect( lambda index: self.displayEvent("entered", index)) self.__treeview.pressed.connect( lambda index: self.displayEvent("pressed", index)) self.__treeview.addContextMenuCallback(self.customContextMenu) # lambda function will never be called cause we store it as weakref self.__treeview.addContextMenuCallback(lambda event: None) # you have to store it first self.__store_lambda = lambda event: self.closeAndSyncCustomContextMenu( event) self.__treeview.addContextMenuCallback(self.__store_lambda)
class Hdf5TreeViewWidget(qt.QWidget): def __init__(self, file_names=None): qt.QWidget.__init__(self) self.__treeview = silx.gui.hdf5.Hdf5TreeView(self) self.__text = qt.QTextEdit(self) self.__dataViewer = DataViewerFrame(self) vSplitter = qt.QSplitter(qt.Qt.Vertical) vSplitter.addWidget(self.__dataViewer) vSplitter.addWidget(self.__text) vSplitter.setSizes([10, 0]) splitter = qt.QSplitter(self) splitter.addWidget(self.__treeview) splitter.addWidget(vSplitter) splitter.setStretchFactor(1, 1) layout = qt.QVBoxLayout() layout.addWidget(splitter) layout.setStretchFactor(splitter, 1) self.setLayout(layout) # append all files to the tree if not file_names is None: for file_name in file_names: self.__treeview.findHdf5TreeModel().appendFile(file_name) self.__treeview.activated.connect(self.displayData) def displayData(self): """Called to update the dataviewer with the selected data. """ selected = list(self.__treeview.selectedH5Nodes()) if len(selected) == 1: # Update the viewer for a single selection data = selected[0] self.__dataViewer.setData(data) def load_file(self, filename): self.__treeview.findHdf5TreeModel().insertFile(filename) def set_text(self, text): self.__text.setText(text) def __hdf5ComboChanged(self, index): function = self.__hdf5Combo.itemData(index) self.__createHdf5Button.setCallable(function) def __edfComboChanged(self, index): function = self.__edfCombo.itemData(index) self.__createEdfButton.setCallable(function)
def __init__(self): """ :param files_: List of HDF5 or Spec files (pathes or :class:`silx.io.spech5.SpecH5` or :class:`h5py.File` instances) """ # Import it here to be sure to use the right logging level import silx.gui.hdf5 from silx.gui.data.DataViewerFrame import DataViewerFrame qt.QMainWindow.__init__(self) self.setWindowTitle("Silx viewer") self.__asyncload = False self.__dialogState = None self.__treeview = silx.gui.hdf5.Hdf5TreeView(self) """Silx HDF5 TreeView""" self.__dataViewer = DataViewerFrame(self) vSpliter = qt.QSplitter(qt.Qt.Vertical) vSpliter.addWidget(self.__dataViewer) vSpliter.setSizes([10, 0]) spliter = qt.QSplitter(self) spliter.addWidget(self.__treeview) spliter.addWidget(vSpliter) spliter.setStretchFactor(1, 1) main_panel = qt.QWidget(self) layout = qt.QVBoxLayout() layout.addWidget(spliter) layout.setStretchFactor(spliter, 1) main_panel.setLayout(layout) self.setCentralWidget(main_panel) model = self.__treeview.selectionModel() model.selectionChanged.connect(self.displayData) self.__treeview.addContextMenuCallback( self.closeAndSyncCustomContextMenu) treeModel = self.__treeview.findHdf5TreeModel() columns = list(treeModel.COLUMN_IDS) columns.remove(treeModel.DESCRIPTION_COLUMN) columns.remove(treeModel.NODE_COLUMN) self.__treeview.header().setSections(columns) self.createActions() self.createMenus()
def __init__(self, parent=None, context=None): qt.QWidget.__init__(self, parent=parent) self.__customNxdataItem = None self.__dataTitle = _HeaderLabel(self) self.__dataTitle.setVisible(False) self.__dataViewer = DataViewerFrame(self) self.__dataViewer.setGlobalHooks(context) layout = qt.QVBoxLayout(self) layout.setSpacing(0) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.__dataTitle) layout.addWidget(self.__dataViewer)
def __init__(self, filenames=None): """ :param files_: List of HDF5 or Spec files (pathes or :class:`silx.io.spech5.SpecH5` or :class:`h5py.File` instances) """ qt.QMainWindow.__init__(self) self.setWindowTitle("Silx HDF5 widget example") self.__asyncload = False self.__treeview = silx.gui.hdf5.Hdf5TreeView(self) """Silx HDF5 TreeView""" self.__sourceModel = self.__treeview.model() """Store the source model""" self.__text = qt.QTextEdit(self) """Widget displaying information""" self.__dataViewer = DataViewerFrame(self) vSpliter = qt.QSplitter(qt.Qt.Vertical) vSpliter.addWidget(self.__dataViewer) vSpliter.addWidget(self.__text) vSpliter.setSizes([10, 0]) spliter = qt.QSplitter(self) spliter.addWidget(self.__treeview) spliter.addWidget(vSpliter) spliter.setStretchFactor(1, 1) main_panel = qt.QWidget(self) layout = qt.QVBoxLayout() layout.addWidget(spliter) layout.addWidget( self.createTreeViewConfigurationPanel(self, self.__treeview)) layout.setStretchFactor(spliter, 1) main_panel.setLayout(layout) self.setCentralWidget(main_panel) # append all files to the tree for file_name in filenames: self.__treeview.findHdf5TreeModel().appendFile(file_name) self.__treeview.activated.connect(self.displayData)
def __init__(self, parent=None): CloseEventNotifyingWidget.CloseEventNotifyingWidget.__init__(self, parent) self.mainLayout = qt.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.setSpacing(0) self.viewWidget = DataViewerFrame(self) self.viewWidget.replaceView(DataViews.PLOT1D_MODE, Plot1DViewWithPlugins(self)) self.viewWidget.replaceView(DataViews.PLOT2D_MODE, Plot2DViewWithPlugins(self)) self.viewWidget.replaceView(DataViews.NXDATA_CURVE_MODE, NXdataCurveViewWithPlugins(self)) self.viewWidget.replaceView(DataViews.NXDATA_IMAGE_MODE, NXdataImageViewWithPlugins(self)) self.mainLayout.addWidget(self.viewWidget)
def main(): app = qt.QApplication([]) widget = DataViewerFrame() widget.addView(MyColorView(widget)) widget.setData(Color.GREEN) widget.show() result = app.exec() # remove ending warnings relative to QTimer app.deleteLater() sys.exit(result)
def __init__(self, filenames=None): """ :param files_: List of HDF5 or Spec files (pathes or :class:`silx.io.spech5.SpecH5` or :class:`h5py.File` instances) """ qt.QMainWindow.__init__(self) self.setWindowTitle("Silx HDF5 widget example") self.__asyncload = False self.__treeview = silx.gui.hdf5.Hdf5TreeView(self) """Silx HDF5 TreeView""" self.__text = qt.QTextEdit(self) """Widget displaying information""" self.__dataViewer = DataViewerFrame(self) vSpliter = qt.QSplitter(qt.Qt.Vertical) vSpliter.addWidget(self.__dataViewer) vSpliter.addWidget(self.__text) vSpliter.setSizes([10, 0]) spliter = qt.QSplitter(self) spliter.addWidget(self.__treeview) spliter.addWidget(vSpliter) spliter.setStretchFactor(1, 1) main_panel = qt.QWidget(self) layout = qt.QVBoxLayout() layout.addWidget(spliter) layout.addWidget(self.createTreeViewConfigurationPanel(self, self.__treeview)) layout.setStretchFactor(spliter, 1) main_panel.setLayout(layout) self.setCentralWidget(main_panel) # append all files to the tree for file_name in filenames: self.__treeview.findHdf5TreeModel().appendFile(file_name) self.__treeview.activated.connect(self.displayData) self.__treeview.activated.connect(lambda index: self.displayEvent("activated", index)) self.__treeview.clicked.connect(lambda index: self.displayEvent("clicked", index)) self.__treeview.doubleClicked.connect(lambda index: self.displayEvent("doubleClicked", index)) self.__treeview.entered.connect(lambda index: self.displayEvent("entered", index)) self.__treeview.pressed.connect(lambda index: self.displayEvent("pressed", index)) self.__treeview.addContextMenuCallback(self.customContextMenu) # lambda function will never be called cause we store it as weakref self.__treeview.addContextMenuCallback(lambda event: None) # you have to store it first self.__store_lambda = lambda event: self.closeAndSyncCustomContextMenu(event) self.__treeview.addContextMenuCallback(self.__store_lambda)
def main(): app = qt.QApplication([]) widget = DataViewerFrame() widget.addView(MyColorView(widget)) widget.setData(Color.GREEN) widget.show() result = app.exec_() # remove ending warnings relative to QTimer app.deleteLater() sys.exit(result)
def __init__(self, file_name=None): qt.QWidget.__init__(self) self.__treeview = silx.gui.hdf5.Hdf5TreeView(self) self.__text = qt.QTextEdit(self) self.__dataViewer = DataViewerFrame(self) box = oasysgui.widgetBox(self, "", orientation="vertical") box.layout().addWidget(self.__dataViewer) self.box_scale = oasysgui.widgetBox(box, "", orientation="horizontal") gui.button(self.box_scale, self, "Apply Coordinates", callback=self.rescale) vSplitter = qt.QSplitter(qt.Qt.Vertical) vSplitter.addWidget(box) vSplitter.addWidget(self.__text) vSplitter.setSizes([10, 0]) splitter = qt.QSplitter(self) splitter.addWidget(self.__treeview) splitter.addWidget(vSplitter) splitter.setStretchFactor(1, 1) layout = qt.QVBoxLayout() layout.addWidget(splitter) layout.setStretchFactor(splitter, 1) self.setLayout(layout) # append all files to the tree if not file_name is None: self.__treeview.findHdf5TreeModel().removeRow(0) self.__treeview.findHdf5TreeModel().appendFile(file_name) self.__treeview.activated.connect(self.displayData)
def createDefaultViews(self, parent=None): views = list(DataViewerFrame.createDefaultViews(self, parent=parent)) # replace 1d view oldView = [v for v in views if v.modeId() == DataViews.PLOT1D_MODE][0] newView = Plot1DViewWithPlugins(parent=parent) views[views.index(oldView)] = newView # replace NXdataView oldView = [v for v in views if isinstance(v, DataViews._NXdataView)][0] newView = NXdataViewWithPlugins(parent=parent) views[views.index(oldView)] = newView return views
def __init__(self, parent=None): CloseEventNotifyingWidget.CloseEventNotifyingWidget.__init__( self, parent) self.mainLayout = qt.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.setSpacing(0) if silx.hexversion >= 0x000700f0: # 0.7.0 final self.viewWidget = DataViewerFrame(self) self.viewWidget.replaceView(DataViews.PLOT1D_MODE, Plot1DViewWithPlugins(self)) self.viewWidget.replaceView(DataViews.NXDATA_CURVE_MODE, NXdataCurveViewWithPlugins(self)) else: self.viewWidget = DataViewerFrameWithPlugins(self) self.mainLayout.addWidget(self.viewWidget)
def __init__(self, filenames=None): """ :param files_: List of HDF5 or Spec files (pathes or :class:`silx.io.spech5.SpecH5` or :class:`h5py.File` instances) """ qt.QMainWindow.__init__(self) self.setWindowTitle("Silx HDF5 widget example") self.__asyncload = False self.__treeview = silx.gui.hdf5.Hdf5TreeView(self) """Silx HDF5 TreeView""" self.__sourceModel = self.__treeview.model() """Store the source model""" self.__text = qt.QTextEdit(self) """Widget displaying information""" self.__dataViewer = DataViewerFrame(self) vSpliter = qt.QSplitter(qt.Qt.Vertical) vSpliter.addWidget(self.__dataViewer) vSpliter.addWidget(self.__text) vSpliter.setSizes([10, 0]) spliter = qt.QSplitter(self) spliter.addWidget(self.__treeview) spliter.addWidget(vSpliter) spliter.setStretchFactor(1, 1) main_panel = qt.QWidget(self) layout = qt.QVBoxLayout() layout.addWidget(spliter) layout.addWidget(self.createTreeViewConfigurationPanel(self, self.__treeview)) layout.setStretchFactor(spliter, 1) main_panel.setLayout(layout) self.setCentralWidget(main_panel) # append all files to the tree for file_name in filenames: self.__treeview.findHdf5TreeModel().appendFile(file_name) self.__treeview.activated.connect(self.displayData)
class Hdf5TreeViewExample(qt.QMainWindow): """ This window show an example of use of a Hdf5TreeView. The tree is initialized with a list of filenames. A panel allow to play with internal property configuration of the widget, and a text screen allow to display events. """ def __init__(self, filenames=None): """ :param files_: List of HDF5 or Spec files (pathes or :class:`silx.io.spech5.SpecH5` or :class:`h5py.File` instances) """ qt.QMainWindow.__init__(self) self.setWindowTitle("Silx HDF5 widget example") self.__asyncload = False self.__treeview = silx.gui.hdf5.Hdf5TreeView(self) """Silx HDF5 TreeView""" self.__sourceModel = self.__treeview.model() """Store the source model""" self.__text = qt.QTextEdit(self) """Widget displaying information""" self.__dataViewer = DataViewerFrame(self) vSpliter = qt.QSplitter(qt.Qt.Vertical) vSpliter.addWidget(self.__dataViewer) vSpliter.addWidget(self.__text) vSpliter.setSizes([10, 0]) spliter = qt.QSplitter(self) spliter.addWidget(self.__treeview) spliter.addWidget(vSpliter) spliter.setStretchFactor(1, 1) main_panel = qt.QWidget(self) layout = qt.QVBoxLayout() layout.addWidget(spliter) layout.addWidget(self.createTreeViewConfigurationPanel(self, self.__treeview)) layout.setStretchFactor(spliter, 1) main_panel.setLayout(layout) self.setCentralWidget(main_panel) # append all files to the tree for file_name in filenames: self.__treeview.findHdf5TreeModel().appendFile(file_name) self.__treeview.activated.connect(self.displayData) def displayData(self): """Called to update the dataviewer with the selected data. """ selected = list(self.__treeview.selectedH5Nodes()) if len(selected) == 1: # Update the viewer for a single selection data = selected[0] # data is a hdf5.H5Node object # data.h5py_object is a Group/Dataset object (from h5py, spech5, fabioh5) # The dataviewer can display both self.__dataViewer.setData(data) def __fileCreated(self, filename): if self.__asyncload: self.__treeview.findHdf5TreeModel().insertFileAsync(filename) else: self.__treeview.findHdf5TreeModel().insertFile(filename) def __hdf5ComboChanged(self, index): function = self.__hdf5Combo.itemData(index) self.__createHdf5Button.setCallable(function) def __edfComboChanged(self, index): function = self.__edfCombo.itemData(index) self.__createEdfButton.setCallable(function) def __useCustomLabel(self): customModel = CustomTooltips(self.__treeview) customModel.setSourceModel(self.__sourceModel) self.__treeview.setModel(customModel) def __useOriginalModel(self): self.__treeview.setModel(self.__sourceModel) def createTreeViewConfigurationPanel(self, parent, treeview): """Create a configuration panel to allow to play with widget states""" panel = qt.QWidget(parent) panel.setLayout(qt.QHBoxLayout()) content = qt.QGroupBox("Create HDF5", panel) content.setLayout(qt.QVBoxLayout()) panel.layout().addWidget(content) combo = qt.QComboBox() combo.addItem("Containing all types", get_hdf5_with_all_types) combo.activated.connect(self.__hdf5ComboChanged) content.layout().addWidget(combo) button = ThreadPoolPushButton(content, text="Create") button.setCallable(combo.itemData(combo.currentIndex())) button.succeeded.connect(self.__fileCreated) content.layout().addWidget(button) self.__hdf5Combo = combo self.__createHdf5Button = button content.layout().addStretch(1) option = qt.QGroupBox("Custom model", panel) option.setLayout(qt.QVBoxLayout()) panel.layout().addWidget(option) button = qt.QPushButton("Original model") button.clicked.connect(self.__useOriginalModel) option.layout().addWidget(button) button = qt.QPushButton("Custom tooltips by composition") button.clicked.connect(self.__useCustomLabel) option.layout().addWidget(button) option.layout().addStretch(1) panel.layout().addStretch(1) return panel
class Hdf5TreeViewWidget(qt.QWidget): x_scale = None y_scale = None def __init__(self, file_name=None): qt.QWidget.__init__(self) self.__treeview = silx.gui.hdf5.Hdf5TreeView(self) self.__text = qt.QTextEdit(self) self.__dataViewer = DataViewerFrame(self) box = oasysgui.widgetBox(self, "", orientation="vertical") box.layout().addWidget(self.__dataViewer) self.box_scale = oasysgui.widgetBox(box, "", orientation="horizontal") gui.button(self.box_scale, self, "Apply Coordinates", callback=self.rescale) vSplitter = qt.QSplitter(qt.Qt.Vertical) vSplitter.addWidget(box) vSplitter.addWidget(self.__text) vSplitter.setSizes([10, 0]) splitter = qt.QSplitter(self) splitter.addWidget(self.__treeview) splitter.addWidget(vSplitter) splitter.setStretchFactor(1, 1) layout = qt.QVBoxLayout() layout.addWidget(splitter) layout.setStretchFactor(splitter, 1) self.setLayout(layout) # append all files to the tree if not file_name is None: self.__treeview.findHdf5TreeModel().removeRow(0) self.__treeview.findHdf5TreeModel().appendFile(file_name) self.__treeview.activated.connect(self.displayData) def displayData(self): """Called to update the dataviewer with the selected data. """ selected = list(self.__treeview.selectedH5Nodes()) if len(selected) == 1: data = selected[0] self.__dataViewer.setData(data) self.is_histogram_v = "histogram_v" in data.h5py_object.name self.object_name = data.basename file = data.h5py_object.file try: self.x_scale = file["coordinates/X"].value self.x_label = file["coordinates"].attrs["x_label"] try: self.y_scale = file["coordinates/Y"].value self.y_label = file["coordinates"].attrs["y_label"] except: self.y_scale = None self.y_label = None self.box_scale.setVisible(True) except: self.box_scale.setVisible(False) def rescale(self): current_view = self.__dataViewer.displayedView() if isinstance(current_view, DataViews._Plot1dView): if self.is_histogram_v: min_x = numpy.min(self.y_scale) max_x = numpy.max(self.y_scale) scale = self.y_scale label = self.y_label else: min_x = numpy.min(self.x_scale) max_x = numpy.max(self.x_scale) scale = self.x_scale label = self.x_label widget = current_view.getWidget() if isinstance(widget, Plot1D): curve = widget.getAllCurves()[0] curve.setData(scale, curve.getYData()) widget.setGraphXLimits(min_x, max_x) widget.setGraphXLabel(label) widget.setGraphYLabel(self.object_name) elif isinstance(current_view, DataViews._ImageView): min_x = numpy.min(self.x_scale) max_x = numpy.max(self.x_scale) nbins_x = len(self.x_scale) min_y = numpy.min(self.y_scale) max_y = numpy.max(self.y_scale) nbins_y = len(self.y_scale) origin = (min_x, min_y) scale = (abs( (max_x - min_x) / nbins_x), abs((max_y - min_y) / nbins_y)) for view in current_view.availableViews(): widget = view.getWidget() if isinstance(widget, Plot2D): widget.getActiveImage().setOrigin(origin) widget.getActiveImage().setScale(scale) widget.setGraphXLimits(min_x, max_x) widget.setGraphYLimits(min_y, max_y) widget.setGraphXLabel(self.x_label) widget.setGraphYLabel(self.y_label) widget.setKeepDataAspectRatio(False) widget.resetZoom() def load_file(self, filename): self.__treeview.findHdf5TreeModel().insertFile(filename) def set_text(self, text): self.__text.setText(text) def __hdf5ComboChanged(self, index): function = self.__hdf5Combo.itemData(index) self.__createHdf5Button.setCallable(function) def __edfComboChanged(self, index): function = self.__edfCombo.itemData(index) self.__createEdfButton.setCallable(function)
class Hdf5TreeViewExample(qt.QMainWindow): """ This window show an example of use of a Hdf5TreeView. The tree is initialized with a list of filenames. A panel allow to play with internal property configuration of the widget, and a text screen allow to display events. """ def __init__(self, filenames=None): """ :param files_: List of HDF5 or Spec files (pathes or :class:`silx.io.spech5.SpecH5` or :class:`h5py.File` instances) """ qt.QMainWindow.__init__(self) self.setWindowTitle("Silx HDF5 widget example") self.__asyncload = False self.__treeview = silx.gui.hdf5.Hdf5TreeView(self) """Silx HDF5 TreeView""" self.__text = qt.QTextEdit(self) """Widget displaying information""" self.__dataViewer = DataViewerFrame(self) vSpliter = qt.QSplitter(qt.Qt.Vertical) vSpliter.addWidget(self.__dataViewer) vSpliter.addWidget(self.__text) vSpliter.setSizes([10, 0]) spliter = qt.QSplitter(self) spliter.addWidget(self.__treeview) spliter.addWidget(vSpliter) spliter.setStretchFactor(1, 1) main_panel = qt.QWidget(self) layout = qt.QVBoxLayout() layout.addWidget(spliter) layout.addWidget( self.createTreeViewConfigurationPanel(self, self.__treeview)) layout.setStretchFactor(spliter, 1) main_panel.setLayout(layout) self.setCentralWidget(main_panel) # append all files to the tree for file_name in filenames: self.__treeview.findHdf5TreeModel().appendFile(file_name) self.__treeview.activated.connect(self.displayData) self.__treeview.activated.connect( lambda index: self.displayEvent("activated", index)) self.__treeview.clicked.connect( lambda index: self.displayEvent("clicked", index)) self.__treeview.doubleClicked.connect( lambda index: self.displayEvent("doubleClicked", index)) self.__treeview.entered.connect( lambda index: self.displayEvent("entered", index)) self.__treeview.pressed.connect( lambda index: self.displayEvent("pressed", index)) self.__treeview.addContextMenuCallback(self.customContextMenu) # lambda function will never be called cause we store it as weakref self.__treeview.addContextMenuCallback(lambda event: None) # you have to store it first self.__store_lambda = lambda event: self.closeAndSyncCustomContextMenu( event) self.__treeview.addContextMenuCallback(self.__store_lambda) def displayData(self): """Called to update the dataviewer with the selected data. """ selected = list(self.__treeview.selectedH5Nodes()) if len(selected) == 1: # Update the viewer for a single selection data = selected[0] # data is a hdf5.H5Node object # data.h5py_object is a Group/Dataset object (from h5py, spech5, fabioh5) # The dataviewer can display both self.__dataViewer.setData(data) def displayEvent(self, eventName, index): """Called to log event in widget """ def formatKey(name, value): name, value = html.escape(str(name)), html.escape(str(value)) return "<li><b>%s</b>: %s</li>" % (name, value) text = "<html>" text += "<h1>Event</h1>" text += "<ul>" text += formatKey("name", eventName) text += formatKey("index", type(index)) text += "</ul>" text += "<h1>Selected HDF5 objects</h1>" for h5_obj in self.__treeview.selectedH5Nodes(): text += "<h2>HDF5 object</h2>" text += "<ul>" text += formatKey("local_filename", h5_obj.local_file.filename) text += formatKey("local_basename", h5_obj.local_basename) text += formatKey("local_name", h5_obj.local_name) text += formatKey("real_filename", h5_obj.file.filename) text += formatKey("real_basename", h5_obj.basename) text += formatKey("real_name", h5_obj.name) text += formatKey("obj", h5_obj.ntype) text += formatKey("dtype", getattr(h5_obj, "dtype", None)) text += formatKey("shape", getattr(h5_obj, "shape", None)) text += formatKey("attrs", getattr(h5_obj, "attrs", None)) if hasattr(h5_obj, "attrs"): text += "<ul>" if len(h5_obj.attrs) == 0: text += "<li>empty</li>" for key, value in h5_obj.attrs.items(): text += formatKey(key, value) text += "</ul>" text += "</ul>" text += "</html>" self.__text.setHtml(text) def useAsyncLoad(self, useAsync): self.__asyncload = useAsync def __fileCreated(self, filename): if self.__asyncload: self.__treeview.findHdf5TreeModel().insertFileAsync(filename) else: self.__treeview.findHdf5TreeModel().insertFile(filename) def customContextMenu(self, event): """Called to populate the context menu :param silx.gui.hdf5.Hdf5ContextMenuEvent event: Event containing expected information to populate the context menu """ selectedObjects = event.source().selectedH5Nodes() menu = event.menu() hasDataset = False for obj in selectedObjects: if obj.ntype is h5py.Dataset: hasDataset = True break if not menu.isEmpty(): menu.addSeparator() if hasDataset: action = qt.QAction("Do something on the datasets", event.source()) menu.addAction(action) def closeAndSyncCustomContextMenu(self, event): """Called to populate the context menu :param silx.gui.hdf5.Hdf5ContextMenuEvent event: Event containing expected information to populate the context menu """ selectedObjects = event.source().selectedH5Nodes() menu = event.menu() if not menu.isEmpty(): menu.addSeparator() for obj in selectedObjects: if obj.ntype is h5py.File: action = qt.QAction("Remove %s" % obj.local_filename, event.source()) action.triggered.connect( lambda: self.__treeview.findHdf5TreeModel( ).removeH5pyObject(obj.h5py_object)) menu.addAction(action) action = qt.QAction("Synchronize %s" % obj.local_filename, event.source()) action.triggered.connect( lambda: self.__treeview.findHdf5TreeModel( ).synchronizeH5pyObject(obj.h5py_object)) menu.addAction(action) def __hdf5ComboChanged(self, index): function = self.__hdf5Combo.itemData(index) self.__createHdf5Button.setCallable(function) def __edfComboChanged(self, index): function = self.__edfCombo.itemData(index) self.__createEdfButton.setCallable(function) def createTreeViewConfigurationPanel(self, parent, treeview): """Create a configuration panel to allow to play with widget states""" panel = qt.QWidget(parent) panel.setLayout(qt.QHBoxLayout()) content = qt.QGroupBox("Create HDF5", panel) content.setLayout(qt.QVBoxLayout()) panel.layout().addWidget(content) combo = qt.QComboBox() combo.addItem("Containing all types", get_hdf5_with_all_types) combo.addItem("Containing all links", get_hdf5_with_all_links) combo.addItem("Containing 1000 datasets", get_hdf5_with_1000_datasets) combo.addItem("Containing 10000 datasets", get_hdf5_with_10000_datasets) combo.addItem("Containing 100000 datasets", get_hdf5_with_100000_datasets) combo.addItem("Containing recursive links", get_hdf5_with_recursive_links) combo.addItem("Containing external recursive links", get_hdf5_with_external_recursive_links) combo.addItem("Containing NXdata groups", get_hdf5_with_nxdata) combo.activated.connect(self.__hdf5ComboChanged) content.layout().addWidget(combo) button = ThreadPoolPushButton(content, text="Create") button.setCallable(combo.itemData(combo.currentIndex())) button.succeeded.connect(self.__fileCreated) content.layout().addWidget(button) self.__hdf5Combo = combo self.__createHdf5Button = button asyncload = qt.QCheckBox("Async load", content) asyncload.setChecked(self.__asyncload) asyncload.toggled.connect( lambda: self.useAsyncLoad(asyncload.isChecked())) content.layout().addWidget(asyncload) content.layout().addStretch(1) content = qt.QGroupBox("Create EDF", panel) content.setLayout(qt.QVBoxLayout()) panel.layout().addWidget(content) combo = qt.QComboBox() combo.addItem("Containing all types", get_edf_with_all_types) combo.addItem("Containing 100000 datasets", get_edf_with_100000_frames) combo.activated.connect(self.__edfComboChanged) content.layout().addWidget(combo) button = ThreadPoolPushButton(content, text="Create") button.setCallable(combo.itemData(combo.currentIndex())) button.succeeded.connect(self.__fileCreated) content.layout().addWidget(button) self.__edfCombo = combo self.__createEdfButton = button content.layout().addStretch(1) option = qt.QGroupBox("Tree options", panel) option.setLayout(qt.QVBoxLayout()) panel.layout().addWidget(option) sorting = qt.QCheckBox("Enable sorting", option) sorting.setChecked( treeview.selectionMode() == qt.QAbstractItemView.MultiSelection) sorting.toggled.connect( lambda: treeview.setSortingEnabled(sorting.isChecked())) option.layout().addWidget(sorting) multiselection = qt.QCheckBox("Multi-selection", option) multiselection.setChecked( treeview.selectionMode() == qt.QAbstractItemView.MultiSelection) switch_selection = lambda: treeview.setSelectionMode( qt.QAbstractItemView.MultiSelection if multiselection.isChecked( ) else qt.QAbstractItemView.SingleSelection) multiselection.toggled.connect(switch_selection) option.layout().addWidget(multiselection) filedrop = qt.QCheckBox("Drop external file", option) filedrop.setChecked(treeview.findHdf5TreeModel().isFileDropEnabled()) filedrop.toggled.connect(lambda: treeview.findHdf5TreeModel(). setFileDropEnabled(filedrop.isChecked())) option.layout().addWidget(filedrop) filemove = qt.QCheckBox("Reorder files", option) filemove.setChecked(treeview.findHdf5TreeModel().isFileMoveEnabled()) filemove.toggled.connect(lambda: treeview.findHdf5TreeModel(). setFileMoveEnabled(filedrop.isChecked())) option.layout().addWidget(filemove) option.layout().addStretch(1) option = qt.QGroupBox("Header options", panel) option.setLayout(qt.QVBoxLayout()) panel.layout().addWidget(option) autosize = qt.QCheckBox("Auto-size headers", option) autosize.setChecked(treeview.header().hasAutoResizeColumns()) autosize.toggled.connect(lambda: treeview.header(). setAutoResizeColumns(autosize.isChecked())) option.layout().addWidget(autosize) columnpopup = qt.QCheckBox("Popup to hide/show columns", option) columnpopup.setChecked(treeview.header().hasHideColumnsPopup()) columnpopup.toggled.connect(lambda: treeview.header( ).setEnableHideColumnsPopup(columnpopup.isChecked())) option.layout().addWidget(columnpopup) define_columns = qt.QComboBox() define_columns.addItem("Default columns", treeview.findHdf5TreeModel().COLUMN_IDS) define_columns.addItem("Only name and Value", [ treeview.findHdf5TreeModel().NAME_COLUMN, treeview.findHdf5TreeModel().VALUE_COLUMN ]) define_columns.activated.connect(lambda index: treeview.header( ).setSections(define_columns.itemData(index))) option.layout().addWidget(define_columns) option.layout().addStretch(1) panel.layout().addStretch(1) return panel
class Viewer(qt.QMainWindow): """ This window allows to browse a data file like images or HDF5 and it's content. """ def __init__(self): """ :param files_: List of HDF5 or Spec files (pathes or :class:`silx.io.spech5.SpecH5` or :class:`h5py.File` instances) """ # Import it here to be sure to use the right logging level import silx.gui.hdf5 from silx.gui.data.DataViewerFrame import DataViewerFrame qt.QMainWindow.__init__(self) self.setWindowTitle("Silx viewer") self.__asyncload = False self.__dialogState = None self.__treeview = silx.gui.hdf5.Hdf5TreeView(self) """Silx HDF5 TreeView""" self.__dataViewer = DataViewerFrame(self) vSpliter = qt.QSplitter(qt.Qt.Vertical) vSpliter.addWidget(self.__dataViewer) vSpliter.setSizes([10, 0]) spliter = qt.QSplitter(self) spliter.addWidget(self.__treeview) spliter.addWidget(vSpliter) spliter.setStretchFactor(1, 1) main_panel = qt.QWidget(self) layout = qt.QVBoxLayout() layout.addWidget(spliter) layout.setStretchFactor(spliter, 1) main_panel.setLayout(layout) self.setCentralWidget(main_panel) model = self.__treeview.selectionModel() model.selectionChanged.connect(self.displayData) self.__treeview.addContextMenuCallback(self.closeAndSyncCustomContextMenu) treeModel = self.__treeview.findHdf5TreeModel() columns = list(treeModel.COLUMN_IDS) columns.remove(treeModel.DESCRIPTION_COLUMN) columns.remove(treeModel.NODE_COLUMN) self.__treeview.header().setSections(columns) self.createActions() self.createMenus() def createActions(self): action = qt.QAction("E&xit", self) action.setShortcuts(qt.QKeySequence.Quit) action.setStatusTip("Exit the application") action.triggered.connect(self.close) self._exitAction = action action = qt.QAction("&Open", self) action.setStatusTip("Open a file") action.triggered.connect(self.open) self._openAction = action action = qt.QAction("&About", self) action.setStatusTip("Show the application's About box") action.triggered.connect(self.about) self._aboutAction = action def createMenus(self): fileMenu = self.menuBar().addMenu("&File") fileMenu.addAction(self._openAction) fileMenu.addSeparator() fileMenu.addAction(self._exitAction) helpMenu = self.menuBar().addMenu("&Help") helpMenu.addAction(self._aboutAction) def open(self): dialog = self.createFileDialog() if self.__dialogState is None: currentDirectory = os.getcwd() dialog.setDirectory(currentDirectory) else: dialog.restoreState(self.__dialogState) result = dialog.exec_() if not result: return self.__dialogState = dialog.saveState() filenames = dialog.selectedFiles() for filename in filenames: self.appendFile(filename) def createFileDialog(self): dialog = qt.QFileDialog(self) dialog.setWindowTitle("Open") dialog.setModal(True) # NOTE: hdf5plugin have to be loaded before import silx.io extensions = collections.OrderedDict() for description, ext in silx.io.supported_extensions().items(): extensions[description] = " ".join(sorted(list(ext))) # NOTE: hdf5plugin have to be loaded before import fabio if fabio is not None: extensions["NeXus layout from EDF files"] = "*.edf" extensions["NeXus layout from TIFF image files"] = "*.tif *.tiff" extensions["NeXus layout from CBF files"] = "*.cbf" extensions["NeXus layout from MarCCD image files"] = "*.mccd" all_supported_extensions = set() for name, exts in extensions.items(): exts = exts.split(" ") all_supported_extensions.update(exts) all_supported_extensions = sorted(list(all_supported_extensions)) filters = [] filters.append("All supported files (%s)" % " ".join(all_supported_extensions)) for name, extension in extensions.items(): filters.append("%s (%s)" % (name, extension)) filters.append("All files (*)") dialog.setNameFilters(filters) dialog.setFileMode(qt.QFileDialog.ExistingFiles) return dialog def about(self): from . import qtutils qtutils.About.about(self, "Silx viewer") def appendFile(self, filename): self.__treeview.findHdf5TreeModel().appendFile(filename) def displayData(self): """Called to update the dataviewer with the selected data. """ selected = list(self.__treeview.selectedH5Nodes(ignoreBrokenLinks=False)) if len(selected) == 1: # Update the viewer for a single selection data = selected[0] self.__dataViewer.setData(data) def useAsyncLoad(self, useAsync): self.__asyncload = useAsync def closeAndSyncCustomContextMenu(self, event): """Called to populate the context menu :param silx.gui.hdf5.Hdf5ContextMenuEvent event: Event containing expected information to populate the context menu """ selectedObjects = event.source().selectedH5Nodes(ignoreBrokenLinks=False) menu = event.menu() if not menu.isEmpty(): menu.addSeparator() # Import it here to be sure to use the right logging level import h5py for obj in selectedObjects: if obj.ntype is h5py.File: action = qt.QAction("Remove %s" % obj.local_filename, event.source()) action.triggered.connect(lambda: self.__treeview.findHdf5TreeModel().removeH5pyObject(obj.h5py_object)) menu.addAction(action) action = qt.QAction("Synchronize %s" % obj.local_filename, event.source()) action.triggered.connect(lambda: self.__treeview.findHdf5TreeModel().synchronizeH5pyObject(obj.h5py_object)) menu.addAction(action)
def create_widget(self): return DataViewerFrame()
class Hdf5TreeViewExample(qt.QMainWindow): """ This window show an example of use of a Hdf5TreeView. The tree is initialized with a list of filenames. A panel allow to play with internal property configuration of the widget, and a text screen allow to display events. """ def __init__(self, filenames=None): """ :param files_: List of HDF5 or Spec files (pathes or :class:`silx.io.spech5.SpecH5` or :class:`h5py.File` instances) """ qt.QMainWindow.__init__(self) self.setWindowTitle("Silx HDF5 widget example") self.__asyncload = False self.__treeview = silx.gui.hdf5.Hdf5TreeView(self) """Silx HDF5 TreeView""" self.__sourceModel = self.__treeview.model() """Store the source model""" self.__text = qt.QTextEdit(self) """Widget displaying information""" self.__dataViewer = DataViewerFrame(self) vSpliter = qt.QSplitter(qt.Qt.Vertical) vSpliter.addWidget(self.__dataViewer) vSpliter.addWidget(self.__text) vSpliter.setSizes([10, 0]) spliter = qt.QSplitter(self) spliter.addWidget(self.__treeview) spliter.addWidget(vSpliter) spliter.setStretchFactor(1, 1) main_panel = qt.QWidget(self) layout = qt.QVBoxLayout() layout.addWidget(spliter) layout.addWidget( self.createTreeViewConfigurationPanel(self, self.__treeview)) layout.setStretchFactor(spliter, 1) main_panel.setLayout(layout) self.setCentralWidget(main_panel) # append all files to the tree for file_name in filenames: self.__treeview.findHdf5TreeModel().appendFile(file_name) self.__treeview.activated.connect(self.displayData) def displayData(self): """Called to update the dataviewer with the selected data. """ selected = list(self.__treeview.selectedH5Nodes()) if len(selected) == 1: # Update the viewer for a single selection data = selected[0] # data is a hdf5.H5Node object # data.h5py_object is a Group/Dataset object (from h5py, spech5, fabioh5) # The dataviewer can display both self.__dataViewer.setData(data) def __fileCreated(self, filename): if self.__asyncload: self.__treeview.findHdf5TreeModel().insertFileAsync(filename) else: self.__treeview.findHdf5TreeModel().insertFile(filename) def __hdf5ComboChanged(self, index): function = self.__hdf5Combo.itemData(index) self.__createHdf5Button.setCallable(function) def __edfComboChanged(self, index): function = self.__edfCombo.itemData(index) self.__createEdfButton.setCallable(function) def __useCustomLabel(self): customModel = CustomTooltips(self.__treeview) customModel.setSourceModel(self.__sourceModel) self.__treeview.setModel(customModel) def __useOriginalModel(self): self.__treeview.setModel(self.__sourceModel) def createTreeViewConfigurationPanel(self, parent, treeview): """Create a configuration panel to allow to play with widget states""" panel = qt.QWidget(parent) panel.setLayout(qt.QHBoxLayout()) content = qt.QGroupBox("Create HDF5", panel) content.setLayout(qt.QVBoxLayout()) panel.layout().addWidget(content) combo = qt.QComboBox() combo.addItem("Containing all types", get_hdf5_with_all_types) combo.activated.connect(self.__hdf5ComboChanged) content.layout().addWidget(combo) button = ThreadPoolPushButton(content, text="Create") button.setCallable(combo.itemData(combo.currentIndex())) button.succeeded.connect(self.__fileCreated) content.layout().addWidget(button) self.__hdf5Combo = combo self.__createHdf5Button = button content.layout().addStretch(1) option = qt.QGroupBox("Custom model", panel) option.setLayout(qt.QVBoxLayout()) panel.layout().addWidget(option) button = qt.QPushButton("Original model") button.clicked.connect(self.__useOriginalModel) option.layout().addWidget(button) button = qt.QPushButton("Custom tooltips by composition") button.clicked.connect(self.__useCustomLabel) option.layout().addWidget(button) option.layout().addStretch(1) panel.layout().addStretch(1) return panel
class Viewer(qt.QMainWindow): """ This window allows to browse a data file like images or HDF5 and it's content. """ def __init__(self): """ :param files_: List of HDF5 or Spec files (pathes or :class:`silx.io.spech5.SpecH5` or :class:`h5py.File` instances) """ # Import it here to be sure to use the right logging level import silx.gui.hdf5 from silx.gui.data.DataViewerFrame import DataViewerFrame qt.QMainWindow.__init__(self) self.setWindowTitle("Silx viewer") self.__context = ApplicationContext(self) self.__context.restoreLibrarySettings() self.__asyncload = False self.__dialogState = None self.__treeview = silx.gui.hdf5.Hdf5TreeView(self) """Silx HDF5 TreeView""" # Custom the model to be able to manage the life cycle of the files treeModel = silx.gui.hdf5.Hdf5TreeModel(self.__treeview, ownFiles=False) treeModel.sigH5pyObjectLoaded.connect(self.__h5FileLoaded) treeModel.sigH5pyObjectRemoved.connect(self.__h5FileRemoved) treeModel.sigH5pyObjectSynchronized.connect(self.__h5FileSynchonized) treeModel2 = silx.gui.hdf5.NexusSortFilterProxyModel(self.__treeview) treeModel2.setSourceModel(treeModel) self.__treeview.setModel(treeModel2) self.__dataViewer = DataViewerFrame(self) self.__dataViewer.setGlobalHooks(self.__context) vSpliter = qt.QSplitter(qt.Qt.Vertical) vSpliter.addWidget(self.__dataViewer) vSpliter.setSizes([10, 0]) spliter = qt.QSplitter(self) spliter.addWidget(self.__treeview) spliter.addWidget(vSpliter) spliter.setStretchFactor(1, 1) self.__spliter = spliter main_panel = qt.QWidget(self) layout = qt.QVBoxLayout() layout.addWidget(spliter) layout.setStretchFactor(spliter, 1) main_panel.setLayout(layout) self.setCentralWidget(main_panel) model = self.__treeview.selectionModel() model.selectionChanged.connect(self.displayData) self.__treeview.addContextMenuCallback( self.closeAndSyncCustomContextMenu) treeModel = self.__treeview.findHdf5TreeModel() columns = list(treeModel.COLUMN_IDS) columns.remove(treeModel.DESCRIPTION_COLUMN) columns.remove(treeModel.NODE_COLUMN) self.__treeview.header().setSections(columns) self._iconUpward = icons.getQIcon('plot-yup') self._iconDownward = icons.getQIcon('plot-ydown') self.createActions() self.createMenus() self.__context.restoreSettings() def __h5FileLoaded(self, loadedH5): self.__context.pushRecentFile(loadedH5.file.filename) def __h5FileRemoved(self, removedH5): data = self.__dataViewer.data() if data is not None: if data.file.filename == removedH5.file.filename: self.__dataViewer.setData(None) removedH5.close() def __h5FileSynchonized(self, removedH5, loadedH5): data = self.__dataViewer.data() if data is not None: if data.file.filename == removedH5.file.filename: # Try to synchonize the viewed data try: # TODO: It have to update the data without changing the view # which is not so easy newData = loadedH5[data.name] self.__dataViewer.setData(newData) except Exception: _logger.debug("Backtrace", exc_info=True) removedH5.close() def closeEvent(self, event): self.__context.saveSettings() def saveSettings(self, settings): """Save the window settings to this settings object :param qt.QSettings settings: Initialized settings """ isFullScreen = bool(self.windowState() & qt.Qt.WindowFullScreen) if isFullScreen: # show in normal to catch the normal geometry self.showNormal() settings.beginGroup("mainwindow") settings.setValue("size", self.size()) settings.setValue("pos", self.pos()) settings.setValue("full-screen", isFullScreen) settings.endGroup() settings.beginGroup("mainlayout") settings.setValue("spliter", self.__spliter.sizes()) settings.endGroup() if isFullScreen: self.showFullScreen() def restoreSettings(self, settings): """Restore the window settings using this settings object :param qt.QSettings settings: Initialized settings """ settings.beginGroup("mainwindow") size = settings.value("size", qt.QSize(640, 480)) pos = settings.value("pos", qt.QPoint()) isFullScreen = settings.value("full-screen", False) if not isinstance(isFullScreen, bool): isFullScreen = False settings.endGroup() settings.beginGroup("mainlayout") try: data = settings.value("spliter") data = [int(d) for d in data] self.__spliter.setSizes(data) except Exception: _logger.debug("Backtrace", exc_info=True) settings.endGroup() if not pos.isNull(): self.move(pos) if not size.isNull(): self.resize(size) if isFullScreen: self.showFullScreen() def createActions(self): action = qt.QAction("E&xit", self) action.setShortcuts(qt.QKeySequence.Quit) action.setStatusTip("Exit the application") action.triggered.connect(self.close) self._exitAction = action action = qt.QAction("&Open...", self) action.setStatusTip("Open a file") action.triggered.connect(self.open) self._openAction = action action = qt.QAction("Open Recent", self) action.setStatusTip("Open a recently openned file") action.triggered.connect(self.open) self._openRecentAction = action action = qt.QAction("&About", self) action.setStatusTip("Show the application's About box") action.triggered.connect(self.about) self._aboutAction = action # Plot backend action = qt.QAction("Plot rendering backend", self) action.setStatusTip("Select plot rendering backend") self._plotBackendSelection = action menu = qt.QMenu() action.setMenu(menu) group = qt.QActionGroup(self) group.setExclusive(True) action = qt.QAction("matplotlib", self) action.setStatusTip("Plot will be rendered using matplotlib") action.setCheckable(True) action.triggered.connect(self.__forceMatplotlibBackend) group.addAction(action) menu.addAction(action) self._usePlotWithMatplotlib = action action = qt.QAction("OpenGL", self) action.setStatusTip("Plot will be rendered using OpenGL") action.setCheckable(True) action.triggered.connect(self.__forceOpenglBackend) group.addAction(action) menu.addAction(action) self._usePlotWithOpengl = action # Plot image orientation action = qt.QAction("Default plot image y-axis orientation", self) action.setStatusTip( "Select the default y-axis orientation used by plot displaying images" ) self._plotImageOrientation = action menu = qt.QMenu() action.setMenu(menu) group = qt.QActionGroup(self) group.setExclusive(True) action = qt.QAction("Downward, origin on top", self) action.setIcon(self._iconDownward) action.setStatusTip( "Plot images will use a downward Y-axis orientation") action.setCheckable(True) action.triggered.connect(self.__forcePlotImageDownward) group.addAction(action) menu.addAction(action) self._useYAxisOrientationDownward = action action = qt.QAction("Upward, origin on bottom", self) action.setIcon(self._iconUpward) action.setStatusTip("Plot images will use a upward Y-axis orientation") action.setCheckable(True) action.triggered.connect(self.__forcePlotImageUpward) group.addAction(action) menu.addAction(action) self._useYAxisOrientationUpward = action def __updateFileMenu(self): files = self.__context.getRecentFiles() self._openRecentAction.setEnabled(len(files) != 0) menu = None if len(files) != 0: menu = qt.QMenu() for filePath in files: baseName = os.path.basename(filePath) action = qt.QAction(baseName, self) action.setToolTip(filePath) action.triggered.connect( functools.partial(self.__openRecentFile, filePath)) menu.addAction(action) menu.addSeparator() baseName = os.path.basename(filePath) action = qt.QAction("Clear history", self) action.setToolTip("Clear the history of the recent files") action.triggered.connect(self.__clearRecentFile) menu.addAction(action) self._openRecentAction.setMenu(menu) def __clearRecentFile(self): self.__context.clearRencentFiles() def __openRecentFile(self, filePath): self.appendFile(filePath) def __updateOptionMenu(self): """Update the state of the checked options as it is based on global environment values.""" # plot backend action = self._plotBackendSelection title = action.text().split(": ", 1)[0] action.setText("%s: %s" % (title, silx.config.DEFAULT_PLOT_BACKEND)) action = self._usePlotWithMatplotlib action.setChecked( silx.config.DEFAULT_PLOT_BACKEND in ["matplotlib", "mpl"]) title = action.text().split(" (", 1)[0] if not action.isChecked(): title += " (applied after application restart)" action.setText(title) action = self._usePlotWithOpengl action.setChecked(silx.config.DEFAULT_PLOT_BACKEND in ["opengl", "gl"]) title = action.text().split(" (", 1)[0] if not action.isChecked(): title += " (applied after application restart)" action.setText(title) # plot orientation action = self._plotImageOrientation if silx.config.DEFAULT_PLOT_IMAGE_Y_AXIS_ORIENTATION == "downward": action.setIcon(self._iconDownward) else: action.setIcon(self._iconUpward) action.setIconVisibleInMenu(True) action = self._useYAxisOrientationDownward action.setChecked( silx.config.DEFAULT_PLOT_IMAGE_Y_AXIS_ORIENTATION == "downward") title = action.text().split(" (", 1)[0] if not action.isChecked(): title += " (applied after application restart)" action.setText(title) action = self._useYAxisOrientationUpward action.setChecked( silx.config.DEFAULT_PLOT_IMAGE_Y_AXIS_ORIENTATION != "downward") title = action.text().split(" (", 1)[0] if not action.isChecked(): title += " (applied after application restart)" action.setText(title) def createMenus(self): fileMenu = self.menuBar().addMenu("&File") fileMenu.addAction(self._openAction) fileMenu.addAction(self._openRecentAction) fileMenu.addSeparator() fileMenu.addAction(self._exitAction) fileMenu.aboutToShow.connect(self.__updateFileMenu) optionMenu = self.menuBar().addMenu("&Options") optionMenu.addAction(self._plotImageOrientation) optionMenu.addAction(self._plotBackendSelection) optionMenu.aboutToShow.connect(self.__updateOptionMenu) helpMenu = self.menuBar().addMenu("&Help") helpMenu.addAction(self._aboutAction) def open(self): dialog = self.createFileDialog() if self.__dialogState is None: currentDirectory = os.getcwd() dialog.setDirectory(currentDirectory) else: dialog.restoreState(self.__dialogState) result = dialog.exec_() if not result: return self.__dialogState = dialog.saveState() filenames = dialog.selectedFiles() for filename in filenames: self.appendFile(filename) def createFileDialog(self): dialog = qt.QFileDialog(self) dialog.setWindowTitle("Open") dialog.setModal(True) # NOTE: hdf5plugin have to be loaded before import silx.io extensions = collections.OrderedDict() for description, ext in silx.io.supported_extensions().items(): extensions[description] = " ".join(sorted(list(ext))) # NOTE: hdf5plugin have to be loaded before import fabio if fabio is not None: extensions["NeXus layout from EDF files"] = "*.edf" extensions["NeXus layout from TIFF image files"] = "*.tif *.tiff" extensions["NeXus layout from CBF files"] = "*.cbf" extensions["NeXus layout from MarCCD image files"] = "*.mccd" all_supported_extensions = set() for name, exts in extensions.items(): exts = exts.split(" ") all_supported_extensions.update(exts) all_supported_extensions = sorted(list(all_supported_extensions)) filters = [] filters.append("All supported files (%s)" % " ".join(all_supported_extensions)) for name, extension in extensions.items(): filters.append("%s (%s)" % (name, extension)) filters.append("All files (*)") dialog.setNameFilters(filters) dialog.setFileMode(qt.QFileDialog.ExistingFiles) return dialog def about(self): from .About import About About.about(self, "Silx viewer") def __forcePlotImageDownward(self): silx.config.DEFAULT_PLOT_IMAGE_Y_AXIS_ORIENTATION = "downward" def __forcePlotImageUpward(self): silx.config.DEFAULT_PLOT_IMAGE_Y_AXIS_ORIENTATION = "upward" def __forceMatplotlibBackend(self): silx.config.DEFAULT_PLOT_BACKEND = "matplotlib" def __forceOpenglBackend(self): silx.config.DEFAULT_PLOT_BACKEND = "opengl" def appendFile(self, filename): self.__treeview.findHdf5TreeModel().appendFile(filename) def displayData(self): """Called to update the dataviewer with the selected data. """ selected = list( self.__treeview.selectedH5Nodes(ignoreBrokenLinks=False)) if len(selected) == 1: # Update the viewer for a single selection data = selected[0] self.__dataViewer.setData(data) def useAsyncLoad(self, useAsync): self.__asyncload = useAsync def closeAndSyncCustomContextMenu(self, event): """Called to populate the context menu :param silx.gui.hdf5.Hdf5ContextMenuEvent event: Event containing expected information to populate the context menu """ selectedObjects = event.source().selectedH5Nodes( ignoreBrokenLinks=False) menu = event.menu() if not menu.isEmpty(): menu.addSeparator() # Import it here to be sure to use the right logging level import h5py for obj in selectedObjects: if obj.ntype is h5py.File: action = qt.QAction("Remove %s" % obj.local_filename, event.source()) action.triggered.connect( lambda: self.__treeview.findHdf5TreeModel( ).removeH5pyObject(obj.h5py_object)) menu.addAction(action) action = qt.QAction("Synchronize %s" % obj.local_filename, event.source()) action.triggered.connect( lambda: self.__treeview.findHdf5TreeModel( ).synchronizeH5pyObject(obj.h5py_object)) menu.addAction(action)
class DataPanel(qt.QWidget): def __init__(self, parent=None, context=None): qt.QWidget.__init__(self, parent=parent) self.__customNxdataItem = None self.__dataTitle = _HeaderLabel(self) self.__dataTitle.setVisible(False) self.__dataViewer = DataViewerFrame(self) self.__dataViewer.setGlobalHooks(context) layout = qt.QVBoxLayout(self) layout.setSpacing(0) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.__dataTitle) layout.addWidget(self.__dataViewer) def getData(self): return self.__dataViewer.data() def getCustomNxdataItem(self): return self.__customNxdataItem def setData(self, data): self.__customNxdataItem = None self.__dataViewer.setData(data) self.__dataTitle.setVisible(data is not None) if data is not None: self.__dataTitle.setVisible(True) if hasattr(data, "name"): if hasattr(data, "file"): filename = str(data.file.filename) else: filename = "" path = data.name else: filename = "" path = "" self.__dataTitle.setData(filename, path) def setCustomDataItem(self, item): self.__customNxdataItem = item if item is not None: data = item.getVirtualGroup() else: data = None self.__dataViewer.setData(data) self.__dataTitle.setVisible(item is not None) if item is not None: text = item.text() self.__dataTitle.setText(text) def removeDatasetsFrom(self, root): """ Remove all datasets provided by this root .. note:: This function do not update data stored inside customNxdataItem cause in the silx-view context this item is already updated on his own. :param root: The root file of datasets to remove """ data = self.__dataViewer.data() if data is not None: if data.file is not None: # That's an approximation, IS can't be used as h5py generates # To objects for each requests to a node if data.file.filename == root.file.filename: self.__dataViewer.setData(None) def replaceDatasetsFrom(self, removedH5, loadedH5): """ Replace any dataset from any NXdata items using the same dataset name from another root. Usually used when a file was synchronized. .. note:: This function do not update data stored inside customNxdataItem cause in the silx-view context this item is already updated on his own. :param removedRoot: The h5py root file which is replaced (which have to be removed) :param loadedRoot: The new h5py root file which have to be used instread. """ data = self.__dataViewer.data() if data is not None: if data.file is not None: if data.file.filename == removedH5.file.filename: # Try to synchonize the viewed data try: # TODO: It have to update the data without changing the # view which is not so easy newData = loadedH5[data.name] self.__dataViewer.setData(newData) except Exception: _logger.debug("Backtrace", exc_info=True)
def __init__(self): """ :param files_: List of HDF5 or Spec files (pathes or :class:`silx.io.spech5.SpecH5` or :class:`h5py.File` instances) """ # Import it here to be sure to use the right logging level import silx.gui.hdf5 from silx.gui.data.DataViewerFrame import DataViewerFrame qt.QMainWindow.__init__(self) self.setWindowTitle("Silx viewer") self.__context = ApplicationContext(self) self.__context.restoreLibrarySettings() self.__asyncload = False self.__dialogState = None self.__treeview = silx.gui.hdf5.Hdf5TreeView(self) """Silx HDF5 TreeView""" # Custom the model to be able to manage the life cycle of the files treeModel = silx.gui.hdf5.Hdf5TreeModel(self.__treeview, ownFiles=False) treeModel.sigH5pyObjectLoaded.connect(self.__h5FileLoaded) treeModel.sigH5pyObjectRemoved.connect(self.__h5FileRemoved) treeModel.sigH5pyObjectSynchronized.connect(self.__h5FileSynchonized) treeModel2 = silx.gui.hdf5.NexusSortFilterProxyModel(self.__treeview) treeModel2.setSourceModel(treeModel) self.__treeview.setModel(treeModel2) self.__dataViewer = DataViewerFrame(self) self.__dataViewer.setGlobalHooks(self.__context) vSpliter = qt.QSplitter(qt.Qt.Vertical) vSpliter.addWidget(self.__dataViewer) vSpliter.setSizes([10, 0]) spliter = qt.QSplitter(self) spliter.addWidget(self.__treeview) spliter.addWidget(vSpliter) spliter.setStretchFactor(1, 1) self.__spliter = spliter main_panel = qt.QWidget(self) layout = qt.QVBoxLayout() layout.addWidget(spliter) layout.setStretchFactor(spliter, 1) main_panel.setLayout(layout) self.setCentralWidget(main_panel) model = self.__treeview.selectionModel() model.selectionChanged.connect(self.displayData) self.__treeview.addContextMenuCallback( self.closeAndSyncCustomContextMenu) treeModel = self.__treeview.findHdf5TreeModel() columns = list(treeModel.COLUMN_IDS) columns.remove(treeModel.DESCRIPTION_COLUMN) columns.remove(treeModel.NODE_COLUMN) self.__treeview.header().setSections(columns) self._iconUpward = icons.getQIcon('plot-yup') self._iconDownward = icons.getQIcon('plot-ydown') self.createActions() self.createMenus() self.__context.restoreSettings()
def createDefaultViews(self, parent=None): views = list(DataViewerFrame.createDefaultViews(self, parent=parent)) oldView = [v for v in views if v.modeId() == DataViews.PLOT1D_MODE][0] newView = Plot1DViewWithPlugins(parent=parent) views[views.index(oldView)] = newView return views
class Hdf5TreeViewExample(qt.QMainWindow): """ This window show an example of use of a Hdf5TreeView. The tree is initialized with a list of filenames. A panel allow to play with internal property configuration of the widget, and a text screen allow to display events. """ def __init__(self, filenames=None): """ :param files_: List of HDF5 or Spec files (pathes or :class:`silx.io.spech5.SpecH5` or :class:`h5py.File` instances) """ qt.QMainWindow.__init__(self) self.setWindowTitle("Silx HDF5 widget example") self.__asyncload = False self.__treeview = silx.gui.hdf5.Hdf5TreeView(self) """Silx HDF5 TreeView""" self.__text = qt.QTextEdit(self) """Widget displaying information""" self.__dataViewer = DataViewerFrame(self) vSpliter = qt.QSplitter(qt.Qt.Vertical) vSpliter.addWidget(self.__dataViewer) vSpliter.addWidget(self.__text) vSpliter.setSizes([10, 0]) spliter = qt.QSplitter(self) spliter.addWidget(self.__treeview) spliter.addWidget(vSpliter) spliter.setStretchFactor(1, 1) main_panel = qt.QWidget(self) layout = qt.QVBoxLayout() layout.addWidget(spliter) layout.addWidget(self.createTreeViewConfigurationPanel(self, self.__treeview)) layout.setStretchFactor(spliter, 1) main_panel.setLayout(layout) self.setCentralWidget(main_panel) # append all files to the tree for file_name in filenames: self.__treeview.findHdf5TreeModel().appendFile(file_name) self.__treeview.activated.connect(self.displayData) self.__treeview.activated.connect(lambda index: self.displayEvent("activated", index)) self.__treeview.clicked.connect(lambda index: self.displayEvent("clicked", index)) self.__treeview.doubleClicked.connect(lambda index: self.displayEvent("doubleClicked", index)) self.__treeview.entered.connect(lambda index: self.displayEvent("entered", index)) self.__treeview.pressed.connect(lambda index: self.displayEvent("pressed", index)) self.__treeview.addContextMenuCallback(self.customContextMenu) # lambda function will never be called cause we store it as weakref self.__treeview.addContextMenuCallback(lambda event: None) # you have to store it first self.__store_lambda = lambda event: self.closeAndSyncCustomContextMenu(event) self.__treeview.addContextMenuCallback(self.__store_lambda) def displayData(self): """Called to update the dataviewer with the selected data. """ selected = list(self.__treeview.selectedH5Nodes()) if len(selected) == 1: # Update the viewer for a single selection data = selected[0] # data is a hdf5.H5Node object # data.h5py_object is a Group/Dataset object (from h5py, spech5, fabioh5) # The dataviewer can display both self.__dataViewer.setData(data) def displayEvent(self, eventName, index): """Called to log event in widget """ def formatKey(name, value): name, value = silx.utils.html.escape(str(name)), silx.utils.html.escape(str(value)) return "<li><b>%s</b>: %s</li>" % (name, value) text = "<html>" text += "<h1>Event</h1>" text += "<ul>" text += formatKey("name", eventName) text += formatKey("index", type(index)) text += "</ul>" text += "<h1>Selected HDF5 objects</h1>" for h5_obj in self.__treeview.selectedH5Nodes(): text += "<h2>HDF5 object</h2>" text += "<ul>" text += formatKey("local_filename", h5_obj.local_file.filename) text += formatKey("local_basename", h5_obj.local_basename) text += formatKey("local_name", h5_obj.local_name) text += formatKey("real_filename", h5_obj.file.filename) text += formatKey("real_basename", h5_obj.basename) text += formatKey("real_name", h5_obj.name) text += formatKey("obj", h5_obj.ntype) text += formatKey("dtype", getattr(h5_obj, "dtype", None)) text += formatKey("shape", getattr(h5_obj, "shape", None)) text += formatKey("attrs", getattr(h5_obj, "attrs", None)) if hasattr(h5_obj, "attrs"): text += "<ul>" if len(h5_obj.attrs) == 0: text += "<li>empty</li>" for key, value in h5_obj.attrs.items(): text += formatKey(key, value) text += "</ul>" text += "</ul>" text += "</html>" self.__text.setHtml(text) def useAsyncLoad(self, useAsync): self.__asyncload = useAsync def __fileCreated(self, filename): if self.__asyncload: self.__treeview.findHdf5TreeModel().insertFileAsync(filename) else: self.__treeview.findHdf5TreeModel().insertFile(filename) def customContextMenu(self, event): """Called to populate the context menu :param silx.gui.hdf5.Hdf5ContextMenuEvent event: Event containing expected information to populate the context menu """ selectedObjects = event.source().selectedH5Nodes() menu = event.menu() hasDataset = False for obj in selectedObjects: if obj.ntype is h5py.Dataset: hasDataset = True break if not menu.isEmpty(): menu.addSeparator() if hasDataset: action = qt.QAction("Do something on the datasets", event.source()) menu.addAction(action) def closeAndSyncCustomContextMenu(self, event): """Called to populate the context menu :param silx.gui.hdf5.Hdf5ContextMenuEvent event: Event containing expected information to populate the context menu """ selectedObjects = event.source().selectedH5Nodes() menu = event.menu() if not menu.isEmpty(): menu.addSeparator() for obj in selectedObjects: if obj.ntype is h5py.File: action = qt.QAction("Remove %s" % obj.local_filename, event.source()) action.triggered.connect(lambda: self.__treeview.findHdf5TreeModel().removeH5pyObject(obj.h5py_object)) menu.addAction(action) action = qt.QAction("Synchronize %s" % obj.local_filename, event.source()) action.triggered.connect(lambda: self.__treeview.findHdf5TreeModel().synchronizeH5pyObject(obj.h5py_object)) menu.addAction(action) def __hdf5ComboChanged(self, index): function = self.__hdf5Combo.itemData(index) self.__createHdf5Button.setCallable(function) def __edfComboChanged(self, index): function = self.__edfCombo.itemData(index) self.__createEdfButton.setCallable(function) def createTreeViewConfigurationPanel(self, parent, treeview): """Create a configuration panel to allow to play with widget states""" panel = qt.QWidget(parent) panel.setLayout(qt.QHBoxLayout()) content = qt.QGroupBox("Create HDF5", panel) content.setLayout(qt.QVBoxLayout()) panel.layout().addWidget(content) combo = qt.QComboBox() combo.addItem("Containing all types", get_hdf5_with_all_types) combo.addItem("Containing all links", get_hdf5_with_all_links) combo.addItem("Containing 1000 datasets", get_hdf5_with_1000_datasets) combo.addItem("Containing 10000 datasets", get_hdf5_with_10000_datasets) combo.addItem("Containing 100000 datasets", get_hdf5_with_100000_datasets) combo.addItem("Containing recursive links", get_hdf5_with_recursive_links) combo.addItem("Containing external recursive links", get_hdf5_with_external_recursive_links) combo.addItem("Containing NXdata groups", get_hdf5_with_nxdata) combo.activated.connect(self.__hdf5ComboChanged) content.layout().addWidget(combo) button = ThreadPoolPushButton(content, text="Create") button.setCallable(combo.itemData(combo.currentIndex())) button.succeeded.connect(self.__fileCreated) content.layout().addWidget(button) self.__hdf5Combo = combo self.__createHdf5Button = button asyncload = qt.QCheckBox("Async load", content) asyncload.setChecked(self.__asyncload) asyncload.toggled.connect(lambda: self.useAsyncLoad(asyncload.isChecked())) content.layout().addWidget(asyncload) content.layout().addStretch(1) content = qt.QGroupBox("Create EDF", panel) content.setLayout(qt.QVBoxLayout()) panel.layout().addWidget(content) combo = qt.QComboBox() combo.addItem("Containing all types", get_edf_with_all_types) combo.addItem("Containing 100000 datasets", get_edf_with_100000_frames) combo.activated.connect(self.__edfComboChanged) content.layout().addWidget(combo) button = ThreadPoolPushButton(content, text="Create") button.setCallable(combo.itemData(combo.currentIndex())) button.succeeded.connect(self.__fileCreated) content.layout().addWidget(button) self.__edfCombo = combo self.__createEdfButton = button content.layout().addStretch(1) option = qt.QGroupBox("Tree options", panel) option.setLayout(qt.QVBoxLayout()) panel.layout().addWidget(option) sorting = qt.QCheckBox("Enable sorting", option) sorting.setChecked(treeview.selectionMode() == qt.QAbstractItemView.MultiSelection) sorting.toggled.connect(lambda: treeview.setSortingEnabled(sorting.isChecked())) option.layout().addWidget(sorting) multiselection = qt.QCheckBox("Multi-selection", option) multiselection.setChecked(treeview.selectionMode() == qt.QAbstractItemView.MultiSelection) switch_selection = lambda: treeview.setSelectionMode( qt.QAbstractItemView.MultiSelection if multiselection.isChecked() else qt.QAbstractItemView.SingleSelection) multiselection.toggled.connect(switch_selection) option.layout().addWidget(multiselection) filedrop = qt.QCheckBox("Drop external file", option) filedrop.setChecked(treeview.findHdf5TreeModel().isFileDropEnabled()) filedrop.toggled.connect(lambda: treeview.findHdf5TreeModel().setFileDropEnabled(filedrop.isChecked())) option.layout().addWidget(filedrop) filemove = qt.QCheckBox("Reorder files", option) filemove.setChecked(treeview.findHdf5TreeModel().isFileMoveEnabled()) filemove.toggled.connect(lambda: treeview.findHdf5TreeModel().setFileMoveEnabled(filedrop.isChecked())) option.layout().addWidget(filemove) option.layout().addStretch(1) option = qt.QGroupBox("Header options", panel) option.setLayout(qt.QVBoxLayout()) panel.layout().addWidget(option) autosize = qt.QCheckBox("Auto-size headers", option) autosize.setChecked(treeview.header().hasAutoResizeColumns()) autosize.toggled.connect(lambda: treeview.header().setAutoResizeColumns(autosize.isChecked())) option.layout().addWidget(autosize) columnpopup = qt.QCheckBox("Popup to hide/show columns", option) columnpopup.setChecked(treeview.header().hasHideColumnsPopup()) columnpopup.toggled.connect(lambda: treeview.header().setEnableHideColumnsPopup(columnpopup.isChecked())) option.layout().addWidget(columnpopup) define_columns = qt.QComboBox() define_columns.addItem("Default columns", treeview.findHdf5TreeModel().COLUMN_IDS) define_columns.addItem("Only name and Value", [treeview.findHdf5TreeModel().NAME_COLUMN, treeview.findHdf5TreeModel().VALUE_COLUMN]) define_columns.activated.connect(lambda index: treeview.header().setSections(define_columns.itemData(index))) option.layout().addWidget(define_columns) option.layout().addStretch(1) panel.layout().addStretch(1) return panel