예제 #1
0
class SegyTabWidget(QWidget):
    def __init__(self, segywidgets=None, parent=None):
        QWidget.__init__(self, parent)
        """
        :type segywidgets: list[segyviewlib.SegyViewWidget]
        :type parent: QObject
        """
        self._context = None
        self._segywidgets = segywidgets if segywidgets else []
        self._tab_widget = QTabWidget()
        self.initialize()

    def initialize(self):
        if len(self._segywidgets) == 0: return

        layout = QVBoxLayout()

        slice_data_source, slice_models = self._setup_model_source()

        self._context = SliceViewContext(slice_models,
                                         slice_data_source,
                                         has_data=False)
        self._context.show_indicators(True)
        self._context.data_changed.connect(self._data_changed)

        self._slice_view_widget = None  # Required for settingswindow
        self._settings_window = SettingsWindow(self._context, self)
        self._settings_window.min_max_changed.connect(self._min_max_changed)
        self._settings_window.indicators_changed.connect(
            self._indicators_changed)
        self._settings_window.interpolation_changed.connect(
            self._interpolation_changed)
        self._settings_window.samples_unit_changed.connect(
            self._samples_unit_changed)
        self._modify_qtree(self._settings_window.qtree, [3, 5])

        self._toolbar = self._create_toolbar()
        self._local_data_changed(self._segywidgets[0].context.models)

        for i, segywidget in enumerate(self._segywidgets):
            self.add_segy_view_widget(i, segywidget)

        self._tab_widget.currentChanged.connect(self._tab_changed)

        layout.addWidget(self._toolbar)
        layout.addWidget(self._tab_widget)

        self.setLayout(layout)

    @property
    def _current_ctxt(self):
        """
        :rtype: SliceViewContext
        """
        return self._tab_widget.currentWidget().context

    @property
    def _ctxs(self):
        """
        :rtype: list of SliceViewContext
        """
        return [
            self._tab_widget.widget(index).context
            for index in range(0, self._tab_widget.count())
        ]

    def count(self):
        """
        :rtype: int
        """
        return self._tab_widget.count()

    def add_segy_view_widget(self, ind, widget, name=None):
        """
        :param widget: The SegyViewWidget that will be added to the SegyTabWidget
        :type widget: SegyViewWidget
        """

        if self._context is None:
            self._segywidgets.append(widget)
            self.initialize()
            return 0  # return 0 for first widget index

        self._tab_widget.updatesEnabled = False
        widget.show_toolbar(toolbar=True,
                            layout_combo=False,
                            colormap=True,
                            save=True,
                            settings=True)
        self._modify_qtree(widget.settings_window.qtree, [0, 1, 2, 4])

        if name is None:
            name = os.path.basename(widget.slice_data_source.source_filename)

        id = self._tab_widget.insertTab(ind, widget, name)

        widget.context.data_changed.connect(self._local_data_changed)
        self._tab_widget.updatesEnabled = True

        return id

    def remove_segy_view_widget(self, index):
        """
        :param index: The index of the tab to be removed
        :type index: int
        """

        self._tab_widget.removeTab(index)

    def _local_data_changed(self, models=None):
        for m in self._context.models:
            for current_model in models:
                if current_model.index_direction == m.index_direction:
                    m.index = current_model.index
                if current_model.x_index_direction == m.index_direction:
                    m.x_index = current_model.index
                if current_model.y_index_direction == m.index_direction:
                    m.y_index = current_model.index
            m.dirty = True

        self._update_models()
        self._context.context_changed.emit()

    def _data_changed(self):
        self._update_models()
        self._update_views()

    def _min_max_changed(self, values, axis):
        min, max = values

        for ctxt in self._ctxs:
            with blocked_update(ctxt, self._current_ctxt):
                if axis == 'depth':
                    ctxt.set_y_view_limits(SD.crossline, min, max)
                    ctxt.set_y_view_limits(SD.inline, min, max)

                elif axis == 'iline':
                    ctxt.set_x_view_limits(SD.crossline, min, max)
                    ctxt.set_x_view_limits(SD.depth, min, max)

                elif axis == 'xline':
                    ctxt.set_x_view_limits(SD.inline, min, max)
                    ctxt.set_y_view_limits(SD.depth, min, max)

        self._update_views()

    def _interpolation_changed(self, interpolation_name):
        for ctxt in self._ctxs:
            with blocked_update(ctxt, self._current_ctxt):
                ctxt.set_interpolation(interpolation_name)

    def _indicators_changed(self, visible):
        for ctxt in self._ctxs:
            with blocked_update(ctxt, self._current_ctxt):
                ctxt.show_indicators(visible)

    def _samples_unit_changed(self, val):
        for ctxt in self._ctxs:
            with blocked_update(ctxt, self._current_ctxt):
                ctxt.samples_unit = val

    def _update_models(self):
        dirty_models = [m for m in self._context.models if m.dirty]
        local_models = list(
            chain.from_iterable([ctx.models for ctx in self._ctxs]))

        for m in dirty_models:
            for local_m in local_models:
                if local_m.index_direction == m.index_direction:
                    local_m.index = m.index
                if local_m.x_index_direction == m.index_direction:
                    local_m.x_index = m.index
                if local_m.y_index_direction == m.index_direction:
                    local_m.y_index = m.index
                local_m.dirty = True
            m.dirty = False

    def _update_views(self):
        self._tab_widget.currentWidget().context.context_changed.emit()
        self._tab_widget.currentWidget().context.load_data()

    def _tab_changed(self):
        if self._tab_widget.count() == 0: return
        widget_spec = self._tab_widget.currentWidget(
        ).slice_view_widget.current_layout()
        setting_spec = self.layout_combo.get_current_layout()
        if widget_spec != setting_spec:
            self._tab_widget.currentWidget().slice_view_widget.set_plot_layout(
                setting_spec)
        self._update_views()

    def _setup_model_source(self):
        slice_data_source = SliceDataSource(False)
        directions = [SD.inline, SD.crossline, SD.depth]

        source_template = self._segywidgets[0].slice_data_source

        for direction in directions:
            slice_data_source.set_indexes(
                direction, source_template.indexes_for_direction(direction))

        inline = SliceModel("Inline", SD.inline, SD.crossline, SD.depth)
        xline = SliceModel("Crossline", SD.crossline, SD.inline, SD.depth)
        depth = SliceModel("Depth", SD.depth, SD.inline, SD.crossline)
        slice_models = [inline, xline, depth]

        return slice_data_source, slice_models

    def __del__(self):
        self.layout_combo.layout_changed.disconnect(self._plot_layout_changed)

    def _create_toolbar(self):
        toolbar = QToolBar()
        toolbar.setFloatable(False)
        toolbar.setMovable(False)

        self.layout_combo = LayoutCombo()
        toolbar.addWidget(self.layout_combo)
        self.layout_combo.layout_changed.connect(self._plot_layout_changed)

        self._settings_button = QToolButton()
        self._settings_button.setToolTip("Toggle settings visibility")
        self._settings_button.setIcon(resource_icon("cog.png"))
        self._settings_button.setCheckable(True)
        self._settings_button.toggled.connect(self._show_settings)
        toolbar.addWidget(self._settings_button)

        def toggle_on_close(event):
            self._settings_button.setChecked(False)
            event.accept()

        self._settings_window.closeEvent = toggle_on_close

        return toolbar

    def _modify_qtree(self, tree, items):
        for i in items:
            tree.setRowHidden(i, QModelIndex(), True)

    def _plot_layout_changed(self, spec):
        self._tab_widget.currentWidget().slice_view_widget.set_plot_layout(
            spec)

    def _show_settings(self, toggled):
        self._settings_window.setVisible(toggled)
        if self._settings_window.isMinimized():
            self._settings_window.showNormal()
