diff --git a/pylot.yml b/pylot.yml new file mode 100644 index 00000000..c7134cd1 --- /dev/null +++ b/pylot.yml @@ -0,0 +1,118 @@ +name: pylot_py35 +channels: + - conda-forge + - defaults +dependencies: + - _libgcc_mutex=0.1=conda_forge + - _openmp_mutex=4.5=1_gnu + - brotlipy=0.7.0=py36h8f6f2f9_1001 + - c-ares=1.17.1=h7f98852_1 + - ca-certificates=2021.5.30=ha878542_0 + - cartopy=0.18.0=py36h104b3a8_13 + - certifi=2021.5.30=py36h5fab9bb_0 + - cffi=1.14.5=py36hc120d54_0 + - chardet=4.0.0=py36h5fab9bb_1 + - cryptography=3.4.6=py36hb60f036_0 + - cycler=0.10.0=py_2 + - dbus=1.13.6=hfdff14a_1 + - decorator=4.4.2=py_0 + - expat=2.2.10=h9c3ff4c_0 + - fontconfig=2.13.1=hba837de_1004 + - freetype=2.10.4=h0708190_1 + - future=0.18.2=py36h5fab9bb_3 + - geos=3.9.1=h9c3ff4c_2 + - gettext=0.19.8.1=h0b5b191_1005 + - glib=2.68.0=h9c3ff4c_1 + - glib-tools=2.68.0=h9c3ff4c_1 + - greenlet=1.0.0=py36hc4f0c31_0 + - gst-plugins-base=1.18.4=h29181c9_0 + - gstreamer=1.18.4=h76c114f_0 + - icu=68.1=h58526e2_0 + - idna=2.10=pyh9f0ad1d_0 + - importlib-metadata=3.7.3=py36h5fab9bb_0 + - jpeg=9d=h36c2ea0_0 + - kiwisolver=1.3.1=py36h605e78d_1 + - krb5=1.17.2=h926e7f8_0 + - lcms2=2.12=hddcbb42_0 + - ld_impl_linux-64=2.35.1=hea4e1c9_2 + - libblas=3.9.0=8_openblas + - libcblas=3.9.0=8_openblas + - libclang=11.1.0=default_ha53f305_0 + - libcurl=7.75.0=hc4aaa36_0 + - libedit=3.1.20191231=he28a2e2_2 + - libev=4.33=h516909a_1 + - libevent=2.1.10=hcdb4288_3 + - libffi=3.3=h58526e2_2 + - libgcc-ng=9.3.0=h2828fa1_18 + - libgfortran-ng=9.3.0=hff62375_18 + - libgfortran5=9.3.0=hff62375_18 + - libglib=2.68.0=h3e27bee_1 + - libgomp=9.3.0=h2828fa1_18 + - libiconv=1.16=h516909a_0 + - liblapack=3.9.0=8_openblas + - libllvm11=11.1.0=hf817b99_0 + - libnghttp2=1.43.0=h812cca2_0 + - libopenblas=0.3.12=pthreads_h4812303_1 + - libpng=1.6.37=h21135ba_2 + - libpq=13.1=hfd2b0eb_2 + - libssh2=1.9.0=ha56f1ee_6 + - libstdcxx-ng=9.3.0=h6de172a_18 + - libtiff=4.2.0=hdc55705_0 + - libuuid=2.32.1=h7f98852_1000 + - libwebp-base=1.2.0=h7f98852_2 + - libxcb=1.13=h7f98852_1003 + - libxkbcommon=1.0.3=he3ba5ed_0 + - libxml2=2.9.10=h72842e0_3 + - libxslt=1.1.33=h15afd5d_2 + - lxml=4.6.2=py36h04a5ba7_1 + - lz4-c=1.9.3=h9c3ff4c_0 + - matplotlib-base=3.3.4=py36hd391965_0 + - mysql-common=8.0.23=ha770c72_1 + - mysql-libs=8.0.23=h935591d_1 + - ncurses=6.2=h58526e2_4 + - nspr=4.30=h9c3ff4c_0 + - nss=3.63=hb5efdd6_0 + - numpy=1.19.5=py36h2aa4a07_1 + - obspy=1.2.2=py36h785e9b2_0 + - olefile=0.46=pyh9f0ad1d_1 + - openssl=1.1.1k=h7f98852_0 + - pandas=1.1.5=py36h284efc9_0 + - pcre=8.44=he1b5a44_0 + - pillow=8.1.2=py36ha6010c0_0 + - pip=21.0.1=pyhd8ed1ab_0 + - proj=7.2.0=h277dcde_2 + - pthread-stubs=0.4=h36c2ea0_1001 + - pycparser=2.20=pyh9f0ad1d_2 + - pyopenssl=20.0.1=pyhd8ed1ab_0 + - pyparsing=2.4.7=pyh9f0ad1d_0 + - pyqt5-sip=4.19.18=py36hc4f0c31_7 + - pyqtgraph=0.11.1=pyhd3deb0d_0 + - pyshp=2.1.3=pyh44b312d_0 + - pyside2=5.13.2=py36h6b97533_4 + - pysocks=1.7.1=py36h5fab9bb_3 + - python=3.6.13=hffdb5ce_0_cpython + - python-dateutil=2.8.1=py_0 + - python_abi=3.6=1_cp36m + - pytz=2021.1=pyhd8ed1ab_0 + - qt=5.12.9=hda022c4_4 + - qtpy=1.9.0=py_0 + - readline=8.0=he28a2e2_2 + - requests=2.25.1=pyhd3deb0d_0 + - scipy=1.5.3=py36h9e8f40b_0 + - setuptools=49.6.0=py36h5fab9bb_3 + - shapely=1.7.1=py36h93b233e_4 + - six=1.15.0=pyh9f0ad1d_0 + - sqlalchemy=1.4.2=py36h8f6f2f9_0 + - sqlite=3.34.0=h74cdb3f_0 + - tk=8.6.10=h21135ba_1 + - tornado=6.1=py36h8f6f2f9_1 + - typing_extensions=3.7.4.3=py_0 + - urllib3=1.26.4=pyhd8ed1ab_0 + - wheel=0.36.2=pyhd3deb0d_0 + - xorg-libxau=1.0.9=h7f98852_0 + - xorg-libxdmcp=1.1.3=h7f98852_0 + - xz=5.2.5=h516909a_1 + - zipp=3.4.1=pyhd8ed1ab_0 + - zlib=1.2.11=h516909a_1010 + - zstd=1.4.9=ha95c52a_0 +prefix: /home/kaan/.conda/envs/pylot_py35 diff --git a/pylot/core/util/array_map.py b/pylot/core/util/array_map.py index e72f4a40..d37eee99 100644 --- a/pylot/core/util/array_map.py +++ b/pylot/core/util/array_map.py @@ -12,6 +12,7 @@ from PySide2.QtCore import Qt from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar from matplotlib.figure import Figure +import matplotlib.patheffects as PathEffects import cartopy.crs as ccrs import matplotlib.pyplot as plt @@ -39,8 +40,10 @@ class MplCanvas(FigureCanvas): 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): - super(Array_map, self).__init__(parent) + # super(Array_map, self).__init__(parent) + QtWidgets.QWidget.__init__(self) + assert (parameter != None or parent != None), 'either parent or parameter has to be set' # set properties self._parent = parent self.metadata = metadata @@ -65,13 +68,20 @@ class Array_map(QtWidgets.QWidget): self.init_graphics() self.init_stations() self.init_crtpyMap() - self.init_colormap() - self.draw_everything() + self.init_map() + # set original map limits to fall back on when home button is pressed + self.org_xlim = self.canvas.axes.get_xlim() + self.org_ylim = self.canvas.axes.get_ylim() self._style = None if not hasattr(parent, '_style') else parent._style self.show() + def init_map(self): + self.init_colormap() + self.connectSignals() + self.draw_everything() + def init_graphics(self): """ Initializes all GUI components and figure elements to be populeted by other functions @@ -82,6 +92,8 @@ class Array_map(QtWidgets.QWidget): # initialize GUI elements self.status_label = QtWidgets.QLabel() + self.map_reset_button = QtWidgets.QPushButton('Reset Map View') + self.map_reset_button.resize(150, 50) self.main_box = QtWidgets.QVBoxLayout() self.setLayout(self.main_box) @@ -121,10 +133,15 @@ class Array_map(QtWidgets.QWidget): self.top_row.addWidget(self.refresh_button) self.main_box.addWidget(self.plotWidget, 1) - self.main_box.addWidget(NavigationToolbar(self.plotWidget, self), 0) - #self.main_box.addWidget(self.status_label, 0) + # self.main_box.addWidget(self.map_reset_button, 0) + # self.main_box.addWidget(NavigationToolbar(self.plotWidget, self), 0) + # self.main_box.addWidget(self.status_label, 0) - self.connectSignals() + self.bot_row = QtWidgets.QHBoxLayout() + self.main_box.addLayout(self.bot_row, 0.3) + self.bot_row.addWidget(self.map_reset_button) + self.bot_row.addWidget(self.status_label) + # self.connectSignals() def init_colormap(self): self.init_lat_lon_dimensions() @@ -139,20 +156,43 @@ class Array_map(QtWidgets.QWidget): self.canvas.axes.add_feature(cf.BORDERS, alpha=0.7) # parallels and meridians - gridlines = self.canvas.axes.gridlines(draw_labels=True, alpha=0.5, zorder=7) - gridlines.xformatter = LONGITUDE_FORMATTER - gridlines.yformatter = LATITUDE_FORMATTER + self.add_merid_paral() # self.canvas.axes.set_global() self.canvas.fig.tight_layout() # self.plotWidget.draw_idle() + def add_merid_paral(self): + self.gridlines = self.canvas.axes.gridlines(draw_labels=False, alpha=0.5, zorder=7) + # current cartopy version does not support label removal. Devs are working on it. + # Should be fixed with next cartopy version + # self.gridlines.xformatter = LONGITUDE_FORMATTER + # self.gridlines.yformatter = LATITUDE_FORMATTER + + def remove_merid_paral(self): + if len(self.gridlines.xline_artists): + for i in self.gridlines.xline_artists: + i.remove() + # self.gridlines.xline_artists[0].remove() + # self.gridlines.yline_artists[0].remove() + + def org_map_view(self): + self.canvas.axes.set_xlim(self.org_xlim[0], self.org_xlim[1]) + self.canvas.axes.set_ylim(self.org_ylim[0], self.org_ylim[1]) + # parallels and meridians + self.remove_merid_paral() + self.add_merid_paral() + + self.canvas.axes.figure.canvas.draw_idle() + def connectSignals(self): self.comboBox_phase.currentIndexChanged.connect(self._refresh_drawings) self.comboBox_am.currentIndexChanged.connect(self._refresh_drawings) self.cmaps_box.currentIndexChanged.connect(self._refresh_drawings) self.annotations_box.stateChanged.connect(self.switch_annotations) self.refresh_button.clicked.connect(self._refresh_drawings) + self.map_reset_button.clicked.connect(self.org_map_view) + self.plotWidget.mpl_connect('motion_notify_event', self.mouse_moved) self.plotWidget.mpl_connect('scroll_event', self.mouse_scroll) self.plotWidget.mpl_connect('button_press_event', self.mouseLeftPress) @@ -162,7 +202,6 @@ class Array_map(QtWidgets.QWidget): def mouse_moved(self, event): if not event.inaxes == self.canvas.axes: return - lat = event.ydata lon = event.xdata self.status_label.setText('Latitude: {}, Longitude: {}'.format(lat, lon)) @@ -189,6 +228,10 @@ class Array_map(QtWidgets.QWidget): self.canvas.axes.set_xlim(xl, xr) self.canvas.axes.set_ylim(yb, yt) + # parallels and meridians + self.remove_merid_paral() + self.add_merid_paral() + self.canvas.axes.figure.canvas.draw_idle() def mouseLeftPress(self, event): @@ -210,6 +253,10 @@ class Array_map(QtWidgets.QWidget): self.canvas.axes.set_xlim((self.map_xlim[0] - dx, self.map_xlim[1] - dx)) self.canvas.axes.set_ylim(self.map_ylim[0] - dy, self.map_ylim[1] - dy) + # parallels and meridians + self.remove_merid_paral() + self.add_merid_paral() + self.canvas.axes.figure.canvas.draw_idle() def onpick(self, event): @@ -223,6 +270,7 @@ class Array_map(QtWidgets.QWidget): self.deletePick(ind) elif button == 3: self.pickInfo(ind) + # data handling ----------------------------------------------------- def update_hybrids_dict(self): self.hybrids_dict = self.picks_dict.copy() @@ -387,18 +435,15 @@ class Array_map(QtWidgets.QWidget): return picks, uncertainties, latitudes, longitudes # plotting ----------------------------------------------------- - def init_colormap(self): - self.init_lat_lon_dimensions() - self.init_lat_lon_grid() - def highlight_station(self, network, station, color): stat_dict = self.stations_dict['{}.{}'.format(network, station)] lat = stat_dict['latitude'] lon = stat_dict['longitude'] self.highlighted_stations.append(self.canvas.axes.scatter(lon, lat, s=self.pointsize, edgecolors=color, - facecolors='none', zorder=12, label='deleted')) + facecolors='none', zorder=12, + transform=ccrs.PlateCarree(), label='deleted')) - self.canvas.idle_draw() + # self.canvas.idle_draw() def openPickDlg(self, ind): data = self._parent.get_data().getWFData() @@ -463,7 +508,7 @@ class Array_map(QtWidgets.QWidget): zorder=10, picker=True, edgecolor='0.5', label='Not Picked', transform=ccrs.PlateCarree()) - self.cid = self.canvas.mpl_connect('pick_event', self.onpick) + self.cid = self.plotWidget.mpl_connect('pick_event', self.onpick) self._station_onpick_ids = stations if self.eventLoc: lats, lons = self.eventLoc @@ -485,10 +530,9 @@ class Array_map(QtWidgets.QWidget): self.sc_picked = self.canvas.axes.scatter(lons, lats, s=sizes, edgecolors='white', cmap=cmap, c=picks, zorder=11, label='Picked', transform=ccrs.PlateCarree()) - def annotate_ax(self): self.annotations = [] - stations, xs, ys = self.get_st_lat_lon_for_plot() + stations, ys, xs = self.get_st_lat_lon_for_plot() # MP MP testing station highlighting if they have high impact on mean gradient of color map # if self.picks_rel: # self.test_gradient() @@ -502,7 +546,9 @@ class Array_map(QtWidgets.QWidget): if st in self.marked_stations: color = 'red' self.annotations.append(self.canvas.axes.annotate(' %s' % st, xy=(x, y), fontsize=self.pointsize / 4., - fontweight='semibold', color=color, zorder=14)) + fontweight='semibold', color=color, + transform=ccrs.PlateCarree(), zorder=14, + path_effects=[PathEffects.withStroke(linewidth=self.pointsize / 4., foreground='k')])) self.legend = self.canvas.axes.legend(loc=1) self.legend.get_frame().set_facecolor((1, 1, 1, 0.75)) @@ -560,7 +606,7 @@ class Array_map(QtWidgets.QWidget): self.comboBox_phase.setEnabled(False) if self.annotate: self.annotate_ax() - self.canvas.draw() + self.plotWidget.draw_idle() def remove_drawings(self): self.remove_annotations() @@ -584,7 +630,7 @@ class Array_map(QtWidgets.QWidget): self.remove_contourf() del self.contourf if hasattr(self, 'cid'): - self.canvas.mpl_disconnect(self.cid) + self.plotWidget.mpl_disconnect(self.cid) del self.cid try: self.sc.remove() @@ -594,7 +640,7 @@ class Array_map(QtWidgets.QWidget): self.legend.remove() except Exception as e: print('Warning: could not remove legend. Reason: {}'.format(e)) - self.canvas.draw() + self.plotWidget.draw_idle() def remove_contourf(self): for item in self.contourf.collections: