mirror of
https://github.com/fatiando/moulder.git
synced 2025-12-21 10:31:09 +08:00
Initial Commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
*.pyc
|
||||||
0
__init__.py
Normal file
0
__init__.py
Normal file
95
figure_canvas.py
Normal file
95
figure_canvas.py
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
from future.builtins import super
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import numpy
|
||||||
|
import matplotlib
|
||||||
|
from matplotlib.figure import Figure
|
||||||
|
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
|
||||||
|
from PyQt5.QtGui import QIcon
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
from PyQt5.QtWidgets import QSizePolicy, QMainWindow, QApplication, QAction
|
||||||
|
from PyQt5.QtWidgets import QMenu, QWidget, QVBoxLayout, QMessageBox
|
||||||
|
from PyQt5.QtWidgets import QSlider, QHBoxLayout, QLabel, QDialog
|
||||||
|
from PyQt5.QtWidgets import QDialogButtonBox
|
||||||
|
|
||||||
|
|
||||||
|
class GravityModelCanvas(FigureCanvasQTAgg):
|
||||||
|
|
||||||
|
def __init__(self, parent=None, width=5, height=4, dpi=100):
|
||||||
|
self.fig = Figure(figsize=(width, height), dpi=dpi)
|
||||||
|
super().__init__(self.fig)
|
||||||
|
self.setParent(parent)
|
||||||
|
|
||||||
|
self._x, self._z = None, None
|
||||||
|
self._min_depth, self._max_depth = 0., 35000.
|
||||||
|
|
||||||
|
self.predicted = None
|
||||||
|
self.data = None
|
||||||
|
self.polygons = None
|
||||||
|
|
||||||
|
self._plotted = False
|
||||||
|
|
||||||
|
FigureCanvasQTAgg.setSizePolicy(self,
|
||||||
|
QSizePolicy.Expanding,
|
||||||
|
QSizePolicy.Expanding)
|
||||||
|
FigureCanvasQTAgg.updateGeometry(self)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def x(self):
|
||||||
|
return self._x
|
||||||
|
|
||||||
|
@x.setter
|
||||||
|
def x(self, new_value):
|
||||||
|
self._x = new_value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def z(self):
|
||||||
|
return self._z
|
||||||
|
|
||||||
|
@z.setter
|
||||||
|
def z(self, new_value):
|
||||||
|
self._z = new_value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def min_depth(self):
|
||||||
|
return self._min_depth
|
||||||
|
|
||||||
|
@min_depth.setter
|
||||||
|
def min_depth(self, new_value):
|
||||||
|
self._min_depth = new_value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def max_depth(self):
|
||||||
|
return self._max_depth
|
||||||
|
|
||||||
|
@max_depth.setter
|
||||||
|
def max_depth(self, new_value):
|
||||||
|
self._max_depth = new_value
|
||||||
|
|
||||||
|
def update_plot(self):
|
||||||
|
if self._plotted:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self._figure_setup()
|
||||||
|
|
||||||
|
def _figure_setup(self, **kwargs):
|
||||||
|
self.dataax, self.modelax = self.fig.subplots(2, 1, sharex=True)
|
||||||
|
if self.data is not None:
|
||||||
|
self.data_line, = self.dataax.plot(self.x, self.data, '.k')
|
||||||
|
self.dataax.set_ylabel('Gravity anomaly [mGal]')
|
||||||
|
self.dataax.set_xlim(self.x.min(), self.x.max())
|
||||||
|
self.dataax.set_ylim((-200, 200))
|
||||||
|
self.dataax.grid(True)
|
||||||
|
self.modelax.set_xlabel('x [m]')
|
||||||
|
self.modelax.set_xlim(self.x.min(), self.x.max())
|
||||||
|
self.modelax.set_ylim(self.min_depth, self.max_depth)
|
||||||
|
self.modelax.grid(True)
|
||||||
|
self.modelax.invert_yaxis()
|
||||||
|
self.modelax.set_ylabel('z [m]')
|
||||||
|
self.fig.subplots_adjust(top=0.95, left=0.1, right=0.95, bottom=0.1,
|
||||||
|
hspace=0.1)
|
||||||
|
self.figure = self.fig
|
||||||
|
self.canvas = self.fig.canvas
|
||||||
|
self.fig.canvas.draw()
|
||||||
110
moulder.py
Normal file
110
moulder.py
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
from future.builtins import super
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import numpy as np
|
||||||
|
import matplotlib
|
||||||
|
from matplotlib.figure import Figure
|
||||||
|
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
|
||||||
|
from PyQt5.QtGui import QIcon
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
from PyQt5.QtWidgets import QSizePolicy, QMainWindow, QApplication, QAction
|
||||||
|
from PyQt5.QtWidgets import QMenu, QWidget, QVBoxLayout, QMessageBox
|
||||||
|
from PyQt5.QtWidgets import QSlider, QHBoxLayout, QLabel, QDialog
|
||||||
|
from PyQt5.QtWidgets import QDialogButtonBox
|
||||||
|
|
||||||
|
from figure_canvas import GravityModelCanvas
|
||||||
|
from new_dialog import NewModelDialog
|
||||||
|
|
||||||
|
|
||||||
|
class Moulder(QMainWindow):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.setWindowTitle("Moulder")
|
||||||
|
self.setWindowIcon(QIcon.fromTheme('python-logo'))
|
||||||
|
self.setGeometry(200, 200, 1024, 800)
|
||||||
|
self.init_ui()
|
||||||
|
self.set_callbacks()
|
||||||
|
|
||||||
|
self.canvas = GravityModelCanvas(self,
|
||||||
|
width=5, height=4, dpi=100)
|
||||||
|
self.canvas.setFocus()
|
||||||
|
self.setCentralWidget(self.canvas)
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
event.ignore()
|
||||||
|
self._quit_callback()
|
||||||
|
|
||||||
|
def init_ui(self):
|
||||||
|
self._define_actions()
|
||||||
|
self._configure_menubar()
|
||||||
|
self._configure_toolbar()
|
||||||
|
|
||||||
|
def set_callbacks(self):
|
||||||
|
self.new_action.triggered.connect(self._new_model_callback)
|
||||||
|
self.about_action.triggered.connect(self._about_callback)
|
||||||
|
# self.file_menu.triggered.connect(self._file_menu_callback)
|
||||||
|
self.quit_action.triggered.connect(self._quit_callback)
|
||||||
|
|
||||||
|
def _define_actions(self):
|
||||||
|
self.new_action = QAction(QIcon.fromTheme('document-new'),
|
||||||
|
'&New model', self)
|
||||||
|
self.new_action.setShortcut('Ctrl+N')
|
||||||
|
self.open_action = QAction(QIcon.fromTheme('document-open'),
|
||||||
|
'&Open model', self)
|
||||||
|
self.open_action.setShortcut('Ctrl+O')
|
||||||
|
self.save_action = QAction(QIcon.fromTheme('document-save'),
|
||||||
|
'&Save model', self)
|
||||||
|
self.save_action.setShortcut('Ctrl+S')
|
||||||
|
self.save_as_action = QAction(QIcon.fromTheme('document-save-as'),
|
||||||
|
'&Save model as...', self)
|
||||||
|
self.save_as_action.setShortcut('Ctrl+Shift+S')
|
||||||
|
self.quit_action = QAction(QIcon.fromTheme('application-exit'),
|
||||||
|
'&Quit', self)
|
||||||
|
self.quit_action.setShortcut('Ctrl+Q')
|
||||||
|
self.about_action = QAction("&About", self)
|
||||||
|
|
||||||
|
def _configure_menubar(self):
|
||||||
|
self.menubar = self.menuBar()
|
||||||
|
self.file_menu = self.menubar.addMenu('File')
|
||||||
|
self.file_menu.addAction(self.open_action)
|
||||||
|
self.file_menu.addAction(self.save_action)
|
||||||
|
self.file_menu.addAction(self.quit_action)
|
||||||
|
self.about_menu = self.menubar.addMenu('About')
|
||||||
|
self.about_menu.addAction(self.about_action)
|
||||||
|
|
||||||
|
def _configure_toolbar(self):
|
||||||
|
self.toolbar = self.addToolBar("adasd")
|
||||||
|
self.toolbar.addAction(self.new_action)
|
||||||
|
self.toolbar.addAction(self.open_action)
|
||||||
|
self.toolbar.addAction(self.save_action)
|
||||||
|
self.toolbar.addAction(self.save_as_action)
|
||||||
|
|
||||||
|
def _about_callback(self):
|
||||||
|
QMessageBox.about(self, "About Moulder",
|
||||||
|
"About Moulder\nVersion 0.1")
|
||||||
|
|
||||||
|
def _new_model_callback(self):
|
||||||
|
new_model_dialog = NewModelDialog(parent=self)
|
||||||
|
new_model_dialog.exec_()
|
||||||
|
if new_model_dialog.is_completed():
|
||||||
|
self.canvas.x = new_model_dialog.x
|
||||||
|
self.canvas.z = new_model_dialog.z
|
||||||
|
self.canvas.update_plot()
|
||||||
|
|
||||||
|
def _quit_callback(self):
|
||||||
|
answer = QMessageBox.question(self, "Quit",
|
||||||
|
"Are you sure you want to quit?",
|
||||||
|
QMessageBox.Yes, QMessageBox.No)
|
||||||
|
if answer == QMessageBox.Yes:
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
app.setApplicationName("Moulder")
|
||||||
|
moulder = Moulder()
|
||||||
|
moulder.show()
|
||||||
|
sys.exit(app.exec_())
|
||||||
147
new_dialog.py
Normal file
147
new_dialog.py
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
from future.builtins import super
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import numpy
|
||||||
|
import matplotlib
|
||||||
|
from matplotlib.figure import Figure
|
||||||
|
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
|
||||||
|
from PyQt5.QtGui import QIcon, QFont
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
from PyQt5.QtWidgets import QSizePolicy, QMainWindow, QApplication, QAction
|
||||||
|
from PyQt5.QtWidgets import QMenu, QWidget, QVBoxLayout, QMessageBox
|
||||||
|
from PyQt5.QtWidgets import QSlider, QHBoxLayout, QLabel, QDialog, QPushButton
|
||||||
|
from PyQt5.QtWidgets import QDialogButtonBox, QGridLayout, QRadioButton, QLineEdit
|
||||||
|
|
||||||
|
|
||||||
|
class NewModelDialog(QDialog):
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setModal(False)
|
||||||
|
self.setWindowTitle("Create New Model")
|
||||||
|
self._completed = False
|
||||||
|
self._init_ui()
|
||||||
|
|
||||||
|
self.regular_grid_btn.toggled.connect(self._radio_button_callback)
|
||||||
|
self.custom_grid_btn.toggled.connect(self._radio_button_callback)
|
||||||
|
self.cancel_btn.clicked.connect(self._button_pushed_callback)
|
||||||
|
self.ok_btn.clicked.connect(self._button_pushed_callback)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def x(self):
|
||||||
|
if self.regular_grid_btn.isChecked():
|
||||||
|
entries = self._read_regular_grid_entries()
|
||||||
|
if entries:
|
||||||
|
x1, x2, step, z = entries[:]
|
||||||
|
return numpy.arange(x1, x2, step, dtype=numpy.float64)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
elif self.custom_grid_btn.isChecked():
|
||||||
|
# Need to be completed
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def z(self):
|
||||||
|
if self.regular_grid_btn.isChecked():
|
||||||
|
entries = self._read_regular_grid_entries()
|
||||||
|
if entries:
|
||||||
|
x1, x2, step, z = entries[:]
|
||||||
|
return z*numpy.ones_like(self.x)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
elif self.custom_grid_btn.isChecked():
|
||||||
|
# Need to be completed
|
||||||
|
pass
|
||||||
|
|
||||||
|
def is_completed(self):
|
||||||
|
return self._completed
|
||||||
|
|
||||||
|
def _init_ui(self):
|
||||||
|
self.regular_grid_btn = QRadioButton("Regular grid (in meters)")
|
||||||
|
self.regular_grid_btn.setChecked(True)
|
||||||
|
self.custom_grid_btn = QRadioButton("Custom grid")
|
||||||
|
self.from_input = QLineEdit()
|
||||||
|
self.to_input = QLineEdit()
|
||||||
|
self.step_input = QLineEdit()
|
||||||
|
self.height_input = QLineEdit()
|
||||||
|
self.ok_btn = QPushButton("Ok")
|
||||||
|
self.cancel_btn = QPushButton("Cancel")
|
||||||
|
self.ok_btn.setDefault(True)
|
||||||
|
|
||||||
|
bold_font = QFont()
|
||||||
|
bold_font.setBold(True)
|
||||||
|
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
layout.addWidget(QLabel("Create Meassurement Points", font=bold_font))
|
||||||
|
layout.addWidget(self.regular_grid_btn)
|
||||||
|
|
||||||
|
grid = QGridLayout()
|
||||||
|
grid.setContentsMargins(25, 0, 0, 0)
|
||||||
|
grid.addWidget(QLabel("From:"), 0, 0)
|
||||||
|
grid.addWidget(self.from_input, 0, 1)
|
||||||
|
grid.addWidget(QLabel("To:"), 0, 2)
|
||||||
|
grid.addWidget(self.to_input, 0, 3)
|
||||||
|
grid.addWidget(QLabel("Step:"), 0, 4)
|
||||||
|
grid.addWidget(self.step_input, 0, 5)
|
||||||
|
grid.addWidget(QLabel("Height:"), 1, 0)
|
||||||
|
grid.addWidget(self.height_input, 1, 1, 1, 5)
|
||||||
|
layout.addLayout(grid)
|
||||||
|
|
||||||
|
layout.addWidget(self.custom_grid_btn)
|
||||||
|
|
||||||
|
hbox = QHBoxLayout()
|
||||||
|
hbox.setAlignment(Qt.AlignRight)
|
||||||
|
hbox.addWidget(self.cancel_btn)
|
||||||
|
hbox.addWidget(self.ok_btn)
|
||||||
|
layout.addLayout(hbox)
|
||||||
|
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
def _button_pushed_callback(self):
|
||||||
|
sender_text = self.sender().text()
|
||||||
|
if sender_text == "Cancel":
|
||||||
|
self.close()
|
||||||
|
elif sender_text == "Ok":
|
||||||
|
filled_entries = self._check_filled_entries()
|
||||||
|
if filled_entries:
|
||||||
|
self._completed = True
|
||||||
|
self.close()
|
||||||
|
else:
|
||||||
|
QMessageBox.warning(self, "Warning",
|
||||||
|
"Some entries are not properly " +
|
||||||
|
"completed or are incomplete.")
|
||||||
|
|
||||||
|
def _radio_button_callback(self):
|
||||||
|
regular_grid_lines = [self.from_input, self.to_input,
|
||||||
|
self.step_input, self.height_input]
|
||||||
|
if self.sender().text() == "Custom grid":
|
||||||
|
for line_edit in regular_grid_lines:
|
||||||
|
line_edit.setDisabled(True)
|
||||||
|
else:
|
||||||
|
for line_edit in regular_grid_lines:
|
||||||
|
line_edit.setEnabled(True)
|
||||||
|
|
||||||
|
def _check_filled_entries(self):
|
||||||
|
if self.regular_grid_btn.isChecked():
|
||||||
|
entries = self._read_regular_grid_entries()
|
||||||
|
if entries:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
# Show messagebox with warning for not completed entries
|
||||||
|
pass
|
||||||
|
elif self.custom_grid_btn.isChecked():
|
||||||
|
# Needed to be completed
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _read_regular_grid_entries(self):
|
||||||
|
x1, x2 = self.from_input.text(), self.to_input.text()
|
||||||
|
step = self.step_input.text()
|
||||||
|
z = self.height_input.text()
|
||||||
|
try:
|
||||||
|
x1, x2, step = float(x1), float(x2), float(step)
|
||||||
|
z = float(z)
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
return x1, x2, step, z
|
||||||
Reference in New Issue
Block a user