예제 #2
0
class SegyViewWidget(QWidget):
    def __init__(self, filename, show_toolbar=True, color_maps=None,
                                 width=11.7, height=8.3, dpi=100,
                                 segyioargs = {}, parent=None):
        QWidget.__init__(self, parent)

        inline = SliceModel("Inline", SD.inline, SD.crossline, SD.depth)
        xline = SliceModel("Crossline", SD.crossline, SD.inline, SD.depth)
        depth = SliceModel("Depth", SD.depth, SD.inline, SD.crossline)

        slice_models = [inline, xline, depth]
        slice_data_source = SliceDataSource(filename, **segyioargs)
        self._slice_data_source = slice_data_source

        self._context = SliceViewContext(slice_models, slice_data_source)
        self._context.show_indicators(True)

        self._slice_view_widget = SliceViewWidget(self._context, width, height, dpi, self)

        layout = QVBoxLayout()

        self._settings_window = SettingsWindow(self._context, self)

        self._toolbar = self._create_toolbar(color_maps)
        self._toolbar.setVisible(show_toolbar)
        layout.addWidget(self._toolbar)
        layout.addWidget(self._slice_view_widget)

        self.setLayout(layout)

    def toolbar(self):
        """ :rtype: QToolBar """
        return self._toolbar

    def _create_toolbar(self, color_maps):
        toolbar = QToolBar()
        toolbar.setFloatable(False)
        toolbar.setMovable(False)

        layout_combo = LayoutCombo()
        toolbar.addWidget(layout_combo)
        layout_combo.layout_changed.connect(self._slice_view_widget.set_plot_layout)

        # self._colormap_combo = ColormapCombo(['seismic', 'spectral', 'RdGy', 'hot', 'jet', 'gray'])
        self._colormap_combo = ColormapCombo(color_maps)
        self._colormap_combo.currentIndexChanged[int].connect(self._colormap_changed)
        toolbar.addWidget(self._colormap_combo)

        save_button = QToolButton()
        save_button.setToolTip("Save as image")
        save_button.setIcon(resource_icon("table_export.png"))
        save_button.clicked.connect(self._save_figure)
        toolbar.addWidget(save_button)

        self._settings_button = QToolButton()
        self._settings_button.setToolTip("Toggle settings visibility")
        self._settings_button.setIcon(resource_icon("cog.png"))
        self._settings_button.setCheckable(True)
        self._settings_button.toggled.connect(self._show_settings)
        toolbar.addWidget(self._settings_button)

        def toggle_on_close(event):
            self._settings_button.setChecked(False)
            event.accept()

        self._settings_window.closeEvent = toggle_on_close

        self._colormap_combo.setCurrentIndex(45)
        layout_combo.setCurrentIndex(4)

        return toolbar

    def _colormap_changed(self, index):
        colormap = str(self._colormap_combo.itemText(index))
        self._context.set_colormap(colormap)

    def _interpolation_changed(self, index):
        interpolation_name = str(self._interpolation_combo.itemText(index))
        self._context.set_interpolation(interpolation_name)

    def _save_figure(self):
        formats = "Portable Network Graphic (*.png);;Adobe Acrobat (*.pdf);;Scalable Vector Graphics (*.svg)"
        output_file = QFileDialog.getSaveFileName(self, "Save as image", "untitled.png", formats)

        output_file = str(output_file).strip()

        if len(output_file) == 0:
            return

        image_size = self._context.image_size
        if not image_size:
            fig = self._slice_view_widget
        else:
            w, h, dpi = image_size
            fig = SliceViewWidget(self._context, width = w, height = h, dpi = dpi)
            fig.set_plot_layout(self._slice_view_widget.layout_figure().current_layout())

        fig.layout_figure().savefig(output_file)

    def set_source_filename(self, filename):
        self._slice_data_source.set_source_filename(filename)

    def as_depth(self):
        self._context.samples_unit = 'Depth (m)'

    def _show_settings(self, toggled):
        self._settings_window.setVisible(toggled)
        if self._settings_window.isMinimized():
            self._settings_window.showNormal()
