[segyio] 44/376: Refactoring. Modularizing viewer
Jørgen Kvalsvik
jokva-guest at moszumanska.debian.org
Wed Sep 20 08:04:05 UTC 2017
This is an automated email from the git hooks/post-receive script.
jokva-guest pushed a commit to branch debian
in repository segyio.
commit 7f518604291b1423a922beb70d2fac7a1a22d3cb
Author: Thorvald Johannessen <thorvjo at statoil.com>
Date: Fri Oct 7 11:39:22 2016 +0200
Refactoring. Modularizing viewer
Classes are renamed and splitted up into seperate files, for easier use outside the example-application segyviewer. I.e to plot slices without QT.
---
applications/segyviewer.py | 385 +++++++---------------------------
examples/CMakeLists.txt | 2 +-
examples/segyviewer.py | 387 -----------------------------------
python/CMakeLists.txt | 3 +-
python/segyview/CMakeLists.txt | 8 +
python/segyview/__init__.py | 10 +
python/segyview/linenavigationbar.py | 50 +++++
python/segyview/segyplot.py | 117 +++++++++++
python/segyview/slicewidget.py | 78 +++++++
9 files changed, 341 insertions(+), 699 deletions(-)
diff --git a/applications/segyviewer.py b/applications/segyviewer.py
index 1ed4170..edb2e07 100755
--- a/applications/segyviewer.py
+++ b/applications/segyviewer.py
@@ -1,12 +1,11 @@
#!/usr/bin/env python
-import segyio
+import sys
-from pylab import *
+import numpy as np
+import segyio
from PyQt4 import QtGui, QtCore
-from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
-from matplotlib.figure import Figure
-import matplotlib.patches as patches
+from segyview import *
class LineSelectionMonitor(QtCore.QObject):
@@ -26,6 +25,7 @@ class LineSelectionMonitor(QtCore.QObject):
def depthUpdated(self, new_index):
self.depthChanged.emit(new_index)
+
class ColorMapMonitor(QtCore.QObject):
cmap_changed = QtCore.pyqtSignal(str)
@@ -36,351 +36,118 @@ class ColorMapMonitor(QtCore.QObject):
self.cmap_changed.emit(str(value))
-class PlaneCanvas(FigureCanvas):
- """
- Generic plot canvas for all plane views
- """
- indexChanged = QtCore.pyqtSignal(int)
-
- def __init__(self, planes, indexes, dataset_title, cmap, x_axis_indexes=None, y_axis_indexes=None,
- display_horizontal_indicator=False,
- display_vertical_indicator=False, parent=None, width=800, height=100, dpi=20, v_min_max=None):
-
- self.fig = Figure(figsize=(width, height), dpi=dpi, facecolor='white')
- FigureCanvas.__init__(self, self.fig)
-
- self.planes = planes
- self.indexes = indexes
-
- if x_axis_indexes:
- self.x_axis_name, self.x_axis_indexes = x_axis_indexes
- else:
- self.x_axis_indexes = None
-
- if y_axis_indexes:
- self.y_axis_name, self.y_axis_indexes = y_axis_indexes
- else:
- self.y_axis_indexes = None
-
-
- self.plane_height = len(self.planes[self.indexes[0]][0])
- self.plane_width = len(self.planes[self.indexes[0]][:])
-
- self.dataset_title = dataset_title
-
- self.setParent(parent)
-
- self.axes = self.fig.add_subplot(111)
- self.axes.tick_params(axis='both', labelsize=30)
-
- if self.x_axis_indexes:
- def x_axis_label_formatter(val, position):
- if val >= 0 and val < len(self.x_axis_indexes):
- return self.x_axis_indexes[int(val)]
- return ''
- self.axes.set_xlabel(self.x_axis_name, fontsize=30)
- self.axes.get_xaxis().set_major_formatter(FuncFormatter(x_axis_label_formatter))
- self.axes.get_xaxis().set_major_locator(MaxNLocator(20)) # max 20 ticks are shown
-
-
- if self.y_axis_indexes:
- def y_axis_label_formatter(val, position):
- if val >= 0 and val < len(self.y_axis_indexes):
- return self.y_axis_indexes[int(val)]
- return ''
-
- self.axes.set_ylabel(self.y_axis_name, fontsize=30)
- self.axes.get_yaxis().set_major_formatter(FuncFormatter(y_axis_label_formatter))
- self.axes.get_yaxis().set_major_locator(MaxNLocator(20)) # max 20 ticks are shown
-
- self.cmap = cmap
-
- self.im = self.axes.imshow(planes[indexes[0]].T,
- interpolation="nearest",
- aspect="auto",
- cmap=self.cmap,
- vmin=v_min_max[0],
- vmax=v_min_max[1])
-
- self.current_index = 0
-
- # connecting matplotlib mouse signals
- self.mpl_connect('motion_notify_event', self.mouse_moved)
- self.mpl_connect('button_press_event', self.mouse_clicked)
- self.mpl_connect('axes_leave_event', self.mouse_left)
-
- if display_vertical_indicator:
- self.verdical_indicator_rect = self.axes.add_patch(
- patches.Rectangle(
- (-0.5, -0.5),
- 1,
- self.plane_height,
- fill=False,
- alpha=1,
- color='black',
- linestyle='--',
- linewidth=2
- )
- )
-
- if display_horizontal_indicator:
- self.horizontal_indicator_rect = self.axes.add_patch(
- patches.Rectangle(
- (-0.5, -0.5),
- self.plane_width,
- 1,
- fill=False,
- alpha=1,
- color='black',
- linestyle='--',
- linewidth=2
- )
- )
-
- self.disabled_overlay = self.axes.add_patch(
- patches.Rectangle(
- (-0.5, -0.5), # (x,y)
- len(self.planes[self.indexes[0]][0]),
- len(self.planes[self.indexes[0]][0]),
- alpha=0.5,
- color='gray',
- visible=False
- )
- )
-
-
- def mouse_left(self, evt):
- # for now do nothing
- # self.set_vertical_line_indicator(self.current_index)
- pass
-
-
- def mouse_clicked(self, evt):
- if evt.inaxes:
- self.current_index = int(evt.xdata)
- self.indexChanged.emit(self.x_axis_indexes[int(evt.xdata)])
-
- def mouse_moved(self, evt):
- # for now do nothing
- # if evt.inaxes:
- # self.set_vertical_line_indicator(int(evt.xdata))
- pass
-
- def set_colormap(self, cmap):
- self.cmap = cmap
- self.im.set_cmap(cmap)
- self.draw()
-
- def update_image(self, index):
- self.im.set_data(self.planes[index].T)
- self.draw()
-
- def set_vertical_line_indicator(self, line_index):
- self.verdical_indicator_rect.set_x(self.x_axis_indexes.index(line_index) - 0.5)
- self.draw()
-
- def set_horizontal_line_indicator(self, line_index):
- self.horizontal_indicator_rect.set_y(self.y_axis_indexes.index(line_index)-0.5)
- self.draw()
-
- def enable_overlay(self):
- self.disabled_overlay.set_visible(True)
- self.draw()
-
- def disable_overlay(self):
- self.disabled_overlay.set_visible(False)
- self.draw()
-
-
-class PlotWidget(QtGui.QWidget):
- """
- Main widget holding the figure and slider
- """
-
- def __init__(self, planes, indexes, dataset_title, default_cmap='seismic',
- x_axis_indexes=None, y_axis_indexes=None,
- show_h_indicator=False, show_v_indicator=False, v_min_max=None):
- super(PlotWidget, self).__init__()
-
- self.planes = planes
- self.indexes = indexes
- self.dataset_title = dataset_title
- self.default_cmap = default_cmap
- self.show_h_indicator = show_h_indicator
- self.show_v_indicator = show_v_indicator
- self.setAutoFillBackground(True)
- p = self.palette()
- p.setColor(self.backgroundRole(), QtCore.Qt.white)
- self.setPalette(p)
-
- self.plotCanvas = PlaneCanvas(self.planes, self.indexes, self.dataset_title, self.default_cmap,
- x_axis_indexes=x_axis_indexes, y_axis_indexes=y_axis_indexes,
- display_horizontal_indicator=self.show_h_indicator,
- display_vertical_indicator=self.show_v_indicator, v_min_max=v_min_max)
-
- self.layout = QtGui.QVBoxLayout(self)
- self.layout.addWidget(self.plotCanvas)
-
- def set_cmap(self, action):
- self.plotCanvas.set_colormap(str(action))
-
- def set_vertical_line_indicator(self, line):
- self.plotCanvas.set_vertical_line_indicator(line)
-
- def set_horizontal_line_indicator(self, line):
- self.plotCanvas.set_horizontal_line_indicator(line)
-
-
-class TopMenu(QtGui.QMenuBar):
- def __init__(self, parent, colormap_monitor):
- super(QtGui.QMenuBar, self).__init__(parent)
-
- self.fileMenu = self.addMenu('&File')
- exitAction = QtGui.QAction('&Exit', self)
- self.fileMenu.addAction(exitAction)
-
- self.viewMenu = self.addMenu('&View')
- self.colormapMenu = self.viewMenu.addMenu("&Colormap")
-
- self.colormap_monitor = colormap_monitor
-
- self.colormap_monitor.cmap_changed.connect(self.set_selected_cmap)
+def configure_main_menu(menu, colormap_monitor, available_colormaps):
+ menu.fileMenu = menu.addMenu('&File')
+ exitAction = QtGui.QAction('&Exit', menu)
+ menu.fileMenu.addAction(exitAction)
- def colormapChanger(color_map_name):
- def performColorMapChange():
- self.colormap_monitor.colormapUpdated(color_map_name)
- return performColorMapChange
+ menu.viewMenu = menu.addMenu('&View')
+ menu.colormapMenu = menu.viewMenu.addMenu("&Colormap")
- for item in ['seismic', 'spectral', 'RdGy', 'hot', 'jet', 'gray']:
- action = self.colormapMenu.addAction(item)
- action.setCheckable(True)
- action.triggered.connect(colormapChanger(item))
-
- def set_selected_cmap(self, cmap_name):
- for item in self.colormapMenu.actions():
+ def set_selected_cmap(cmap_name):
+ for item in menu.colormapMenu.actions():
item.setChecked(str(item.text()) == cmap_name)
+ colormap_monitor.cmap_changed.connect(set_selected_cmap)
-class LineSelector(QtGui.QWidget):
- indexChanged = QtCore.pyqtSignal(int)
-
- def __init__(self, parent, label, indexes, monitor_func):
- super(QtGui.QWidget, self).__init__(parent)
- self.label = label
- self.indexes = indexes
- self.monitor_func = monitor_func
-
- self.layout = QtGui.QHBoxLayout()
- self.slabel = QtGui.QLabel(self.label)
- self.sbox = QtGui.QSpinBox(self)
- self.sbox.setRange(self.indexes[0], self.indexes[-1])
- self.sbox.valueChanged.connect(self.monitor_func)
- self.layout.addWidget(self.slabel)
- self.layout.addWidget(self.sbox)
- self.setLayout(self.layout)
-
- def index_changed(self, val):
- self.indexChanged.emit(val)
+ def colormapChanger(color_map_name):
+ def performColorMapChange():
+ colormap_monitor.colormapUpdated(color_map_name)
- def set_index(self, val):
- self.sbox.blockSignals(True)
- self.sbox.setValue(val)
- self.sbox.blockSignals(False)
+ return performColorMapChange
+ for item in available_colormaps:
+ action = menu.colormapMenu.addAction(item)
+ action.setCheckable(True)
+ action.triggered.connect(colormapChanger(item))
-class ToolBar(QtGui.QToolBar):
- def __init__(self, xline_indexes, iline_indexes, depth_indexes, line_selection_monitor):
- super(ToolBar, self).__init__("")
- self.xline_indexes = xline_indexes
- self.iline_indexes = iline_indexes
- self.depth_indexes = depth_indexes
- self.line_selection_monitor = line_selection_monitor
- # xline
- self.xline_selector = LineSelector(self, "xline", self.xline_indexes, self.line_selection_monitor.xlineUpdated)
- self.line_selection_monitor.xlineChanged.connect(self.xline_selector.set_index)
- self.addWidget(self.xline_selector)
-
- # iline
- self.iline_selector = LineSelector(self, "iline", self.iline_indexes, self.line_selection_monitor.ilineUpdated)
- self.line_selection_monitor.ilineChanged.connect(self.iline_selector.set_index)
- self.addWidget(self.iline_selector)
-
- # iline
- self.depth_selector = LineSelector(self, "depth", self.depth_indexes, self.line_selection_monitor.depthUpdated)
- self.addWidget(self.depth_selector)
-
-
-class AppWindow(QtGui.QMainWindow):
+class SegyViewer(QtGui.QMainWindow):
def __init__(self, s):
QtGui.QMainWindow.__init__(self)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
- self.setWindowTitle("Segy Viewer")
- self.main_widget = QtGui.QWidget(self)
+ self.setWindowTitle("SegyViewer")
+ main_widget = QtGui.QWidget(self)
# signal monitors
colormap_monitor = ColorMapMonitor(self)
line_monitor = LineSelectionMonitor(self)
- self.setMenuBar(TopMenu(self, colormap_monitor))
- self.addToolBar(ToolBar(s.xlines, s.ilines, range(s.samples), line_monitor))
+
+ # menus
+ available_colormaps = ['seismic', 'spectral', 'RdGy', 'hot', 'jet', 'gray']
+ configure_main_menu(self.menuBar(), colormap_monitor, available_colormaps)
+
+
+ self.addToolBar(LineNavigationBar(s.xlines, s.ilines, range(s.samples), line_monitor))
self.statusBar()
- depth_planes, min_max = read_traces_to_memory(s)
+ depth_slices, min_max = read_traces_to_memory(s)
# initialize
- x_plane_canvas = PlotWidget(s.xline, s.xlines, "x-lines", x_axis_indexes=('i-lines', s.ilines),
- show_v_indicator=True, v_min_max=min_max)
- i_plane_canvas = PlotWidget(s.iline, s.ilines, "i-lines", x_axis_indexes=('x-lines', s.xlines),
- show_v_indicator=True, v_min_max=min_max)
- depth_plane_canvas = PlotWidget(depth_planes, range(s.samples), "depth", x_axis_indexes=('i-lines', s.ilines),
- y_axis_indexes=('x-lines', s.xlines),
- show_v_indicator=True, show_h_indicator=True, v_min_max=min_max)
+ x_slice_widget = SliceWidget(s.xline, s.xlines,
+ x_axis_indexes=('i-lines', s.ilines.tolist()),
+ y_axis_indexes=('depth', range(s.samples)),
+ show_v_indicator=True,
+ v_min_max=min_max)
+ i_slice_widget = SliceWidget(s.iline, s.ilines,
+ x_axis_indexes=('x-lines', s.xlines.tolist()),
+ y_axis_indexes=('depth', range(s.samples)),
+ show_v_indicator=True,
+ v_min_max=min_max)
+ depth_slice_widget = SliceWidget(depth_slices, range(s.samples),
+ x_axis_indexes=('i-lines', s.ilines.tolist()),
+ y_axis_indexes=('x-lines', s.xlines.tolist()),
+ show_v_indicator=True,
+ show_h_indicator=True,
+ v_min_max=min_max)
# attach signals
- x_plane_canvas.plotCanvas.indexChanged.connect(line_monitor.ilineUpdated)
- i_plane_canvas.plotCanvas.indexChanged.connect(line_monitor.xlineUpdated)
+ x_slice_widget.indexChanged.connect(line_monitor.ilineUpdated)
+ i_slice_widget.indexChanged.connect(line_monitor.xlineUpdated)
- line_monitor.ilineChanged.connect(x_plane_canvas.set_vertical_line_indicator)
- line_monitor.ilineChanged.connect(depth_plane_canvas.set_vertical_line_indicator)
- line_monitor.ilineChanged.connect(i_plane_canvas.plotCanvas.update_image)
+ line_monitor.ilineChanged.connect(x_slice_widget.set_vertical_line_indicator)
+ line_monitor.ilineChanged.connect(depth_slice_widget.set_vertical_line_indicator)
+ line_monitor.ilineChanged.connect(i_slice_widget.update_image)
- line_monitor.xlineChanged.connect(i_plane_canvas.set_vertical_line_indicator)
- line_monitor.xlineChanged.connect(depth_plane_canvas.set_horizontal_line_indicator)
- line_monitor.xlineChanged.connect(x_plane_canvas.plotCanvas.update_image)
+ line_monitor.xlineChanged.connect(i_slice_widget.set_vertical_line_indicator)
+ line_monitor.xlineChanged.connect(depth_slice_widget.set_horizontal_line_indicator)
+ line_monitor.xlineChanged.connect(x_slice_widget.update_image)
- line_monitor.depthChanged.connect(depth_plane_canvas.plotCanvas.update_image)
+ line_monitor.depthChanged.connect(depth_slice_widget.update_image)
# colormap signals
- colormap_monitor.cmap_changed.connect(x_plane_canvas.set_cmap)
- colormap_monitor.cmap_changed.connect(i_plane_canvas.set_cmap)
- colormap_monitor.cmap_changed.connect(depth_plane_canvas.set_cmap)
+ colormap_monitor.cmap_changed.connect(x_slice_widget.set_cmap)
+ colormap_monitor.cmap_changed.connect(i_slice_widget.set_cmap)
+ colormap_monitor.cmap_changed.connect(depth_slice_widget.set_cmap)
# layout
- xdock = QtGui.QDockWidget("x-lines")
+ xdock = QtGui.QDockWidget("x-line")
xdock.setFeatures(QtGui.QDockWidget.DockWidgetFloatable | QtGui.QDockWidget.DockWidgetMovable)
- xdock.setWidget(x_plane_canvas)
+ xdock.setWidget(x_slice_widget)
- idock = QtGui.QDockWidget("i-lines")
+ idock = QtGui.QDockWidget("i-line")
idock.setFeatures(QtGui.QDockWidget.DockWidgetFloatable | QtGui.QDockWidget.DockWidgetMovable)
- idock.setWidget(i_plane_canvas)
+ idock.setWidget(i_slice_widget)
- ddock = QtGui.QDockWidget("depth plane")
+ ddock = QtGui.QDockWidget("depth slice")
ddock.setFeatures(QtGui.QDockWidget.DockWidgetFloatable | QtGui.QDockWidget.DockWidgetMovable)
- ddock.setWidget(depth_plane_canvas)
+ ddock.setWidget(depth_slice_widget)
self.setDockOptions(QtGui.QMainWindow.AllowNestedDocks)
self.addDockWidget(QtCore.Qt.TopDockWidgetArea, xdock)
self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, idock)
self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, ddock)
- self.main_widget.setFocus()
- self.setCentralWidget(self.main_widget)
- self.main_widget.hide()
+ main_widget.setFocus()
+ self.setCentralWidget(main_widget)
+ main_widget.hide()
def read_traces_to_memory(segy):
- ''' read all samples into memory and identify min and max'''
+ ''' read all samples into memory and identify min and max. A temporary utility method to handle the
+ challenge of navigating up and down in depth slices. As each depth slice consist of samples from all traces in
+ the file '''
all_traces = np.empty(shape=((len(segy.ilines) * len(segy.xlines)), segy.samples), dtype=np.float32)
min_value = sys.float_info.max
@@ -405,17 +172,15 @@ def read_traces_to_memory(segy):
return transposed_traces, (min_value, max_value)
-
-
def main():
if len(sys.argv) < 2:
- sys.exit("Usage: segyviewer.py [file]")
+ sys.exit("Usage: view.py [file]")
filename = sys.argv[1]
with segyio.open(filename, "r") as s:
qApp = QtGui.QApplication(sys.argv)
- aw = AppWindow(s)
+ aw = SegyViewer(s)
aw.show()
sys.exit(qApp.exec_())
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 9eca648..ee72a57 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,5 +1,5 @@
configure_file(../tests/test-data/small.sgy test-data/small.sgy COPYONLY)
-configure_file(segyviewer.py segyviewer.py COPYONLY)
+
add_python_example(python.examples.about about.py test-data/small.sgy INLINE_3D CROSSLINE_3D)
add_python_example(python.examples.write write.py test-data/small.sgy)
diff --git a/examples/segyviewer.py b/examples/segyviewer.py
deleted file mode 100644
index 679e819..0000000
--- a/examples/segyviewer.py
+++ /dev/null
@@ -1,387 +0,0 @@
-import segyio
-
-from pylab import *
-
-from PyQt4 import QtGui, QtCore
-
-from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
-from matplotlib.figure import Figure
-import matplotlib.patches as patches
-
-
-class LineSelectionMonitor(QtCore.QObject):
- ilineChanged = QtCore.pyqtSignal(int)
- xlineChanged = QtCore.pyqtSignal(int)
- depthChanged = QtCore.pyqtSignal(int)
-
- def __init__(self, parent):
- QtCore.QObject.__init__(self, parent)
-
- def ilineUpdated(self, new_index):
- self.ilineChanged.emit(new_index)
-
- def xlineUpdated(self, new_index):
- self.xlineChanged.emit(new_index)
-
- def depthUpdated(self, new_index):
- self.depthChanged.emit(new_index)
-
-class ColorMapMonitor(QtCore.QObject):
- cmap_changed = QtCore.pyqtSignal(str)
-
- def __init__(self, parent=None):
- QtCore.QObject.__init__(self, parent)
-
- def colormapUpdated(self, value):
- self.cmap_changed.emit(str(value))
-
-
-class PlaneCanvas(FigureCanvas):
- """
- Generic plot canvas for all plane views
- """
- indexChanged = QtCore.pyqtSignal(int)
-
- def __init__(self, planes, indexes, axis_indexes, dataset_title, cmap, display_horizontal_indicator=False,
- display_vertical_indicator=False, parent=None, width=800, height=100, dpi=20, v_min_max=None):
-
- self.planes = planes
- self.indexes = indexes
- self.x_axis_indexes, self.y_axis_indexes = axis_indexes[0], axis_indexes[1]
-
- self.dataset_title = dataset_title
-
- self.fig = Figure(figsize=(width, height), dpi=dpi, facecolor='white')
- FigureCanvas.__init__(self, self.fig)
-
- self.setParent(parent)
-
- self.axes = self.fig.add_subplot(111)
-
- self.axes.tick_params(labelsize=30)
-
- # the default colormap
- self.cmap = cmap
-
- self.im = self.axes.imshow(planes[indexes[0]].T, interpolation="nearest", aspect="auto", cmap=self.cmap, vmin=v_min_max[0], vmax=v_min_max[1])
-
- self.current_index = 0
-
- # connecting matplotlib mouse signals
- self.mpl_connect('motion_notify_event', self.mouse_moved)
- self.mpl_connect('button_press_event', self.mouse_clicked)
- self.mpl_connect('axes_leave_event', self.mouse_left)
-
- if display_vertical_indicator:
- self.verdical_indicator_rect = self.axes.add_patch(
- patches.Rectangle(
- (-0.5, 0), # (x,y)
- 1, # width - bredde er pr dot ikke pixel...
- len(self.planes[self.indexes[0]][0]), # height / depth
- fill=False,
- alpha=1,
- color='black',
- linestyle='--',
- linewidth=2
- )
- )
-
- if display_horizontal_indicator:
- self.horizontal_indicator_rect = self.axes.add_patch(
- patches.Rectangle(
- (-0.5, 0),
- len(self.planes[self.indexes[0]][0]),
- 1,
- fill=False,
- alpha=1,
- color='black',
- linestyle='--',
- linewidth=2
- )
- )
-
- self.disabled_overlay = self.axes.add_patch(
- patches.Rectangle(
- (-0.5, 0), # (x,y)
- len(self.planes[self.indexes[0]][0]),
- len(self.planes[self.indexes[0]][0]),
- alpha=0.5,
- color='gray',
- visible=False
- )
- )
-
-
- def mouse_left(self, evt):
- # for now do nothing
- # self.set_vertical_line_indicator(self.current_index)
- pass
-
-
- def mouse_clicked(self, evt):
- if evt.inaxes:
- self.current_index = int(evt.xdata)
- self.indexChanged.emit(self.x_axis_indexes[int(evt.xdata)])
-
- def mouse_moved(self, evt):
-
- # if evt.inaxes:
- # self.set_vertical_line_indicator(int(evt.xdata))
- pass
-
- def set_colormap(self, cmap):
- self.cmap = cmap
- self.im.set_cmap(cmap)
- self.draw()
-
- def update_image(self, index):
- self.im.set_data(self.planes[index].T)
- self.draw()
-
- def set_vertical_line_indicator(self, line_index):
- self.verdical_indicator_rect.set_x(self.x_axis_indexes.index(line_index) - 0.5)
- self.verdical_indicator_rect.set_y(0)
- self.draw()
-
- def set_horizontal_line_indicator(self, line_index):
- self.horizontal_indicator_rect.set_x(-0.5)
-
- self.horizontal_indicator_rect.set_y(self.y_axis_indexes.index(line_index))
- self.draw()
-
- def enable_overlay(self):
- self.disabled_overlay.set_visible(True)
- self.draw()
-
- def disable_overlay(self):
- self.disabled_overlay.set_visible(False)
- self.draw()
-
-
-class PlotWidget(QtGui.QWidget):
- """
- Main widget holding the figure and slider
- """
-
- def __init__(self, planes, indexes, axis_indexes, dataset_title, default_cmap='seismic',
- show_h_indicator=False, show_v_indicator=False, v_min_max=None):
- super(PlotWidget, self).__init__()
-
- self.planes = planes
- self.indexes = indexes
- self.dataset_title = dataset_title
- self.default_cmap = default_cmap
- self.show_h_indicator = show_h_indicator
- self.show_v_indicator = show_v_indicator
- self.setAutoFillBackground(True)
- p = self.palette()
- p.setColor(self.backgroundRole(), QtCore.Qt.white)
- self.setPalette(p)
-
-
- self.plotCanvas = PlaneCanvas(self.planes, self.indexes, axis_indexes, self.dataset_title, self.default_cmap,
- display_horizontal_indicator=self.show_h_indicator,
- display_vertical_indicator=self.show_v_indicator, v_min_max=v_min_max)
-
- self.layout = QtGui.QVBoxLayout(self)
- self.layout.addWidget(self.plotCanvas)
-
- def set_cmap(self, action):
- self.plotCanvas.set_colormap(str(action))
-
- def set_vertical_line_indicator(self, line):
- self.plotCanvas.set_vertical_line_indicator(line)
-
- def set_horizontal_line_indicator(self, line):
- self.plotCanvas.set_horizontal_line_indicator(line)
-
-
-class TopMenu(QtGui.QMenuBar):
- def __init__(self, parent, colormap_monitor):
- super(QtGui.QMenuBar, self).__init__(parent)
-
- self.fileMenu = self.addMenu('&File')
- exitAction = QtGui.QAction('&Exit', self)
- self.fileMenu.addAction(exitAction)
-
- self.viewMenu = self.addMenu('&View')
- self.colormapMenu = self.viewMenu.addMenu("&Colormap")
-
- self.colormap_monitor = colormap_monitor
-
- self.colormap_monitor.cmap_changed.connect(self.set_selected_cmap)
-
- def colormapChanger(color_map_name):
- def performColorMapChange():
- self.colormap_monitor.colormapUpdated(color_map_name)
- return performColorMapChange
-
- for item in ['seismic', 'spectral', 'RdGy', 'hot', 'jet', 'gray']:
- action = self.colormapMenu.addAction(item)
- action.setCheckable(True)
- action.triggered.connect(colormapChanger(item))
-
- def set_selected_cmap(self, cmap_name):
- for item in self.colormapMenu.actions():
- item.setChecked(str(item.text()) == cmap_name)
-
-
-class LineSelector(QtGui.QWidget):
- indexChanged = QtCore.pyqtSignal(int)
-
- def __init__(self, parent, label, indexes, monitor_func):
- super(QtGui.QWidget, self).__init__(parent)
- self.label = label
- self.indexes = indexes
- self.monitor_func = monitor_func
-
- self.layout = QtGui.QHBoxLayout()
- self.slabel = QtGui.QLabel(self.label)
- self.sbox = QtGui.QSpinBox(self)
- self.sbox.setRange(self.indexes[0], self.indexes[-1])
- self.sbox.valueChanged.connect(self.monitor_func)
- self.layout.addWidget(self.slabel)
- self.layout.addWidget(self.sbox)
- self.setLayout(self.layout)
-
- def index_changed(self, val):
- self.indexChanged.emit(val)
-
- def set_index(self, val):
- self.sbox.blockSignals(True)
- self.sbox.setValue(val)
- self.sbox.blockSignals(False)
-
-
-class ToolBar(QtGui.QToolBar):
- def __init__(self, xline_indexes, iline_indexes, depth_indexes, line_selection_monitor):
- super(ToolBar, self).__init__("")
- self.xline_indexes = xline_indexes
- self.iline_indexes = iline_indexes
- self.depth_indexes = depth_indexes
- self.line_selection_monitor = line_selection_monitor
-
- # xline
- self.xline_selector = LineSelector(self, "xline", self.xline_indexes, self.line_selection_monitor.xlineUpdated)
- self.line_selection_monitor.xlineChanged.connect(self.xline_selector.set_index)
- self.addWidget(self.xline_selector)
-
- # iline
- self.iline_selector = LineSelector(self, "iline", self.iline_indexes, self.line_selection_monitor.ilineUpdated)
- self.line_selection_monitor.ilineChanged.connect(self.iline_selector.set_index)
- self.addWidget(self.iline_selector)
-
- # iline
- self.depth_selector = LineSelector(self, "depth", self.depth_indexes, self.line_selection_monitor.depthUpdated)
- self.addWidget(self.depth_selector)
-
-
-class AppWindow(QtGui.QMainWindow):
- def __init__(self, s):
- QtGui.QMainWindow.__init__(self)
- self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
- self.setWindowTitle("Segy Viewer")
- self.main_widget = QtGui.QWidget(self)
-
- # signal monitors
- colormap_monitor = ColorMapMonitor(self)
- line_monitor = LineSelectionMonitor(self)
-
- self.setMenuBar(TopMenu(self, colormap_monitor))
- self.addToolBar(ToolBar(s.xlines, s.ilines, range(s.samples), line_monitor))
- self.statusBar()
-
- depth_planes, min_max = read_traces_to_memory(s)
-
- # initialize
- x_plane_canvas = PlotWidget(s.xline, s.xlines, (s.ilines, 0), "xlines", show_v_indicator=True, v_min_max=min_max)
- i_plane_canvas = PlotWidget(s.iline, s.ilines, (s.xlines, 0), "ilines", show_v_indicator=True, v_min_max=min_max)
- depth_plane_canvas = PlotWidget(depth_planes, range(s.samples), (s.xlines, s.ilines), "depth",
- show_v_indicator=True, show_h_indicator=True, v_min_max=min_max)
-
- # attach signals
- x_plane_canvas.plotCanvas.indexChanged.connect(line_monitor.ilineUpdated)
- i_plane_canvas.plotCanvas.indexChanged.connect(line_monitor.xlineUpdated)
-
- line_monitor.ilineChanged.connect(x_plane_canvas.set_vertical_line_indicator)
- line_monitor.ilineChanged.connect(depth_plane_canvas.set_horizontal_line_indicator)
- line_monitor.ilineChanged.connect(i_plane_canvas.plotCanvas.update_image)
-
- line_monitor.xlineChanged.connect(i_plane_canvas.set_vertical_line_indicator)
- line_monitor.xlineChanged.connect(depth_plane_canvas.set_vertical_line_indicator)
- line_monitor.xlineChanged.connect(x_plane_canvas.plotCanvas.update_image)
-
- line_monitor.depthChanged.connect(depth_plane_canvas.plotCanvas.update_image)
-
- # colormap signals
- colormap_monitor.cmap_changed.connect(x_plane_canvas.set_cmap)
- colormap_monitor.cmap_changed.connect(i_plane_canvas.set_cmap)
- colormap_monitor.cmap_changed.connect(depth_plane_canvas.set_cmap)
-
- # layout
- xdock = QtGui.QDockWidget("x-lines")
- xdock.setFeatures(QtGui.QDockWidget.DockWidgetFloatable | QtGui.QDockWidget.DockWidgetMovable)
- xdock.setWidget(x_plane_canvas)
-
- idock = QtGui.QDockWidget("i-lines")
- idock.setFeatures(QtGui.QDockWidget.DockWidgetFloatable | QtGui.QDockWidget.DockWidgetMovable)
- idock.setWidget(i_plane_canvas)
-
- ddock = QtGui.QDockWidget("depth plane")
- ddock.setFeatures(QtGui.QDockWidget.DockWidgetFloatable | QtGui.QDockWidget.DockWidgetMovable)
- ddock.setWidget(depth_plane_canvas)
-
- self.setDockOptions(QtGui.QMainWindow.AllowNestedDocks)
- self.addDockWidget(QtCore.Qt.TopDockWidgetArea, xdock)
- self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, idock)
- self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, ddock)
-
- self.main_widget.setFocus()
- self.setCentralWidget(self.main_widget)
- self.main_widget.hide()
-
-
-def read_traces_to_memory(segy):
- ''' read all samples into memory and identify min and max'''
-
- all_traces = np.empty(shape=((len(segy.ilines) * len(segy.xlines)), segy.samples), dtype=np.float32)
-
- min_value = sys.float_info.max
- max_value = sys.float_info.min
-
- for i, t in enumerate(segy.trace):
- all_traces[i] = t
-
- local_min = np.nanmin(t)
- local_max = np.nanmax(t)
-
- if np.isfinite(local_min):
- min_value = min(local_min, min_value)
-
- if np.isfinite(local_max):
- max_value = max(local_max, max_value)
-
- all_traces2 = all_traces.reshape(len(segy.ilines), len(segy.xlines), segy.samples)
-
- transposed_traces = all_traces2.transpose(2, 0, 1)
-
- return transposed_traces, (min_value,max_value)
-
-
-
-
-def main():
- if len(sys.argv) < 2:
- sys.exit("Usage: segyviewer.py [file]")
-
- filename = sys.argv[1]
-
- with segyio.open(filename, "r") as s:
- qApp = QtGui.QApplication(sys.argv)
- aw = AppWindow(s)
- aw.show()
- sys.exit(qApp.exec_())
-
-
-if __name__ == '__main__':
- main()
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index bfaa4bb..d857a01 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -30,4 +30,5 @@ if (PYTHONLIBS_FOUND)
$<TARGET_FILE:_segyio> ${CMAKE_BINARY_DIR}/python/segyio/_segyio.so)
endif ()
-add_subdirectory(segyio)
\ No newline at end of file
+add_subdirectory(segyio)
+add_subdirectory(segyview)
diff --git a/python/segyview/CMakeLists.txt b/python/segyview/CMakeLists.txt
new file mode 100644
index 0000000..2b157d1
--- /dev/null
+++ b/python/segyview/CMakeLists.txt
@@ -0,0 +1,8 @@
+set(PYTHON_SOURCES
+ __init__.py
+ linenavigationbar.py
+ segyplot.py
+ slicewidget.py
+ )
+
+add_python_package(segyview segyview "${PYTHON_SOURCES}")
diff --git a/python/segyview/__init__.py b/python/segyview/__init__.py
new file mode 100644
index 0000000..640d109
--- /dev/null
+++ b/python/segyview/__init__.py
@@ -0,0 +1,10 @@
+from .segyplot import SegyPlot
+
+try:
+ from .linenavigationbar import LineNavigationBar
+ from .slicewidget import SliceWidget
+except ImportError as e:
+ import sys
+ import traceback
+ exc_type, exc_value, exc_traceback = sys.exc_info()
+ traceback.print_exception(exc_type, exc_value, exc_traceback, limit=2, file=sys.stderr)
diff --git a/python/segyview/linenavigationbar.py b/python/segyview/linenavigationbar.py
new file mode 100644
index 0000000..76cfb6c
--- /dev/null
+++ b/python/segyview/linenavigationbar.py
@@ -0,0 +1,50 @@
+from PyQt4 import QtGui, QtCore
+
+
+class LineSelector(QtGui.QWidget):
+ indexChanged = QtCore.pyqtSignal(int)
+
+ def __init__(self, parent, label, indexes, monitor_func):
+ super(QtGui.QWidget, self).__init__(parent)
+ self.label = label
+ self.indexes = indexes
+ self.monitor_func = monitor_func
+
+ self.layout = QtGui.QHBoxLayout()
+ self.slabel = QtGui.QLabel(self.label)
+ self.sbox = QtGui.QSpinBox(self)
+ self.sbox.setRange(self.indexes[0], self.indexes[-1])
+ self.sbox.valueChanged.connect(self.monitor_func)
+ self.layout.addWidget(self.slabel)
+ self.layout.addWidget(self.sbox)
+ self.setLayout(self.layout)
+
+ def index_changed(self, val):
+ self.indexChanged.emit(val)
+
+ def set_index(self, val):
+ self.sbox.blockSignals(True)
+ self.sbox.setValue(val)
+ self.sbox.blockSignals(False)
+
+class LineNavigationBar(QtGui.QToolBar):
+ def __init__(self, xline_indexes, iline_indexes, depth_indexes, line_selection_monitor):
+ super(LineNavigationBar, self).__init__("")
+ self.xline_indexes = xline_indexes
+ self.iline_indexes = iline_indexes
+ self.depth_indexes = depth_indexes
+ self.line_selection_monitor = line_selection_monitor
+
+ # xline
+ self.xline_selector = LineSelector(self, "x-line", self.xline_indexes, self.line_selection_monitor.xlineUpdated)
+ self.line_selection_monitor.xlineChanged.connect(self.xline_selector.set_index)
+ self.addWidget(self.xline_selector)
+
+ # iline
+ self.iline_selector = LineSelector(self, "i-line", self.iline_indexes, self.line_selection_monitor.ilineUpdated)
+ self.line_selection_monitor.ilineChanged.connect(self.iline_selector.set_index)
+ self.addWidget(self.iline_selector)
+
+ # depth
+ self.depth_selector = LineSelector(self, "depth", self.depth_indexes, self.line_selection_monitor.depthUpdated)
+ self.addWidget(self.depth_selector)
diff --git a/python/segyview/segyplot.py b/python/segyview/segyplot.py
new file mode 100644
index 0000000..d579d86
--- /dev/null
+++ b/python/segyview/segyplot.py
@@ -0,0 +1,117 @@
+from matplotlib.ticker import FuncFormatter, MaxNLocator
+import matplotlib.patches as patches
+
+
+class SegyPlot(object):
+
+ """
+ SegyPlot plots a segy slice and line indicators on the provided axes.
+ """
+
+ def __init__(self, slices, indexes, axes, cmap='seismic', x_axis_indexes=None, y_axis_indexes=None,
+ display_horizontal_indicator=False,
+ display_vertical_indicator=False, v_min_max=None):
+
+ self.slices = slices
+ self.indexes = indexes
+ self.cmap = cmap
+
+ self.vmin, self.vmax = v_min_max or (None, None)
+
+ self.plane_height = len(self.slices[self.indexes[0]][0])
+ self.plane_width = len(self.slices[self.indexes[0]][:])
+
+ self.x_axis_name, self.x_axis_indexes = x_axis_indexes or (None, None)
+ self.y_axis_name, self.y_axis_indexes = y_axis_indexes or (None, None)
+
+ self.slice_axes = axes
+ self.slice_axes.tick_params(axis='both', labelsize=30)
+
+ if self.x_axis_indexes is not None:
+ def x_axis_label_formatter(val, position):
+ if 0 <= val < len(self.x_axis_indexes):
+ return self.x_axis_indexes[int(val)]
+ return ''
+
+ self.slice_axes.set_xlabel(self.x_axis_name, fontsize=40)
+ self.slice_axes.get_xaxis().set_major_formatter(FuncFormatter(x_axis_label_formatter))
+ self.slice_axes.get_xaxis().set_major_locator(MaxNLocator(20)) # max 20 ticks are shown
+
+ if self.y_axis_indexes is not None:
+ def y_axis_label_formatter(val, position):
+ if 0 <= val < len(self.y_axis_indexes):
+ return self.y_axis_indexes[int(val)]
+ return ''
+
+ self.slice_axes.set_ylabel(self.y_axis_name, fontsize=40)
+ self.slice_axes.get_yaxis().set_major_formatter(FuncFormatter(y_axis_label_formatter))
+ self.slice_axes.get_yaxis().set_major_locator(MaxNLocator(10)) # max 20 ticks are shown
+
+ self.im = self.slice_axes.imshow(slices[indexes[0]].T,
+ interpolation="nearest",
+ aspect="auto",
+ cmap=self.cmap,
+ vmin=self.vmin,
+ vmax=self.vmax)
+
+ if display_vertical_indicator:
+ self.vertical_indicator_rect = self.slice_axes.add_patch(
+ patches.Rectangle(
+ (-0.5, -0.5),
+ 1,
+ self.plane_height,
+ fill=False,
+ alpha=1,
+ color='black',
+ linestyle='--',
+ linewidth=2
+ )
+ )
+
+ if display_horizontal_indicator:
+ self.horizontal_indicator_rect = self.slice_axes.add_patch(
+ patches.Rectangle(
+ (-0.5, -0.5),
+ self.plane_width,
+ 1,
+ fill=False,
+ alpha=1,
+ color='black',
+ linestyle='--',
+ linewidth=2
+ )
+ )
+
+ self.disabled_overlay = self.slice_axes.add_patch(
+ patches.Rectangle(
+ (-0.5, -0.5), # (x,y)
+ len(self.slices[self.indexes[0]][0]),
+ len(self.slices[self.indexes[0]][0]),
+ alpha=0.5,
+ color='gray',
+ visible=False
+ )
+ )
+
+ def set_colormap(self, cmap):
+ self.cmap = cmap
+ self.im.set_cmap(cmap)
+
+ def update_image(self, index):
+ self.im.set_data(self.slices[index].T)
+
+ def set_vertical_line_indicator(self, line_index):
+ if self.x_axis_indexes is not None:
+ self.vertical_indicator_rect.set_x(self.x_axis_indexes.index(line_index) - 0.5)
+
+ def set_horizontal_line_indicator(self, line_index):
+ if self.y_axis_indexes is not None:
+ line_index = self.y_axis_indexes.index(line_index)
+ self.horizontal_indicator_rect.set_y(line_index - 0.5)
+
+ def enable_overlay(self):
+ self.disabled_overlay.set_visible(True)
+
+ def disable_overlay(self):
+ self.disabled_overlay.set_visible(False)
+
diff --git a/python/segyview/slicewidget.py b/python/segyview/slicewidget.py
new file mode 100644
index 0000000..1d21e05
--- /dev/null
+++ b/python/segyview/slicewidget.py
@@ -0,0 +1,78 @@
+from PyQt4 import QtGui, QtCore
+
+from segyplot import SegyPlot
+from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
+from matplotlib.figure import Figure
+
+
+class SliceWidget(QtGui.QWidget):
+ """
+ Main widget holding the slice matplotlib Figure wrapped in FigureCanvasQTAgg.
+ """
+ indexChanged = QtCore.pyqtSignal(int)
+
+ def __init__(self, slices, indexes, dataset_title=None, default_cmap='seismic',
+ x_axis_indexes=None, y_axis_indexes=None,
+ show_h_indicator=False, show_v_indicator=False, v_min_max=None):
+ super(SliceWidget, self).__init__()
+
+ self.slices = slices
+ self.indexes = indexes
+
+ self.x_axis_name, self.x_axis_indexes = x_axis_indexes or (None, None)
+ self.y_axis_name, self.y_axis_indexes = y_axis_indexes or (None, None)
+
+ self.default_cmap = default_cmap
+
+ self.show_h_indicator = show_h_indicator
+ self.show_v_indicator = show_v_indicator
+
+ self.palette().setColor(self.backgroundRole(), QtCore.Qt.white)
+
+ self.current_index = 0
+
+ # setting up the figure and canvas
+ self.figure = Figure(figsize=(800, 200), dpi=20, facecolor='white')
+
+ self.axes = self.figure.add_subplot(111)
+
+ self.segy_plot = SegyPlot(self.slices, self.indexes, self.axes, self.default_cmap,
+ x_axis_indexes=x_axis_indexes, y_axis_indexes=y_axis_indexes,
+ display_horizontal_indicator=self.show_h_indicator,
+ display_vertical_indicator=self.show_v_indicator, v_min_max=v_min_max)
+
+ self.figure_canvas = FigureCanvas(self.figure)
+ self.figure_canvas.setParent(self)
+
+ # connect to mouse click events
+ self.figure_canvas.mpl_connect('button_press_event', self._mouse_clicked)
+
+ # widget layout
+ self.layout = QtGui.QVBoxLayout(self)
+ self.layout.addWidget(self.figure_canvas)
+
+ def _mouse_clicked(self, evt):
+ if evt.inaxes is not None:
+ self.current_index = int(evt.xdata)
+ self._signal_index_change(self.current_index)
+
+ def _signal_index_change(self, x):
+ if self.x_axis_indexes is not None:
+ self.index_changed.emit(self.x_axis_indexes[x])
+
+
+ def update_image(self, index):
+ self.segy_plot.update_image(index)
+ self.figure_canvas.draw()
+
+ def set_cmap(self, action):
+ self.segy_plot.set_colormap(str(action))
+ self.figure_canvas.draw()
+
+ def set_vertical_line_indicator(self, line):
+ self.segy_plot.set_vertical_line_indicator(line)
+ self.figure_canvas.draw()
+
+ def set_horizontal_line_indicator(self, line):
+ self.segy_plot.set_horizontal_line_indicator(line)
+ self.figure_canvas.draw()
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/segyio.git
More information about the debian-science-commits
mailing list