From ded46d45cce39c2ed53d6793f868cb82cab80245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20C=C3=B6kerim?= Date: Sun, 4 Apr 2021 12:21:27 +0200 Subject: [PATCH] GUI starts successfully. Changed imports tu work with pyside2 --- PyLoT.py | 25 ++++--- icons_rc_2.py | 2 +- icons_rc_3.py | 8 +- pylot/core/io/data.py | 14 ++-- pylot/core/util/array_map.py | 141 ++++++++++++++++++++++------------- pylot/core/util/thread.py | 31 +++++--- pylot/core/util/widgets.py | 25 ++++--- 7 files changed, 151 insertions(+), 95 deletions(-) diff --git a/PyLoT.py b/PyLoT.py index 5d85765a..28c0b1a9 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -35,18 +35,18 @@ import traceback import json from datetime import datetime -matplotlib.use('Qt4Agg') -matplotlib.rcParams['backend.qt4'] = 'PySide' -matplotlib.rcParams['savefig.dpi'] = 300 +matplotlib.use('Qt5Agg') +# matplotlib.rcParams['backend.qt4'] = 'PySide' +# matplotlib.rcParams['savefig.dpi'] = 300 - -from PySide import QtGui, QtCore -from PySide.QtCore import QCoreApplication, QSettings, Signal, QFile, \ +from PySide2 import QtGui, QtCore, QtWidgets +from PySide2.QtCore import QCoreApplication, QSettings, Signal, QFile, \ QFileInfo, Qt, QSize -from PySide.QtGui import QMainWindow, QInputDialog, QIcon, QFileDialog, \ - QWidget, QHBoxLayout, QVBoxLayout, QStyle, QKeySequence, QLabel, QFrame, QAction, \ - QDialog, QApplication, QPixmap, QMessageBox, QSplashScreen, \ - QActionGroup, QListWidget, QListView, QAbstractItemView, \ +from PySide2.QtGui import QIcon, QKeySequence, QPixmap +from PySide2.QtWidgets import QMainWindow, QInputDialog, QFileDialog, \ + QWidget, QHBoxLayout, QVBoxLayout, QStyle, QLabel, QFrame, QAction, \ + QDialog, QErrorMessage, QApplication, QMessageBox, QSplashScreen, \ + QActionGroup, QListWidget, QLineEdit, QListView, QAbstractItemView, \ QTreeView, QComboBox, QTabWidget, QPushButton, QGridLayout import numpy as np from obspy import UTCDateTime, Stream @@ -58,9 +58,10 @@ from pylot.core.util.obspyDMT_interface import check_obspydmt_structure import pyqtgraph as pg try: - from matplotlib.backends.backend_qt4agg import FigureCanvas + from matplotlib.backends.backend_qt5agg import FigureCanvas except ImportError: - from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas + from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas +from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar from matplotlib.figure import Figure from pylot.core.analysis.magnitude import LocalMagnitude, MomentMagnitude diff --git a/icons_rc_2.py b/icons_rc_2.py index 9f36b183..31aa67a3 100644 --- a/icons_rc_2.py +++ b/icons_rc_2.py @@ -7,7 +7,7 @@ # # WARNING! All changes made in this file will be lost! -from PySide import QtCore +from PySide2 import QtCore qt_resource_data = "\ \x00\x00\x9e\x04\ diff --git a/icons_rc_3.py b/icons_rc_3.py index 963cf353..3a309944 100644 --- a/icons_rc_3.py +++ b/icons_rc_3.py @@ -7,9 +7,9 @@ # # WARNING! All changes made in this file will be lost! -from PySide import QtCore +from PySide2 import QtCore -qt_resource_data = "\ +qt_resource_data = b"\ \x00\x00\x9e\x04\ \x89\ \x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ @@ -109000,7 +109000,7 @@ qt_resource_data = "\ \x62\x6f\x64\x79\x3e\x0a\x3c\x2f\x68\x74\x6d\x6c\x3e\x0a\ " -qt_resource_name = "\ +qt_resource_name = b"\ \x00\x04\ \x00\x06\xec\x30\ \x00\x68\ @@ -109235,7 +109235,7 @@ qt_resource_name = "\ \x00\x6e\x00\x64\x00\x65\x00\x78\x00\x2e\x00\x68\x00\x74\x00\x6d\x00\x6c\ " -qt_resource_struct = "\ +qt_resource_struct = b"\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x01\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x3a\ \x00\x00\x00\x0e\x00\x02\x00\x00\x00\x35\x00\x00\x00\x05\ diff --git a/pylot/core/io/data.py b/pylot/core/io/data.py index c737eb21..5f7eec2a 100644 --- a/pylot/core/io/data.py +++ b/pylot/core/io/data.py @@ -8,7 +8,7 @@ from obspy.core import read, Stream, UTCDateTime from obspy.core.event import Event as ObsPyEvent from obspy.io.sac import SacIOError -from PySide.QtGui import QMessageBox +from PySide2.QtWidgets import QMessageBox import pylot.core.loc.velest as velest import pylot.core.loc.focmec as focmec @@ -21,14 +21,18 @@ from pylot.core.util.obspyDMT_interface import qml_from_obspyDMT from pylot.core.util.utils import fnConstructor, full_range, check4rotated, \ check4gapsAndMerge, trim_station_components +try: + str_TypeLst = [str, unicode] # if python 2.X +except NameError: + str_TypeLst = [str] # if python 3.* class Data(object): """ Data container with attributes wfdata holding ~obspy.core.stream. - :type parent: PySide.QtGui.QWidget object, optional - :param parent: A PySide.QtGui.QWidget object utilized when - called by a GUI to display a PySide.QtGui.QMessageBox instead of printing + :type parent: PySide2.QtWidgets.QWidget object, optional + :param parent: A PySide2.QtWidgets.QWidget object utilized when + called by a GUI to display a PySide2.QtWidgets.QMessageBox instead of printing to standard out. :type evtdata: ~obspy.core.event.Event object, optional :param evtdata ~obspy.core.event.Event object containing all derived or @@ -48,7 +52,7 @@ class Data(object): elif isinstance(evtdata, dict): evt = readPILOTEvent(**evtdata) evtdata = evt - elif type(evtdata) in [str, unicode]: + elif type(evtdata) in str_TypeLst: try: cat = read_events(evtdata) if len(cat) is not 1: diff --git a/pylot/core/util/array_map.py b/pylot/core/util/array_map.py index b2f3b078..b2eafc6f 100644 --- a/pylot/core/util/array_map.py +++ b/pylot/core/util/array_map.py @@ -6,19 +6,26 @@ import matplotlib.pyplot as plt import numpy as np import obspy import traceback -from PySide import QtGui +from PySide2 import QtWidgets from matplotlib.figure import Figure from mpl_toolkits.axes_grid1.inset_locator import inset_axes -from mpl_toolkits.basemap import Basemap +# from mpl_toolkits.basemap import Basemap from scipy.interpolate import griddata +import cartopy.crs as ccrs +import cartopy.feature as cf +from cartopy.feature import ShapelyFeature +from cartopy.io.shapereader import Reader +from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER + + from pylot.core.util.widgets import PickDlg, PylotCanvas from pylot.core.pick.utils import get_quality_class plt.interactive(False) -class Array_map(QtGui.QWidget): +class Array_map(QtWidgets.QWidget): def __init__(self, parent, metadata, parameter=None, figure=None, annotate=True, pointsize=25., linewidth=1.5, width=5e6, height=2e6): ''' @@ -27,7 +34,7 @@ class Array_map(QtGui.QWidget): :param parameter: object of PyLoT parameter class :param figure: ''' - QtGui.QWidget.__init__(self) + QtWidgets.QWidget.__init__(self) assert (parameter != None or parent != None), 'either parent or parameter has to be set' self._parent = parent self.metadata = metadata @@ -210,7 +217,9 @@ class Array_map(QtGui.QWidget): return x = event.xdata y = event.ydata - lat, lon = self.basemap(x, y, inverse=True) + # lat, lon = self.basemap(x, y, inverse=True) + lat = y + lon = x self.status_label.setText('Latitude: {}, Longitude: {}'.format(lat, lon)) def current_picks_dict(self): @@ -224,43 +233,43 @@ class Array_map(QtGui.QWidget): if not self.figure: self.figure = Figure() - self.status_label = QtGui.QLabel() + self.status_label = QtWidgets.QLabel() self.main_ax = self.figure.add_subplot(111) #self.main_ax.set_facecolor('0.7') self.canvas = PylotCanvas(self.figure, parent=self._parent, multicursor=True, panZoomX=False, panZoomY=False) - self.main_box = QtGui.QVBoxLayout() + self.main_box = QtWidgets.QVBoxLayout() self.setLayout(self.main_box) - self.top_row = QtGui.QHBoxLayout() + self.top_row = QtWidgets.QHBoxLayout() self.main_box.addLayout(self.top_row, 1) - self.comboBox_phase = QtGui.QComboBox() + self.comboBox_phase = QtWidgets.QComboBox() self.comboBox_phase.insertItem(0, 'P') self.comboBox_phase.insertItem(1, 'S') - self.comboBox_am = QtGui.QComboBox() + self.comboBox_am = QtWidgets.QComboBox() self.comboBox_am.insertItem(0, 'hybrid (prefer manual)') self.comboBox_am.insertItem(1, 'manual') self.comboBox_am.insertItem(2, 'auto') - self.annotations_box = QtGui.QCheckBox('Annotate') + self.annotations_box = QtWidgets.QCheckBox('Annotate') self.annotations_box.setChecked(True) - self.auto_refresh_box = QtGui.QCheckBox('Automatic refresh') + self.auto_refresh_box = QtWidgets.QCheckBox('Automatic refresh') self.auto_refresh_box.setChecked(True) - self.refresh_button = QtGui.QPushButton('Refresh') - self.cmaps_box = QtGui.QComboBox() + self.refresh_button = QtWidgets.QPushButton('Refresh') + self.cmaps_box = QtWidgets.QComboBox() self.cmaps_box.setMaxVisibleItems(20) [self.cmaps_box.addItem(map_name) for map_name in sorted(plt.colormaps())] # try to set to hsv as default self.cmaps_box.setCurrentIndex(self.cmaps_box.findText('hsv')) - self.top_row.addWidget(QtGui.QLabel('Select a phase: ')) + self.top_row.addWidget(QtWidgets.QLabel('Select a phase: ')) self.top_row.addWidget(self.comboBox_phase) self.top_row.setStretch(1, 1) # set stretch of item 1 to 1 - self.top_row.addWidget(QtGui.QLabel('Pick type: ')) + self.top_row.addWidget(QtWidgets.QLabel('Pick type: ')) self.top_row.addWidget(self.comboBox_am) self.top_row.setStretch(3, 1) # set stretch of item 1 to 1 self.top_row.addWidget(self.cmaps_box) @@ -332,32 +341,53 @@ class Array_map(QtGui.QWidget): self.xdim = self.get_max_from_stations('x') - self.get_min_from_stations('x') self.ydim = self.get_max_from_stations('y') - self.get_min_from_stations('y') - def init_basemap(self, resolution='l'): - # basemap = Basemap(projection=projection, resolution = resolution, ax=self.main_ax) - basemap = Basemap(projection='lcc', resolution=resolution, ax=self.main_ax, - width=self.width, height=self.height, - lat_0=(self.latmin + self.latmax) / 2., - lon_0=(self.lonmin + self.lonmax) / 2.) + def init_basemap(self): + # initialize cartopy coordinate reference system + proj = ccrs.PlateCarree(central_longitude=(self.lonmin + self.lonmax) / 2.) + crtpy_map = plt.axes(projection=proj) + mapxtent = [self.lonmin, self.lonmax, self.latmin, self.latmax] # add conditional buffer + crtpy_map.set_extent(mapxtent) # find way to directly open zoomed map on area - # basemap.fillcontinents(color=None, lake_color='aqua',zorder=1) - basemap.drawmapboundary(zorder=2) # fill_color='darkblue') - basemap.shadedrelief(zorder=3) - basemap.drawcountries(zorder=4) - basemap.drawstates(zorder=5) - basemap.drawcoastlines(zorder=6) - # labels = [left,right,top,bottom] - parallels = np.arange(-90, 90, 5.) - parallels_small = np.arange(-90, 90, 2.5) - basemap.drawparallels(parallels_small, linewidth=0.5, zorder=7) - basemap.drawparallels(parallels, zorder=7)#, labels=[1, 1, 0, 0]) - meridians = np.arange(-180, 180, 5.) - meridians_small = np.arange(-180, 180, 2.5) - basemap.drawmeridians(meridians_small, linewidth=0.5, zorder=7) - basemap.drawmeridians(meridians, zorder=7)#, labels=[0, 0, 1, 1]) - self.basemap = basemap + # add features (option for plate boundaries) + crtpy_map.add_feature(cf.LAND) # replace with background map + crtpy_map.add_feature(cf.OCEAN) + crtpy_map.add_feature(cf.BORDERS, linestyle=':') # include province borders + crtpy_map.add_feature(cf.COASTLINE) + # fname = 'PB2002_plates.shp' + # plateBoundaries = ShapelyFeature(Reader(fname).geometries(), ccrs.PlateCarree(), facecolor='none', edgecolor='r') + # crtpy_map.add_feature(plateBoundaries) + + # parallels and meridians + gridlines = crtpy_map.gridlines(draw_labels=True, alpha=0.5, zorder=7) + gridlines.xformatter = LONGITUDE_FORMATTER + gridlines.yformatter = LATITUDE_FORMATTER + + self.basemap = crtpy_map self.figure._tight = True self.figure.tight_layout() + # basemap = Basemap(projection=projection, resolution = resolution, ax=self.main_ax) + # basemap = Basemap(projection='lcc', resolution=resolution, ax=self.main_ax, width=self.width, height=self.height, lat_0=(self.latmin + self.latmax) / 2., lon_0=(self.lonmin + self.lonmax) / 2.) + # + # basemap.fillcontinents(color=None, lake_color='aqua',zorder=1) + # basemap.drawmapboundary(zorder=2) # fill_color='darkblue') + # basemap.shadedrelief(zorder=3) + # basemap.drawcountries(zorder=4) + # basemap.drawstates(zorder=5) + # basemap.drawcoastlines(zorder=6) + # labels = [left,right,top,bottom] + # parallels = np.arange(-90, 90, 5.) + # parallels_small = np.arange(-90, 90, 2.5) + # basemap.drawparallels(parallels_small, linewidth=0.5, zorder=7) + # basemap.drawparallels(parallels, zorder=7)#, labels=[1, 1, 0, 0]) + # meridians = np.arange(-180, 180, 5.) + # meridians_small = np.arange(-180, 180, 2.5) + # basemap.drawmeridians(meridians_small, linewidth=0.5, zorder=7) + # basemap.drawmeridians(meridians, zorder=7)#, labels=[0, 0, 1, 1]) + # self.basemap = basemap + # self.figure._tight = True + # self.figure.tight_layout() + def init_lat_lon_grid(self, nstep=250): # create a regular grid to display colormap lataxis = np.linspace(self.latmin, self.latmax, nstep) @@ -408,9 +438,12 @@ class Array_map(QtGui.QWidget): # self.test_gradient() levels = np.linspace(self.get_min_from_picks(), self.get_max_from_picks(), nlevel) - self.contourf = self.basemap.contour(self.longrid, self.latgrid, self.picksgrid_active, levels, - linewidths=self.linewidth, latlon=True, zorder=8, alpha=0.7, - cmap=self.get_colormap()) + # self.contourf = self.basemap.contour(self.longrid, self.latgrid, self.picksgrid_active, levels, + # linewidths=self.linewidth, latlon=True, zorder=8, alpha=0.7, + # cmap=self.get_colormap()) + + plt.contourf(self.longrid, self.latgrid, self.picksgrid_active, levels, linewidths=self.linewidth, + transform=ccrs.PlateCarree(), alpha=0.7, zorder=8) def get_colormap(self): return plt.get_cmap(self.cmaps_box.currentText()) @@ -455,14 +488,18 @@ class Array_map(QtGui.QWidget): def scatter_all_stations(self): stations, lats, lons = self.get_st_lat_lon_for_plot() + #self.sc = self.basemap.scatter(lons, lats, s=self.pointsize, facecolor='none', latlon=True, marker='.', + # zorder=10, picker=True, edgecolor='0.5', label='Not Picked') + self.sc = self.basemap.scatter(lons, lats, s=self.pointsize, facecolor='none', latlon=True, marker='.', - zorder=10, picker=True, edgecolor='0.5', label='Not Picked') + zorder=10, picker=True, edgecolor='0.5', label='Not Picked', transform=ccrs.PlateCarree()) + self.cid = self.canvas.mpl_connect('pick_event', self.onpick) self._station_onpick_ids = stations if self.eventLoc: lats, lons = self.eventLoc self.sc_event = self.basemap.scatter(lons, lats, s=2*self.pointsize, facecolor='red', - latlon=True, zorder=11, label='Event (might be outside map region)') + latlon=True, zorder=11, label='Event (might be outside map region)', transform=ccrs.PlateCarree()) def scatter_picked_stations(self): picks, uncertainties, lats, lons = self.get_picks_lat_lon() @@ -478,13 +515,13 @@ class Array_map(QtGui.QWidget): # workaround because of an issue with latlon transformation of arrays with len <3 if len(lons) <= 2 and len(lats) <= 2: self.sc_picked = self.basemap.scatter(lons[0], lats[0], s=sizes, edgecolors='white', cmap=cmap, - c=picks[0], latlon=True, zorder=11) + c=picks[0], latlon=True, zorder=11, transform=ccrs.PlateCarree()) if len(lons) == 2 and len(lats) == 2: self.sc_picked = self.basemap.scatter(lons[1], lats[1], s=sizes, edgecolors='white', cmap=cmap, - c=picks[1], latlon=True, zorder=11) + c=picks[1], latlon=True, zorder=11, transform=ccrs.PlateCarree()) if len(lons) > 2 and len(lats) > 2: self.sc_picked = self.basemap.scatter(lons, lats, s=sizes, edgecolors='white', cmap=cmap, - c=picks, latlon=True, zorder=11, label='Picked') + c=picks, latlon=True, zorder=11, label='Picked', transform=ccrs.PlateCarree()) def annotate_ax(self): self.annotations = [] @@ -607,8 +644,8 @@ class Array_map(QtGui.QWidget): def zoom(self, event): map = self.basemap - xlim = map.ax.get_xlim() - ylim = map.ax.get_ylim() + xlim = map.get_xlim() + ylim = map.get_ylim() x, y = event.xdata, event.ydata zoom = {'up': 1. / 2., 'down': 2.} @@ -628,11 +665,11 @@ class Array_map(QtGui.QWidget): if xl < map.xmin or yb < map.ymin or xr > map.xmax or yt > map.ymax: xl, xr = map.xmin, map.xmax yb, yt = map.ymin, map.ymax - map.ax.set_xlim(xl, xr) - map.ax.set_ylim(yb, yt) - map.ax.figure.canvas.draw() + map.set_xlim(xl, xr) + map.set_ylim(yb, yt) + map.figure.canvas.draw() def _warn(self, message): - self.qmb = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Warning, + self.qmb = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Icon.Warning, 'Warning', message) self.qmb.show() diff --git a/pylot/core/util/thread.py b/pylot/core/util/thread.py index d5ca3ef4..f2979cb8 100644 --- a/pylot/core/util/thread.py +++ b/pylot/core/util/thread.py @@ -1,11 +1,8 @@ # -*- coding: utf-8 -*- +import sys, os, traceback import multiprocessing -import os -import sys -import traceback - -from PySide.QtCore import QThread, Signal, Qt, Slot, QRunnable, QObject -from PySide.QtGui import QDialog, QProgressBar, QLabel, QHBoxLayout +from PySide2.QtCore import QThread, Signal, Qt, Slot, QRunnable, QObject +from PySide2.QtWidgets import QDialog, QProgressBar, QLabel, QHBoxLayout, QPushButton class Thread(QThread): @@ -49,7 +46,23 @@ class Thread(QThread): # self.pb_widget.setWindowFlags(Qt.SplashScreen) # self.pb_widget.setModal(True) - self.pb_widget.label.setText(self.progressText) + # generate widget if not given in init + if not self.pb_widget: + self.pb_widget = QDialog(self.parent()) + self.pb_widget.setWindowFlags(Qt.SplashScreen) + self.pb_widget.setModal(True) + + # add button + delete_button = QPushButton('X') + delete_button.clicked.connect(self.exit) + hl = QHBoxLayout() + pb = QProgressBar() + pb.setRange(0, 0) + hl.addWidget(pb) + hl.addWidget(QLabel(self.progressText)) + if self.abortButton: + hl.addWidget(delete_button) + self.pb_widget.setLayout(hl) self.pb_widget.show() def hideProgressbar(self): @@ -89,9 +102,9 @@ class Worker(QRunnable): try: result = self.fun(self.args) except: - exctype, value = sys.exc_info()[:2] + exctype, value = sys.exc_info ()[:2] print(exctype, value, traceback.format_exc()) - self.signals.error.emit((exctype, value, traceback.format_exc())) + self.signals.error.emit ((exctype, value, traceback.format_exc ())) else: self.signals.result.emit(result) finally: diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index fd2b4eab..ebee867d 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -22,22 +22,23 @@ matplotlib.use('QT4Agg') from matplotlib.figure import Figure try: - from matplotlib.backends.backend_qt4agg import FigureCanvas + from matplotlib.backends.backend_qt5agg import FigureCanvas except ImportError: - from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas -from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT + from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas +from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT from matplotlib.widgets import MultiCursor from obspy import read -from PySide import QtCore, QtGui -from PySide.QtGui import QAction, QApplication, QCheckBox, QComboBox, \ +from PySide2 import QtCore, QtGui +from PySide2.QtGui import QIcon, QPixmap, QKeySequence +from PySide2.QtWidgets import QAction, QApplication, QCheckBox, QComboBox, \ QDateTimeEdit, QDialog, QDialogButtonBox, QDoubleSpinBox, QGroupBox, \ - QGridLayout, QFormLayout, QIcon, QLabel, QLineEdit, QMessageBox, \ - QPixmap, QSpinBox, QTabWidget, QToolBar, QVBoxLayout, QHBoxLayout, QWidget, \ - QPushButton, QFileDialog, QInputDialog, QKeySequence -from PySide.QtCore import QSettings, Qt, QUrl, Signal -from PySide.QtWebKit import QWebView -from obspy import Stream, Trace, UTCDateTime + QGridLayout, QLabel, QLineEdit, QMessageBox, \ + QSpinBox, QTabWidget, QToolBar, QVBoxLayout, QHBoxLayout, QWidget, \ + QPushButton, QFileDialog, QInputDialog +from PySide2.QtCore import QSettings, Qt, QUrl, Signal, Slot +from PySide2.QtWebEngineWidgets import QWebEngineView as QWebView +from obspy import Stream, UTCDateTime from obspy.core.util import AttribDict from obspy.taup import TauPyModel from obspy.taup.utils import get_phase_names @@ -67,7 +68,7 @@ else: raise ImportError('Could not determine python version.') # workaround to prevent PyCharm from deleting icons_rc import when optimizing imports -icons_rc = icons_rc +# icons_rc = icons_rc def getDataType(parent):