예제 #3
0
class SegyViewWidget(QWidget):
    def __init__(self,
                 filename,
                 show_toolbar=True,
                 color_maps=None,
                 width=11.7,
                 height=8.3,
                 dpi=100,
                 segyioargs={},
                 parent=None):
        QWidget.__init__(self, parent)

        inline = SliceModel("Inline", SD.inline, SD.crossline, SD.depth)
        xline = SliceModel("Crossline", SD.crossline, SD.inline, SD.depth)
        depth = SliceModel("Depth", SD.depth, SD.inline, SD.crossline)

        slice_models = [inline, xline, depth]
        slice_data_source = SliceDataSource(filename, **segyioargs)
        self._slice_data_source = slice_data_source

        self._context = SliceViewContext(slice_models, slice_data_source)
        self._context.show_indicators(True)

        self._slice_view_widget = SliceViewWidget(self._context, width, height,
                                                  dpi, self)

        layout = QVBoxLayout()

        self._settings_window = SettingsWindow(self._context, self)
        self._help_window = HelpWindow(self)

        self._toolbar = self._create_toolbar(color_maps)
        self._toolbar.setVisible(show_toolbar)
        layout.addWidget(self._toolbar)
        layout.addWidget(self._slice_view_widget)

        self.setLayout(layout)

    @property
    def context(self):
        """ :rtype: SliceViewContext"""
        return self._context

    @property
    def slice_data_source(self):
        """ :rtype: SliceDataSource"""
        return self._slice_data_source

    @property
    def toolbar(self):
        """ :rtype: QToolBar """
        return self._toolbar

    @property
    def slice_view_widget(self):
        """ :rtype: SliceViewWidget """
        return self._slice_view_widget

    @property
    def settings_window(self):
        """ :rtype: QWidget """
        return self._settings_window

    @property
    def help_window(self):
        """ :rtype: QWidget """
        return self._help_window

    # custom signal slots are required to be manually disconnected
    # https://stackoverflow.com/questions/15600014/pyqt-disconnect-slots-new-style
    def __del__(self):
        self._layout_combo.layout_changed.disconnect(
            self._slice_view_widget.set_plot_layout)

    def _create_toolbar(self, color_maps):
        toolbar = QToolBar()
        toolbar.setFloatable(False)
        toolbar.setMovable(False)

        self._layout_combo = LayoutCombo()
        self._layout_combo_action = QWidgetAction(self._layout_combo)
        self._layout_combo_action.setDefaultWidget(self._layout_combo)
        toolbar.addAction(self._layout_combo_action)
        self._layout_combo.layout_changed.connect(
            self._slice_view_widget.set_plot_layout)

        # self._colormap_combo = ColormapCombo(['seismic', 'spectral', 'RdGy', 'hot', 'jet', 'gray'])
        self._colormap_combo = ColormapCombo(color_maps)
        self._colormap_combo.currentIndexChanged[int].connect(
            self._colormap_changed)
        toolbar.addWidget(self._colormap_combo)

        self._save_button = QToolButton()
        self._save_button.setToolTip("Save as image")
        self._save_button.setIcon(resource_icon("table_export.png"))
        self._save_button.clicked.connect(self._save_figure)
        toolbar.addWidget(self._save_button)

        self._settings_button = QToolButton()
        self._settings_button.setToolTip("Toggle settings visibility")
        self._settings_button.setIcon(resource_icon("cog.png"))
        self._settings_button.setCheckable(True)
        self._settings_button.toggled.connect(self._show_settings)
        toolbar.addWidget(self._settings_button)

        self._help_button = QToolButton()
        self._help_button.setToolTip("View help")
        self._help_button.setIcon(resource_icon("help.png"))
        self._help_button.setCheckable(True)
        self._help_button.toggled.connect(self._show_help)
        toolbar.addWidget(self._help_button)

        def toggle_on_close(event):
            self._settings_button.setChecked(False)
            event.accept()

        def toggle_on_close_help(event):
            self._help_button.setChecked(False)
            event.accept()

        self._settings_window.closeEvent = toggle_on_close
        self._help_window.closeEvent = toggle_on_close_help

        self._colormap_combo.setCurrentIndex(45)
        self.set_default_layout()

        return toolbar

    def _colormap_changed(self, index):
        colormap = str(self._colormap_combo.itemText(index))
        self._context.set_colormap(colormap)

    def _interpolation_changed(self, index):
        interpolation_name = str(self._interpolation_combo.itemText(index))
        self._context.set_interpolation(interpolation_name)

    def _save_figure(self):
        formats = "Portable Network Graphic (*.png);;Adobe Acrobat (*.pdf);;Scalable Vector Graphics (*.svg)"
        output_file = QFileDialog.getSaveFileName(self, "Save as image",
                                                  "untitled.png", formats)

        output_file = str(output_file).strip()

        if len(output_file) == 0:
            return

        image_size = self._context.image_size
        if not image_size:
            fig = self._slice_view_widget
        else:
            w, h, dpi = image_size
            fig = SliceViewWidget(self._context, width=w, height=h, dpi=dpi)
            fig.set_plot_layout(
                self._slice_view_widget.layout_figure().current_layout())

        fig.layout_figure().savefig(output_file)

    def set_source_filename(self, filename):
        self._slice_data_source.set_source_filename(filename)

    def set_default_layout(self):
        # default slice view layout depends on the file size
        if self._slice_data_source.file_size < 8 * 10**8:
            self._layout_combo.setCurrentIndex(
                self._layout_combo.DEFAULT_SMALL_FILE_LAYOUT)
        else:
            self._layout_combo.setCurrentIndex(
                self._layout_combo.DEFAULT_LARGE_FILE_LAYOUT)

    def as_depth(self):
        self._context.samples_unit = 'Depth (m)'

    def _show_settings(self, toggled):
        self._settings_window.setVisible(toggled)
        if self._settings_window.isMinimized():
            self._settings_window.showNormal()

    def _show_help(self, toggled):
        self._help_window.setVisible(toggled)
        if self._help_window.isMinimized():
            self._help_window.showNormal()

    def show_toolbar(self,
                     toolbar,
                     layout_combo=True,
                     colormap=True,
                     save=True,
                     settings=True):
        self._toolbar.setVisible(toolbar)
        self._colormap_combo.setDisabled(not colormap)
        self._save_button.setDisabled(not save)
        self._settings_button.setDisabled(not settings)
        self._layout_combo_action.setVisible(layout_combo)
