From 4f71eff681f00aeb2c47aee9366dcc78a81cb0c9 Mon Sep 17 00:00:00 2001 From: Daniel Scheffler Date: Tue, 6 Oct 2020 23:32:08 +0200 Subject: [PATCH] Revised COREG_LOCAL.view_CoRegPoints() and replaced basemap with cartopy. Revised environment_arosics.yml. Fixes issue #36. Closes issue #26. Signed-off-by: Daniel Scheffler --- .gitlab-ci.yml | 6 +- arosics/CoReg_local.py | 148 ++++++++++-------- requirements.txt | 22 +-- requirements_dev.txt | 12 +- requirements_pip.txt | 4 +- setup.py | 19 ++- .../CI_docker/context/environment_arosics.yml | 14 +- tests/test_COREG_LOCAL.py | 12 +- 8 files changed, 129 insertions(+), 108 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3e58d67..544a792 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,9 +13,11 @@ test_arosics: script: - source /root/miniconda3/bin/activate ci_env + - conda install -c conda-forge cartopy # FIXME remove as soon as docker container is rebuilt + # update py_tools_ds and geoarray # - pip install "py_tools_ds>=0.14.28" - # - pip install "geoarray>=0.8.30" + - pip install "geoarray>=0.9.0" # run tests - make nosetests @@ -60,7 +62,7 @@ test_arosics_install: - source activate arosics_testinstall # resolve some requirements with conda - - conda install --yes -q -c conda-forge numpy gdal scikit-image matplotlib 'pyproj>2.2.0' shapely geopandas pandas pykrige pyfftw basemap + - conda install --yes -q -c conda-forge numpy gdal scikit-image matplotlib 'pyproj>2.2.0' shapely geopandas pandas pykrige pyfftw cartopy # run installer - python setup.py install diff --git a/arosics/CoReg_local.py b/arosics/CoReg_local.py index af02306..f4a8322 100644 --- a/arosics/CoReg_local.py +++ b/arosics/CoReg_local.py @@ -363,9 +363,8 @@ class COREG_LOCAL(object): def view_CoRegPoints(self, shapes2plot='points', attribute2plot='ABS_SHIFT', cmap=None, exclude_fillVals=True, backgroundIm='tgt', hide_filtered=True, figsize=None, title='', vector_scale=1., - savefigPath='', savefigDPI=96, showFig=True, vmin=None, vmax=None, return_map=False, - zoomable=False): - # type: (str, str, plt.cm, bool, str, bool, tuple, str, float, str, int, bool, float, float, bool, bool) -> ... + savefigPath='', savefigDPI=96, showFig=True, vmin=None, vmax=None, return_map=False): + # type: (str, str, plt.cm, bool, str, bool, tuple, str, float, str, int, bool, float, float, bool) -> ... """ Show a map of the calculated tie point grid with the target image as background. @@ -388,63 +387,62 @@ class COREG_LOCAL(object): :param showFig: whether to show or to hide the figure :param vmin: :param vmax: - :param return_map - :param zoomable: enable or disable zooming via mpld3 + :param return_map 0: @@ -455,27 +453,31 @@ class COREG_LOCAL(object): GDF = GDF[GDF.L3_OUTLIER.__eq__(False)].copy() else: marker = 'o' if len(GDF) < 10000 else '.' + common_kw = dict(marker=marker, alpha=1.0, transform=PlateCarree()) if self.tieP_filter_level > 0: # flag level 1 outliers GDF_filt = GDF[GDF.L1_OUTLIER.__eq__(True)].copy() - ax.scatter(GDF_filt['plt_X'], GDF_filt['plt_Y'], c='b', marker=marker, s=250, alpha=1.0, - label='reliability') + ax.scatter(GDF_filt['Lon'], GDF_filt['Lat'], c='b', s=250, label='reliability', + **common_kw) if self.tieP_filter_level > 1: # flag level 2 outliers GDF_filt = GDF[GDF.L2_OUTLIER.__eq__(True)].copy() - ax.scatter(GDF_filt['plt_X'], GDF_filt['plt_Y'], c='r', marker=marker, s=150, alpha=1.0, label='SSIM') + ax.scatter(GDF_filt['Lon'], GDF_filt['Lat'], c='r', s=150, label='SSIM', + **common_kw) if self.tieP_filter_level > 2: # flag level 3 outliers GDF_filt = GDF[GDF.L3_OUTLIER.__eq__(True)].copy() - ax.scatter(GDF_filt['plt_X'], GDF_filt['plt_Y'], c='y', marker=marker, s=250, alpha=1.0, - label='RANSAC') + ax.scatter(GDF_filt['Lon'], GDF_filt['Lat'], c='y', s=250, label='RANSAC', + **common_kw) if self.tieP_filter_level > 0: ax.legend(loc=0, scatterpoints=1) # plot all points or vectors on top if not GDF.empty: - vmin_auto, vmax_auto = (np.percentile(GDF[attribute2plot], 0), np.percentile(GDF[attribute2plot], 98)) \ + vmin_auto, vmax_auto = \ + (np.percentile(GDF[attribute2plot], 0), + np.percentile(GDF[attribute2plot], 98)) \ if attribute2plot != 'ANGLE' else (0, 360) vmin = vmin if vmin is not None else vmin_auto vmax = vmax if vmax is not None else vmax_auto @@ -483,30 +485,48 @@ class COREG_LOCAL(object): if shapes2plot == 'vectors': # plot shift vectors # doc: https://matplotlib.org/devdocs/api/_as_gen/matplotlib.axes.Axes.quiver.html - ax.quiver(GDF['plt_X'], GDF['plt_Y'], - -GDF['X_SHIFT_M'], -GDF['Y_SHIFT_M'], # invert absolute shifts to make arrows point to tgt - GDF[attribute2plot].clip(vmin, vmax), # sets the colors - scale=1200 / vector_scale, # larger values decrease the arrow length - width=.0015, # arrow width (in relation to plot width) - # linewidth=1, # maybe use this to mark outliers instead of scatter points - cmap=palette, - pivot='middle' # position the middle point of the arrows onto the tie point location - ) + mappable = ax.quiver( + GDF['Lon'].values, GDF['Lat'].values, + -GDF['X_SHIFT_M'].values, + -GDF['Y_SHIFT_M'].values, # invert absolute shifts to make arrows point to tgt + GDF[attribute2plot].clip(vmin, vmax), # sets the colors + scale=1200 / vector_scale, # larger values decrease the arrow length + width=.0015, # arrow width (in relation to plot width) + # linewidth=1, # maybe use this to mark outliers instead of scatter points + cmap=palette, + pivot='middle', # position the middle point of the arrows onto the tie point location + transform=PlateCarree() + ) elif shapes2plot == 'points': # plot tie points - ax.scatter(GDF['plt_X'], GDF['plt_Y'], c=GDF[attribute2plot], lw=0, - cmap=palette, marker='o' if len(GDF) < 10000 else '.', s=50, alpha=1.0, - vmin=vmin, vmax=vmax) - + mappable = ax.scatter( + GDF['Lon'], GDF['Lat'], + c=GDF[attribute2plot], + lw=0, + cmap=palette, + marker='o' if len(GDF) < 10000 else '.', + s=50, + alpha=1.0, + vmin=vmin, + vmax=vmax, + transform=PlateCarree()) + pass else: - raise ValueError("The parameter 'shapes2plot' must be set to 'vectors' or 'points'. Received %s." - % shapes2plot) + raise ValueError("The parameter 'shapes2plot' must be set to 'vectors' or 'points'. " + "Received %s." % shapes2plot) # add colorbar - p = ax.get_position().get_points().flatten() # [left, bottom, right, top] - cax = fig.add_axes([p[2] + 0.02, p[1], 0.02, p[3] - p[1]]) # [left, bottom, width, height] - ColorbarBase(cax, cmap=palette, norm=Normalize(vmin=vmin, vmax=vmax), orientation='vertical') + divider = make_axes_locatable(ax) + cax = divider.new_vertical(size="2%", pad=0.4, pack_start=True, + axes_class=plt.Axes # needed because ax is a GeoAxis instance + ) + fig.add_axes(cax) + fig.colorbar(mappable, cax=cax, cmap=palette, + norm=Normalize(vmin=vmin, vmax=vmax), orientation="horizontal") + + # hack to enlarge the figure on the top to avoid cutting off the title (everthing else has no effect) + divider.new_vertical(size="2%", pad=0.4, pack_start=False, axes_class=plt.Axes) else: if not self.q: @@ -516,7 +536,7 @@ class COREG_LOCAL(object): fig.savefig(savefigPath, dpi=savefigDPI) if return_map: - return fig, ax, map2show + return fig, ax if showFig and not self.q: plt.show(block=True) diff --git a/requirements.txt b/requirements.txt index 2e2f85d..97e06cc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,17 +1,17 @@ -geoarray>=0.8.30 -py_tools_ds>=0.14.28 +cartopy cmocean -numpy gdal -shapely -scikit-image -matplotlib +geoarray>=0.9.0 +geojson +folium>=0.6.0 geopandas +matplotlib +numpy pandas plotly -six -folium>=0.6.0 -geojson -pykrige pyfftw -git+https://github.com/matplotlib/basemap#egg=basemap +pykrige +py_tools_ds>=0.14.28 +scikit-image +shapely +six diff --git a/requirements_dev.txt b/requirements_dev.txt index a8cf053..a82b778 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,10 +1,10 @@ -pip bumpversion -wheel -watchdog -flake8 -tox coverage -Sphinx cryptography +flake8 +pip PyYAML +Sphinx +tox +watchdog +wheel diff --git a/requirements_pip.txt b/requirements_pip.txt index a36ecd4..a419eb3 100644 --- a/requirements_pip.txt +++ b/requirements_pip.txt @@ -1,4 +1,4 @@ -plotly -six folium>=0.6.0 geojson +plotly +six diff --git a/setup.py b/setup.py index 16d2686..1d247b3 100644 --- a/setup.py +++ b/setup.py @@ -38,9 +38,22 @@ with open("arosics/version.py") as version_file: exec(version_file.read(), version) requirements = [ - 'numpy', 'gdal', 'shapely', 'scikit-image', 'matplotlib', 'geopandas', 'pandas', 'plotly', 'cmocean', 'six', - 'folium>=0.6.0', 'geojson', 'pykrige', 'pyfftw', 'geoarray>=0.8.30', 'py_tools_ds>=0.14.28', - 'basemap @ git+https://github.com/matplotlib/basemap#egg=basemap' + 'cmocean', + 'folium>=0.6.0', + 'gdal', + 'geojson', + 'geoarray>=0.9.0', + 'geopandas', + 'matplotlib', + 'numpy', + 'pandas', + 'plotly', + 'pyfftw', + 'pykrige', + 'py_tools_ds>=0.14.28', + 'scikit-image', + 'shapely', + 'six', ] setup_requirements = [ diff --git a/tests/CI_docker/context/environment_arosics.yml b/tests/CI_docker/context/environment_arosics.yml index 78b5510..fdbae51 100644 --- a/tests/CI_docker/context/environment_arosics.yml +++ b/tests/CI_docker/context/environment_arosics.yml @@ -15,25 +15,15 @@ dependencies: - ipython - shapely - matplotlib - - basemap - holoviews - - bokeh - pykrige - pyfftw - cmocean + - cartopy - pip: - - dicttoxml - - jsmin - - cerberus - - pyprind - - pint - - iso8601 - - tqdm - - mpld3 - sphinx-argparse - six - - spectral - folium>=0.6.0 - geojson - flake8 @@ -46,5 +36,5 @@ dependencies: - coverage - rednose - plotly - - geoarray>=0.8.30 + - geoarray>=0.9.0 - py_tools_ds>=0.15.0 diff --git a/tests/test_COREG_LOCAL.py b/tests/test_COREG_LOCAL.py index a168e6f..7770479 100644 --- a/tests/test_COREG_LOCAL.py +++ b/tests/test_COREG_LOCAL.py @@ -27,7 +27,6 @@ import unittest import shutil import os -from pkgutil import find_loader # custom from .cases import test_cases @@ -85,13 +84,10 @@ class CompleteWorkflow_INTER1_S2A_S2A(unittest.TestCase): CRL.CoRegPoints_table # test tie point grid visualization - if find_loader('mpl_toolkits.basemap'): # only works if basemap is installed - CRL.view_CoRegPoints(hide_filtered=True) - CRL.view_CoRegPoints(hide_filtered=False) - CRL.view_CoRegPoints(shapes2plot='vectors') - - if find_loader('folium') and find_loader('geojson'): - CRL.view_CoRegPoints_folium() + CRL.view_CoRegPoints(hide_filtered=True) + CRL.view_CoRegPoints(hide_filtered=False) + CRL.view_CoRegPoints(shapes2plot='vectors') + CRL.view_CoRegPoints_folium() # test shift correction and output writer CRL.correct_shifts() -- GitLab