예제 #4
0
class SegyTabWidget(QWidget):
    def __init__(self,
                 segywidgets,
                 show_toolbar=True,
                 color_maps=None,
                 width=11.7,
                 height=8.3,
                 dpi=100,
                 parent=None):
        QWidget.__init__(self, parent)

        self._segywidgets = segywidgets
        """ :type: list[SegyViewWidget] """

        self._tab_widget = QTabWidget()
        layout = QVBoxLayout()

        for i, segywidget in enumerate(self._segywidgets):
            segywidget.show_toolbar(False)
            self._tab_widget.insertTab(i, segywidget, 'File: ' + str(i + 1))

        self._tab_widget.currentChanged.connect(self.update_views)

        slice_data_source = self.setup_datasource()

        inline = SliceModel("Inline", SD.inline, SD.crossline, SD.depth)
        xline = SliceModel("Crossline", SD.crossline, SD.inline, SD.depth)
        depth = SliceModel("Depth", SD.depth, SD.inline, SD.crossline)
        slice_models = [inline, xline, depth]

        self._context = SliceViewContext(slice_models,
                                         slice_data_source,
                                         has_data=False)
        self._context.data_changed.connect(self.data_changed)

        self._settings_window = SettingsWindow(self._context, self)
        self._toolbar = self._create_toolbar(color_maps)

        layout.addWidget(self._toolbar)
        layout.addWidget(self._tab_widget)

        self.setLayout(layout)

    def data_changed(self):
        dirty_models = [m for m in self._context.models if m.dirty]
        ctxs = [
            self._tab_widget.widget(index).context
            for index in range(0, self._tab_widget.count())
        ]
        local_models = list(chain.from_iterable([ctx.models for ctx in ctxs]))

        for m in dirty_models:
            for local_m in local_models:
                if local_m.index_direction == m.index_direction:
                    local_m.index = m.index
                if local_m.x_index_direction == m.index_direction:
                    local_m.x_index = m.index
                if local_m.y_index_direction == m.index_direction:
                    local_m.y_index = m.index
                local_m.dirty = True
            m.dirty = False
        self.update_views()

    def update_views(self):
        self._tab_widget.currentWidget().context.load_data()

    def setup_datasource(self):
        slice_data_source = SliceDataSource(False)
        directions = [SD.inline, SD.crossline, SD.depth]
        for direction in directions:
            slice_data_source.set_indexes(
                direction,
                self._segywidgets[0].slice_data_source.indexes_for_direction(
                    direction))
        return slice_data_source

    def _create_toolbar(self, color_maps):
        toolbar = QToolBar()
        toolbar.setFloatable(False)
        toolbar.setMovable(False)

        self._settings_button = QToolButton()
        self._settings_button.setToolTip("Toggle settings visibility")
        self._settings_button.setIcon(resource_icon("cog.png"))
        self._settings_button.setCheckable(True)
        self._settings_button.toggled.connect(self._show_settings)
        toolbar.addWidget(self._settings_button)

        def toggle_on_close(event):
            self._settings_button.setChecked(False)
            event.accept()

        self._settings_window.closeEvent = toggle_on_close

        return toolbar

    def _show_settings(self, toggled):
        self._settings_window.setVisible(toggled)
        if self._settings_window.isMinimized():
            self._settings_window.showNormal()