Skip to content
Commits on Source (7)
[bumpversion]
current_version = 1.8.3
current_version = 1.9.0
commit = True
tag = True
......
......@@ -15,4 +15,4 @@ expected output is a better solution.]
#### Versions of Python, package at hand and relevant dependencies
Thank you for reporting an issue !
<!-- Thank you for reporting an issue ! -->
Please make the PR against the `develop` branch.
<!-- Please make the PR against the `develop` branch. -->
- [ ] Closes #xxxx (remove if there is no corresponding issue, which should only be the case for minor changes)
- [ ] Tests added (for all bug fixes or enhancements)
- [ ] Tests passed (for all non-documentation changes)
- [ ] Passes ``git diff origin/develop **/*py | flake8 --diff`` (remove if you did not edit any Python files)
- [ ] Fully documented (remove if this change should not be visible to users, e.g., if it is an internal clean-up, or if this is part of a larger project that will be documented later)
- [ ] Closes #xxxx <!-- remove if there is no corresponding issue, which should only be the case for minor changes -->
- [ ] Tests added <!-- for all bug fixes or enhancements -->
- [ ] Tests passed <!-- for all non-documentation changes -->
- [ ] Passes ``git diff origin/develop **/*py | flake8 --diff`` <!-- remove if you did not edit any Python files -->
- [ ] Fully documented <!-- remove if this change should not be visible to users, e.g., if it is an internal clean-up, or if this is part of a larger project that will be documented later -->
language: python
python:
- '2.7'
- '3.4'
- '3.5'
- '3.6'
before_install:
- sudo add-apt-repository ppa:ubuntugis/ppa -y
- sudo apt-get update -qq
- sudo apt-get install libfreetype6-dev
- sudo apt-get install libgeos-dev
env:
global:
# Set defaults to avoid repeating in most cases
- PYTHON_VERSION=$TRAVIS_PYTHON_VERSION
- NUMPY_VERSION=stable
- MAIN_CMD='python setup.py'
- CONDA_DEPENDENCIES='xarray dask toolz Cython pykdtree sphinx cartopy pillow matplotlib basemap pyyaml pyproj coveralls configobj coverage'
- SETUP_XVFB=False
- EVENT_TYPE='push pull_request'
- SETUP_CMD='test'
- CONDA_CHANNELS='conda-forge'
install:
# matplotlib 2.1.0 has a bug that causes plotting masked arrays to fail
# https://github.com/matplotlib/matplotlib/issues/9280
- if [[ $TRAVIS_PYTHON_VERSION == "2.7" ]]; then pip install "matplotlib>=1.5.0,!=2.1.0"; fi
- if [[ $TRAVIS_PYTHON_VERSION == "2.7" ]]; then pip install "sphinx>=1.5.0"; fi
- if [[ $TRAVIS_PYTHON_VERSION == "3.4" ]]; then pip install "matplotlib>=1.5.0,!=2.1.0"; fi
- if [[ $TRAVIS_PYTHON_VERSION == "3.4" ]]; then pip install "sphinx>=1.5.0"; fi
- if [[ $TRAVIS_PYTHON_VERSION == "3.5" ]]; then pip install "matplotlib>=1.5.0,!=2.1.0"; fi
- if [[ $TRAVIS_PYTHON_VERSION == "3.5" ]]; then pip install "sphinx>=1.5.0"; fi
- if [[ $TRAVIS_PYTHON_VERSION == "3.6" ]]; then pip install "matplotlib>=1.5.0,!=2.1.0"; fi
- if [[ $TRAVIS_PYTHON_VERSION == "3.6" ]]; then pip install "sphinx>=1.5.0"; fi
- pip install -r requirements.txt
- pip install toolz
- pip install dask
- pip install xarray
- pip install -e ".[pykdtree,quicklook]"
- pip install coveralls
- git clone --depth 1 git://github.com/astropy/ci-helpers.git
- source ci-helpers/travis/setup_conda.sh
script:
- coverage run --source=pyresample setup.py test && cd docs && mkdir doctest && sphinx-build -E -n -b doctest ./source ./doctest && cd ..
after_success: coveralls
......
[![Build Status](https://travis-ci.org/pytroll/pyresample.svg?branch=master)](https://travis-ci.org/pytroll/pyresample)
[![Build status](https://ci.appveyor.com/api/projects/status/10qdrecp45rgkf73/branch/master?svg=true)](https://ci.appveyor.com/project/davidh-ssec/pyresample-ly2q0/branch/master)
[![Build status](https://ci.appveyor.com/api/projects/status/a34o4utf8dqjsob1/branch/master?svg=true)](https://ci.appveyor.com/project/pytroll/pyresample/branch/master)
Python package for geospatial resampling
......@@ -13,29 +13,9 @@ Pyresample works with Numpy arrays including support for masked arrays.
Support for parallel resampling using multiple processor cores.
Plotting capablity using Basemap. As of v0.8.0 [pykdtree](https://github.com/storpipfugl/pykdtree) can be used to speed up processing.
Pyresample is tested with Python 2.7, 3.4, 3.5, and 3.6.
Note: For numpy >= 1.6.2 use pyresample >= 0.7.13
Pyresample is tested with Python 2.7 and 3.6, but should additionally work
on Python 3.4+.
[Documentation](https://pyresample.readthedocs.org/en/latest/)
Look at [pytroll.org](http://pytroll.org/) for more information.
===News===
* *2015-02-03*: Pyresample-1.1.3 released. Switch to LGPLv3.
* *2014-12-17*: Pyresample-1.1.2 released. Fix to allow tests to run on travis.
* *2014-12-10*: Pyresample-1.1.1 released. Wrapping of longitudes and latitudes is now implemented.
* *2013-10-23*: Pyresample-1.1.0 released. Added option for calculating uncertainties for weighted kd-tree resampling. From now on pyresample will adhere to [http://semver.org/ semantic versioning].
* *2013-07-03*: Pyresample-1.0.0 released. Minor API change to the geometry.py module as the boundary variable is removed and replaced by proj_x_coords and proj_y_coords. Caching scheme removed from projection coordinate calculation in geometry.py as it introduced excessive complications. The numexpr package is now used for minor bottleneck optimization if available. Version number bumped to 1.0.0 as pyresample has been running stable in production environments for several years now.
* *2013-03-20*: Pyresample-0.8.0 released. Enables use of pykdtree. Fixes projection handling for 'latlong' projection.
* *2013-01-21*: Pyresample-0.7.13 released. Fixes numpy incompability introduced with numpy v1.6.2
* *2012-10-18*: Pyresample-0.7.12 released. Better integration with Basemap with support for plotting using globe projections (geos, ortho and nspere). Documentation updated with correct description of the epsilon parameter.
* *2012-07-03*: Pyresample-0.7.11 released. Support for plotting in Plate Carree projection and bugfixes for meridians and parallels in plots. Added utils.fwhm2sigma convenience function for use in Gauss resampling.
environment:
global:
# SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the
# /E:ON and /V:ON options are not enabled in the batch script intepreter
# See: http://stackoverflow.com/a/13751649/163740
CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\appveyor\\run_with_compiler.cmd"
PYTHON: "C:\\conda"
MINICONDA_VERSION: "latest"
CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\ci-helpers\\appveyor\\windows_sdk.cmd"
# Don't build pykdtree with openmp because it isn't supported in appveyor's compilers
USE_OMP: "0"
CONDA_DEPENDENCIES: "xarray dask toolz Cython pykdtree sphinx cartopy pillow matplotlib pyyaml pyproj coveralls configobj coverage"
CONDA_CHANNELS: "conda-forge"
matrix:
- PYTHON: "C:\\Python27_32"
PYTHON_VERSION: "2.7.8"
PYTHON_VERSION: "2.7"
PYTHON_ARCH: "32"
MINICONDA_VERSION: "2"
NUMPY_VERSION: "stable"
- PYTHON: "C:\\Python27_64"
PYTHON_VERSION: "2.7.8"
PYTHON_VERSION: "2.7"
PYTHON_ARCH: "64"
MINICONDA_VERSION: "2"
- PYTHON: "C:\\Python34_32"
PYTHON_VERSION: "3.4.1"
PYTHON_ARCH: "32"
MINICONDA_VERSION: "3"
- PYTHON: "C:\\Python34_64"
PYTHON_VERSION: "3.4.1"
PYTHON_ARCH: "64"
MINICONDA_VERSION: "3"
NUMPY_VERSION: "stable"
- PYTHON: "C:\\Python36_32"
PYTHON_VERSION: "3.6"
PYTHON_ARCH: "32"
MINICONDA_VERSION: "3"
NUMPY_VERSION: "stable"
- PYTHON: "C:\\Python36_64"
PYTHON_VERSION: "3.6"
PYTHON_ARCH: "64"
MINICONDA_VERSION: "3"
NUMPY_VERSION: "stable"
install:
- "git submodule update --init --recursive"
- ECHO "Filesystem root:"
- ps: "ls \"C:/\""
- ECHO "Installed SDKs:"
- ps: "ls \"C:/Program Files/Microsoft SDKs/Windows\""
# install miniconda with the powershell script install.ps1
- "powershell ./appveyor/install.ps1"
# Prepend newly installed Python to the PATH of this build (this cannot be
# done from inside the powershell script as it would require to restart
# the parent CMD process).
- "git clone --depth 1 git://github.com/astropy/ci-helpers.git"
- "powershell ci-helpers/appveyor/install-miniconda.ps1"
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
# Check that we have the expected version and architecture for Python
- "python --version"
- "python -c \"import struct; print(struct.calcsize('P') * 8)\""
# Install the build dependencies of the project. If some dependencies contain
# compiled extensions and are not provided as pre-built wheel packages,
# pip will build them from source using the MSVC compiler matching the
# target Python version and architecture
- "conda update --yes conda"
- "conda config --add channels conda-forge"
- "conda create -q --yes -n test python=%PYTHON_VERSION% basemap-data-hires sphinx pyproj scipy pykdtree dask xarray"
- "activate test"
- "pip install coveralls"
- "pip install mock"
- "where python"
build: false # Not a C# project, build stuff at the test step instead.
......
# Sample script to install anaconda under windows
# Authors: Stuart Mumford
# Borrwed from: Olivier Grisel and Kyle Kastner
# License: BSD 3 clause
$MINICONDA_URL = "http://repo.continuum.io/miniconda/"
function DownloadMiniconda ($miniconda_version, $platform_suffix) {
$webclient = New-Object System.Net.WebClient
$filename = "Miniconda" + $miniconda_version + "-latest" + "-Windows-" + $platform_suffix + ".exe"
$url = $MINICONDA_URL + $filename
$basedir = $pwd.Path + "\"
$filepath = $basedir + $filename
if (Test-Path $filename) {
Write-Host "Reusing" $filepath
return $filepath
}
# Download and retry up to 3 times in case of network transient errors.
Write-Host "Downloading" $filename "from" $url
$retry_attempts = 2
for($i=0; $i -lt $retry_attempts; $i++){
try {
$webclient.DownloadFile($url, $filepath)
break
}
Catch [Exception]{
Start-Sleep 1
}
}
if (Test-Path $filepath) {
Write-Host "File saved at" $filepath
} else {
# Retry once to get the error message if any at the last try
$webclient.DownloadFile($url, $filepath)
}
return $filepath
}
function InstallMiniconda ($miniconda_version, $architecture, $python_home) {
Write-Host "Installing miniconda" $miniconda_version "for" $architecture "bit architecture to" $python_home
if (Test-Path $python_home) {
Write-Host $python_home "already exists, skipping."
return $false
}
if ($architecture -eq "32") {
$platform_suffix = "x86"
} else {
$platform_suffix = "x86_64"
}
$filepath = DownloadMiniconda $miniconda_version $platform_suffix
Write-Host "Installing" $filepath "to" $python_home
$args = "/InstallationType=AllUsers /S /AddToPath=1 /RegisterPython=1 /D=" + $python_home
Write-Host $filepath $args
Start-Process -FilePath $filepath -ArgumentList $args -Wait -Passthru
#Start-Sleep -s 15
if (Test-Path $python_home) {
Write-Host "Miniconda $miniconda_version ($architecture) installation complete"
} else {
Write-Host "Failed to install Python in $python_home"
Exit 1
}
}
function main () {
InstallMiniconda $env:MINICONDA_VERSION $env:PYTHON_ARCH $env:PYTHON
}
main
:: To build extensions for 64 bit Python 3, we need to configure environment
:: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of:
:: MS Windows SDK for Windows 7 and .NET Framework 4 (SDK v7.1)
::
:: To build extensions for 64 bit Python 2, we need to configure environment
:: variables to use the MSVC 2008 C++ compilers from GRMSDKX_EN_DVD.iso of:
:: MS Windows SDK for Windows 7 and .NET Framework 3.5 (SDK v7.0)
::
:: 32 bit builds do not require specific environment configurations.
::
:: Note: this script needs to be run with the /E:ON and /V:ON flags for the
:: cmd interpreter, at least for (SDK v7.0)
::
:: More details at:
:: https://github.com/cython/cython/wiki/64BitCythonExtensionsOnWindows
:: http://stackoverflow.com/a/13751649/163740
::
:: Author: Olivier Grisel
:: License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/
@ECHO OFF
SET COMMAND_TO_RUN=%*
SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows
SET MAJOR_PYTHON_VERSION="%PYTHON_VERSION:~0,1%"
SET MINOR_PYTHON_VERSION=%PYTHON_VERSION:~2,1%
IF %MAJOR_PYTHON_VERSION% == "2" (
SET WINDOWS_SDK_VERSION="v7.0"
SET SET_SDK_64=Y
) ELSE IF %MAJOR_PYTHON_VERSION% == "3" (
SET WINDOWS_SDK_VERSION="v7.1"
IF %MINOR_PYTHON_VERSION% LEQ 4 (
SET SET_SDK_64=Y
) ELSE (
SET SET_SDK_64=N
)
) ELSE (
ECHO Unsupported Python version: "%MAJOR_PYTHON_VERSION%"
EXIT 1
)
IF "%PYTHON_ARCH%"=="64" (
IF %SET_SDK_64% == Y (
ECHO Configuring Windows SDK %WINDOWS_SDK_VERSION% for Python %MAJOR_PYTHON_VERSION% on a 64 bit architecture
SET DISTUTILS_USE_SDK=1
SET MSSdk=1
"%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WINDOWS_SDK_VERSION%
"%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release
ECHO Executing: %COMMAND_TO_RUN%
call %COMMAND_TO_RUN% || EXIT 1
) ELSE (
ECHO Using default MSVC build environment for 64 bit architecture
ECHO Executing: %COMMAND_TO_RUN%
call %COMMAND_TO_RUN% || EXIT 1
)
) ELSE (
ECHO Using default MSVC build environment for 32 bit architecture
ECHO Executing: %COMMAND_TO_RUN%
call %COMMAND_TO_RUN% || EXIT 1
)
......@@ -2,6 +2,62 @@ Changelog
=========
v1.9.0 (2018-04-27)
-------------------
- update changelog. [Martin Raspaud]
- Bump version: 1.8.3 → 1.9.0. [Martin Raspaud]
- Merge pull request #114 from pytroll/feature-hash-update. [Martin
Raspaud]
Implement Deterministic hashing
- Fix __hash__ inheritance block in python 3. [Martin Raspaud]
- Add the hash attribute to all definitions. [Martin Raspaud]
- Add the update_hash method, centralize __hash__ [Martin Raspaud]
- Merge pull request #102 from pytroll/feature-cartopy-convert. [David
Hoese]
Add cartopy conversion method to AreaDefinition
- Add license and copyright to plot and test_plot. [davidh-ssec]
- Update appveyor badge to point to new project. [davidh-ssec]
- Fix line too long. [davidh-ssec]
- Merge branch 'develop' into feature-cartopy-convert. [davidh-ssec]
# Conflicts:
# appveyor.yml
# pyresample/__init__.py
# pyresample/geometry.py
# pyresample/kd_tree.py
- Merge pull request #109 from pytroll/feature-better-omerc-azimuth.
[Martin Raspaud]
Make azimuth angle for omerc dynamic areas more robust
- Fix tests for new omerc parameters computation. [Martin Raspaud]
- Take care of azimuth flipping in omerc parameter computation. [Martin
Raspaud]
- Take care of small omerc azimuth angles. [Martin Raspaud]
- Use no_rot for better 2-point omerc fitting. [Martin Raspaud]
- Make azimuth angle for omerc dynamic areas more robust. [Martin
Raspaud]
- Add basemap to travis for doctests. [davidh-ssec]
- Remove appveyor unused scripts. [davidh-ssec]
- Fix conda dependencies on travis and switch to ci-helpers for
appveyor. [davidh-ssec]
- Add missing coverage dependency to travis CI. [davidh-ssec]
- Use conda for travis tests. [davidh-ssec]
- Update github templates. [davidh-ssec]
- Fix flake8 issues. [davidh-ssec]
- Add basemap quicklook generation back in as a fallback. [davidh-ssec]
- Install proj libraries binaries for cartopy. [davidh-ssec]
- Remove python 3.4 and 3.5 from CI tests. [davidh-ssec]
- Add simple cartopy conversion test. [davidh-ssec]
- Skip basemap tests if basemap isn't available. [davidh-ssec]
- Switch quicklook to use cartopy instead of basemap. [davidh-ssec]
- Replace quicklook functionality with cartopy. [davidh-ssec]
- Update documentation to include cartopy example. [davidh-ssec]
- Add cartopy conversion method to AreaDefinition. [davidh-ssec]
v1.8.3 (2018-03-19)
-------------------
- update changelog. [Martin Raspaud]
......
pyresample (1.8.3-2) UNRELEASED; urgency=medium
pyresample (1.9.0-1) unstable; urgency=medium
[ Bas Couwenberg ]
* Bump Standards-Version to 4.1.4, no changes.
-- Antonio Valentino <antonio.valentino@tiscali.it> Wed, 18 Apr 2018 20:48:38 +0200
[ Antonio Valentino ]
* New upstream release.
* debian/patches
- refresh all patches
* debian/control
- add build dependency for cartopy.
For binary packages now cartopy is recommended,
while basemap is only suggested
- add dependency form scipy which is suggested by cartopy
but is necessary for plotting
* debian/copyright
- update remove no longer necessaty entries for files in the appveyor
folder
-- Antonio Valentino <antonio.valentino@tiscali.it> Sat, 28 Apr 2018 08:19:51 +0000
pyresample (1.8.3-1) unstable; urgency=medium
......
......@@ -22,6 +22,8 @@ Build-Depends: debhelper (>= 11.0.0),
python3-numexpr,
python-yaml,
python3-yaml,
python-cartopy,
python3-cartopy,
python-mpltoolkits.basemap,
python3-mpltoolkits.basemap,
python-pil,
......@@ -29,6 +31,8 @@ Build-Depends: debhelper (>= 11.0.0),
python-mock,
python-six,
python3-six,
python-scipy,
python3-scipy,
cython,
cython3
Standards-Version: 4.1.4
......@@ -50,8 +54,10 @@ Depends: ${misc:Depends},
python-pyresample-test
Recommends: python-numexpr,
python-pil,
python-cartopy,
python-scipy
Suggests: python-pyresample-doc,
python-mpltoolkits.basemap
Suggests: python-pyresample-doc
Description: Resampling of remote sensing data in Python 2
Pyresample is a Python package for resampling (reprojection) of earth
observing satellite data. It handles both resampling of gridded data
......@@ -77,9 +83,11 @@ Depends: ${misc:Depends},
python-pyresample-test
Recommends: python3-numexpr,
python3-pil,
python3-mpltoolkits.basemap,
python3-cartopy,
python3-scipy,
python3-dask
Suggests: python-pyresample-doc,
python3-mpltoolkits.basemap,
python3-xarray
Description: Resampling of remote sensing data in Python 3
Pyresample is a Python package for resampling (reprojection) of earth
......
......@@ -20,14 +20,6 @@ Files: pyresample/ewa/*
Copyright: 2016 David Hoese <david.hoese@ssec.wisc.edu>
License: GPL-3+
Files: appveyor/run_with_compiler.cmd
Copyright: Olivier Grisel
License: CC0-1.0
Files: appveyor/install.ps1
Copyright: Stuart Mumford
License: BSD-3-Clause
Files: debian/*
Copyright: 2013-2015, Antonio Valentino <antonio.valentino@tiscali.it>
License: GPL-3+
......@@ -66,149 +58,3 @@ License: LGPL-3+
On Debian systems, the complete text of the GNU Lesser General
Public License can be found in "/usr/share/common-licenses/LGPL-3".
License: CC0-1.0
Statatement of Purpose
.
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work
of authorship and/or a database (each, a "Work").
.
Certain owners wish to permanently relinquish those rights to a Work
for the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without
fear of later claims of infringement build upon, modify, incorporate in
other works, reuse and redistribute as freely as possible in any form
whatsoever and for any purposes, including without limitation commercial
purposes. These owners may contribute to the Commons to promote the ideal
of a free culture and the further production of creative, cultural and
scientific works, or to gain reputation or greater distribution for
their Work in part through the use and efforts of others.
.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that
he or she is an owner of Copyright and Related Rights in the Work,
voluntarily elects to apply CC0 to the Work and publicly distribute
the Work under its terms, with knowledge of his or her Copyright and
Related Rights in the Work and the meaning and intended legal effect
of CC0 on those rights.
.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright
and Related Rights"). Copyright and Related Rights include, but are
not limited to, the following:
.
the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
.
moral rights retained by the original author(s) and/or performer(s);
.
publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
.
rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
.
rights protecting the extraction, dissemination, use and reuse of data in a Work;
.
database rights (such as those arising under Directive 96/9/EC
of the European Parliament and of the Council of 11 March 1996
on the legal protection of databases, and under any national
implementation thereof, including any amended or successor version
of such directive); and
.
other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations
thereof.
.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all
of Affirmer's Copyright and Related Rights and associated claims and
causes of action, whether now known or unknown (including existing
as well as future claims and causes of action), in the Work (i) in
all territories worldwide, (ii) for the maximum duration provided by
applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv)
for any purpose whatsoever, including without limitation commercial,
advertising or promotional purposes (the "Waiver"). Affirmer makes the
Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such
Waiver shall not be subject to revocation, rescission, cancellation,
termination, or any other legal or equitable action to disrupt the
quiet enjoyment of the Work by the public as contemplated by Affirmer's
express Statement of Purpose.
.
3. Public License Fallback. Should any part of the Waiver for any
reason be judged legally invalid or ineffective under applicable law,
then the Waiver shall be preserved to the maximum extent permitted
taking into account Affirmer's express Statement of Purpose. In
addition, to the extent the Waiver is so judged Affirmer hereby
grants to each affected person a royalty-free, non transferable, non
sublicensable, non exclusive, irrevocable and unconditional license
to exercise Affirmer's Copyright and Related Rights in the Work (i)
in all territories worldwide, (ii) for the maximum duration provided
by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv)
for any purpose whatsoever, including without limitation commercial,
advertising or promotional purposes (the "License"). The License shall
be deemed effective as of the date CC0 was applied by Affirmer to the
Work. Should any part of the License for any reason be judged legally
invalid or ineffective under applicable law, such partial invalidity
or ineffectiveness shall not invalidate the remainder of the License,
and in such case Affirmer hereby affirms that he or she will not (i)
exercise any of his or her remaining Copyright and Related Rights in
the Work or (ii) assert any associated claims and causes of action
with respect to the Work, in either case contrary to Affirmer's express
Statement of Purpose.
.
4. Limitations and Disclaimers.
.
No trademark or patent rights held by Affirmer are waived,
abandoned, surrendered, licensed or otherwise affected by this
document.
.
Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties
of title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy,
or the present or absence of errors, whether or not discoverable,
all to the greatest extent permissible under applicable law.
.
Affirmer disclaims responsibility for clearing rights of other
persons that may apply to the Work or any use thereof, including
without limitation any person's Copyright and Related Rights in the
Work. Further, Affirmer disclaims responsibility for obtaining any
necessary consents, permissions or other rights required for any
use of the Work.
.
Affirmer understands and acknowledges that Creative Commons is not
a party to this document and has no duty or obligation with respect
to this CC0 or use of the Work.
License: BSD-3-Clause
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
a. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
b. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
c. Neither the name of the authors nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
'AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
......@@ -21,10 +21,10 @@ index 3c6ef3c..5346cb4 100644
YSIZE: 480
AREA_EXTENT: (-20037508.342789244, -10018754.171394622, 20037508.342789244, 10018754.171394622)
diff --git a/pyresample/test/test_geometry.py b/pyresample/test/test_geometry.py
index ef060d4..c35f304 100644
index eb1e13c..1a32806 100644
--- a/pyresample/test/test_geometry.py
+++ b/pyresample/test/test_geometry.py
@@ -389,7 +389,7 @@ class Test(unittest.TestCase):
@@ -411,7 +411,7 @@ class Test(unittest.TestCase):
swath_def = geometry.SwathDefinition(lons, lats)
filter_area = geometry.AreaDefinition('test', 'test', 'test',
{'proj': 'eqc', 'lon_0': 0.0,
......@@ -33,7 +33,7 @@ index ef060d4..c35f304 100644
8, 8,
(-20037508.34, -10018754.17, 20037508.34, 10018754.17))
filter = np.array([[1, 1, 1, 1, 0, 0, 0, 0],
@@ -414,7 +414,7 @@ class Test(unittest.TestCase):
@@ -436,7 +436,7 @@ class Test(unittest.TestCase):
data = np.array([1, 2, 3, 4])
filter_area = geometry.AreaDefinition('test', 'test', 'test',
{'proj': 'eqc', 'lon_0': 0.0,
......@@ -42,7 +42,7 @@ index ef060d4..c35f304 100644
8, 8,
(-20037508.34, -10018754.17, 20037508.34, 10018754.17))
filter = np.array([[1, 1, 1, 1, 0, 0, 0, 0],
@@ -449,7 +449,7 @@ class Test(unittest.TestCase):
@@ -471,7 +471,7 @@ class Test(unittest.TestCase):
data = np.dstack((data1, data2, data3))
filter_area = geometry.AreaDefinition('test', 'test', 'test',
{'proj': 'eqc', 'lon_0': 0.0,
......@@ -51,7 +51,7 @@ index ef060d4..c35f304 100644
8, 8,
(-20037508.34, -10018754.17, 20037508.34, 10018754.17))
filter = np.array([[1, 1, 1, 1, 0, 0, 0, 0],
@@ -518,7 +518,7 @@ class Test(unittest.TestCase):
@@ -540,7 +540,7 @@ class Test(unittest.TestCase):
def test_latlong_area(self):
area_def = geometry.AreaDefinition('', '', '',
......
.. _plot:
Plotting with pyresample and Basemap
Plotting with pyresample and Cartopy
====================================
Pyresample supports basic integration with Basemap (http://matplotlib.sourceforge.net/basemap).
Pyresample supports basic integration with Cartopy
(http://scitools.org.uk/cartopy/).
Displaying data quickly
-----------------------
Pyresample has some convenience functions for displaying data from a single channel.
The function **plot.show_quicklook** shows a Basemap image of a dataset for a specified AreaDefinition.
The function **plot.save_quicklook** saves the Basemap image directly to file.
Pyresample has some convenience functions for displaying data from a single
channel. The function **plot.show_quicklook** shows a Cartopy generated image
of a dataset for a specified AreaDefinition. The function
**plot.save_quicklook** saves the Cartopy image directly to file.
**Example usage:**
......@@ -66,8 +69,11 @@ Assuming **lons**, **lats** and **tb37v** are initialized with real data the res
The Globe projections
+++++++++++++++++++++
From v0.7.12 pyresample can use the geos, ortho and nsper projections with Basemap.
Assuming the file **areas.cfg** has the following area definition for an ortho projection area:
From v0.7.12 pyresample can use the geos, ortho and nsper projections with
Basemap. Starting with v1.9.0 quicklooks are now generated with Cartopy which
should also work with these projections. Assuming the file **areas.cfg** has
the following area definition for an ortho projection area:
.. code-block:: bash
......@@ -97,10 +103,52 @@ Assuming **lons**, **lats** and **tb37v** are initialized with real data the res
.. image:: _static/images/tb37v_ortho.png
Getting a Cartopy CRS
---------------------
To make more advanced plots than the preconfigured quicklooks Cartopy can be
used to work with mapped data alongside matplotlib. The below code is based
on
`this <http://scitools.org.uk/cartopy/docs/v0.16/gallery/geostationary.html>`_
Cartopy example. Pyresample allows any `AreaDefinition` to be converted to a
Cartopy CRS as long as Cartopy can represent the projection. Once an
AreaDefinition is converted to a CRS object it can be used like any other
Cartopy CRS object.
>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> from pyresample import load_area, save_quicklook, SwathDefinition
>>> from pyresample.kd_tree import resample_nearest
>>> lons = np.zeros(1000)
>>> lats = np.arange(-80, -90, -0.01)
>>> i04_data = np.arange(1000)
>>> swath_def = SwathDefinition(lons, lats)
>>> area_def = swath_def.compute_optimal_bb_area({'proj': 'lcc', 'lon_0': -95., 'lat_0': 25., 'lat_1': 25., 'lat_2': 25.})
>>> result = resample_nearest(swath_def, i04_data, area_def,
... radius_of_influence=20000, fill_value=None)
>>> crs = area_def.to_cartopy_crs()
>>> ax = plt.axes(projection=crs)
>>> ax.coastlines()
>>> ax.set_global()
>>> plt.imshow(data, transform=crs, extent=crs.bounds, origin='upper')
>>> plt.colorbar()
>>> plt.savefig('viirs_i04_cartopy.png')
Assuming **lons**, **lats**, and **i04_data** are initialized with real data
the result might look something like this:
.. image:: _static/images/viirs_i04_cartopy.png
Getting a Basemap object
------------------------
.. warning::
Basemap is no longer maintained. Cartopy (see above) should be used
instead.
In order to make more advanced plots than the preconfigured quicklooks a Basemap object can be generated from an
AreaDefintion using the **plot.area_def2basemap(area_def, **kwargs)** function.
AreaDefinition using the **plot.area_def2basemap(area_def, **kwargs)** function.
**Example usage:**
......@@ -129,17 +177,3 @@ Any keyword arguments (not concerning the projection) passed to **plot.area_def2
directly to the Basemap initialization.
For more information on how to plot with Basemap please refer to the Basemap and matplotlib documentation.
Limitations
-----------
The pyresample use of Basemap is basically a conversion from a pyresample AreaDefintion to a Basemap object
which allows for correct plotting of a resampled dataset using the **basemap.imshow** function.
Currently only the following set of Proj.4 arguments can be interpreted in the conversion:
{'proj', 'a', 'b', 'ellps', 'lon_0', 'lat_0', 'lon_1', 'lat_1', 'lon_2', 'lat_2', 'lat_ts'}
Any other Proj.4 parameters will be ignored.
If the ellipsoid is not defined in terms of 'ellps', 'a' or ('a', 'b') it will default to WGS84.
The xsize and ysize in an AreaDefinition will only be used during resampling when the image data for use in
**basemap.imshow** is created. The actual size and shape of the final plot is handled by matplotlib.
......@@ -19,6 +19,7 @@ import os
CHUNK_SIZE = int(os.getenv('PYTROLL_CHUNK_SIZE', 4096))
from pyresample.version import __version__ # noqa
# Backwards compatibility
from pyresample import geometry # noqa
from pyresample import grid # noqa
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (C) 2018 PyTroll developers
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Classes for geometry operations"""
from logging import getLogger
import warnings
import numpy as np
try:
from xarray import DataArray
except ImportError:
DataArray = np.ndarray
from pyresample.utils import proj4_str_to_dict
import cartopy.crs as ccrs
import shapely.geometry as sgeom
try:
from cartopy.crs import from_proj
except ImportError:
warnings.warn("'cartopy' >= 0.17 required for better 'from_proj' "
"functionality.")
from_proj = None
logger = getLogger(__name__)
_GLOBE_PARAMS = {'datum': 'datum',
'ellps': 'ellipse',
'a': 'semimajor_axis',
'b': 'semiminor_axis',
'f': 'flattening',
'rf': 'inverse_flattening',
'towgs84': 'towgs84',
'nadgrids': 'nadgrids'}
def _globe_from_proj4(proj4_terms):
"""Create a `Globe` object from PROJ.4 parameters."""
globe_terms = filter(lambda term: term[0] in _GLOBE_PARAMS,
proj4_terms.items())
globe = ccrs.Globe(**{_GLOBE_PARAMS[name]: value for name, value in
globe_terms})
return globe
# copy of class in cartopy (before it was released)
class _PROJ4Projection(ccrs.Projection):
def __init__(self, proj4_terms, globe=None, bounds=None):
terms = proj4_str_to_dict(proj4_terms)
globe = _globe_from_proj4(terms) if globe is None else globe
other_terms = []
for term in terms.items():
if term[0] not in _GLOBE_PARAMS:
other_terms.append(term)
super(_PROJ4Projection, self).__init__(other_terms, globe)
self.bounds = bounds
def __repr__(self):
return '_PROJ4Projection({})'.format(self.proj4_init)
@property
def boundary(self):
x0, x1, y0, y1 = self.bounds
return sgeom.LineString([(x0, y0), (x0, y1), (x1, y1), (x1, y0),
(x0, y0)])
@property
def x_limits(self):
x0, x1, y0, y1 = self.bounds
return (x0, x1)
@property
def y_limits(self):
x0, x1, y0, y1 = self.bounds
return (y0, y1)
@property
def threshold(self):
x0, x1, y0, y1 = self.bounds
return min(x1 - x0, y1 - y0) / 100.
def _lesser_from_proj(proj4_terms, globe=None, bounds=None):
"""Not-as-good version of cartopy's 'from_proj' function.
The user doesn't have a newer version of Cartopy so there is
no `from_proj` function to use which does a fancier job of
creating CRS objects from PROJ.4 strings than this does.
"""
return _PROJ4Projection(proj4_terms, globe=globe, bounds=bounds)
if from_proj is None:
from_proj = _lesser_from_proj
......@@ -17,8 +17,8 @@
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Classes for geometry operations"""
......@@ -90,6 +90,13 @@ class BaseDefinition(object):
self.lons = lons
self.ndim = None
self.cartesian_coords = None
self.hash = None
def __hash__(self):
"""Compute the hash of this object."""
if self.hash is None:
self.hash = int(self.update_hash().hexdigest(), 16)
return self.hash
def __eq__(self, other):
"""Test for approximate equality"""
......@@ -491,22 +498,23 @@ class SwathDefinition(CoordinateDefinition):
elif lons.ndim > 2:
raise ValueError('Only 1 and 2 dimensional swaths are allowed')
self.hash = None
def __hash__(self):
"""Compute the hash of this object."""
if self.hash is None:
hasher = hashlib.sha1()
hasher.update(get_array_hashable(self.lons))
hasher.update(get_array_hashable(self.lats))
self.hash = int(self.update_hash().hexdigest(), 16)
return self.hash
def update_hash(self, the_hash=None):
if the_hash is None:
the_hash = hashlib.sha1()
the_hash.update(get_array_hashable(self.lons))
the_hash.update(get_array_hashable(self.lats))
try:
if self.lons.mask is not np.bool_(False):
hasher.update(get_array_hashable(self.lons.mask))
the_hash.update(get_array_hashable(self.lons.mask))
except AttributeError:
pass
self.hash = int(hasher.hexdigest(), 16)
return self.hash
return the_hash
def get_lonlats_dask(self, chunks=CHUNK_SIZE):
"""Get the lon lats as a single dask array."""
......@@ -531,15 +539,33 @@ class SwathDefinition(CoordinateDefinition):
proj_dict2points = {'proj': 'omerc', 'lat_0': lat, 'ellps': ellipsoid,
'lat_1': lat1, 'lon_1': lon1,
'lat_2': lat2, 'lon_2': lon2}
'lat_2': lat2, 'lon_2': lon2, 'no_rot': True}
# return proj_dict2points
# We need to compute alpha-based omerc for geotiff support
lonc, lat0 = Proj(**proj_dict2points)(0, 0, inverse=True)
az1, az2, dist = Geod(**proj_dict2points).inv(lonc, lat0, lon2, lat2)
azimuth = az1
az1, az2, dist = Geod(**proj_dict2points).inv(lonc, lat0, lon1, lat1)
del az2, dist
return {'proj': 'omerc', 'alpha': float(az1),
if abs(az1 - azimuth) > 1:
if abs(az2 - azimuth) > 1:
logger.warning("Can't find appropriate azimuth.")
else:
azimuth += az2
azimuth /= 2
else:
azimuth += az1
azimuth /= 2
if abs(azimuth) > 90:
azimuth = 180 + azimuth
prj_params = {'proj': 'omerc', 'alpha': float(azimuth),
'lat_0': float(lat0), 'lonc': float(lonc),
'no_rot': True, 'ellps': ellipsoid}
return prj_params
def _compute_generic_parameters(self, projection, ellipsoid):
"""Compute the projection bb parameters for most projections."""
lines, cols = self.lons.shape
......@@ -843,6 +869,12 @@ class AreaDefinition(BaseDefinition):
self.dtype = dtype
def __hash__(self):
"""Compute the hash of this object."""
if self.hash is None:
self.hash = int(self.update_hash().hexdigest(), 16)
return self.hash
@property
def proj_str(self):
return utils.proj4_dict_to_str(self.proj_dict, sort=True)
......@@ -866,6 +898,17 @@ class AreaDefinition(BaseDefinition):
proj_str, self.x_size, self.y_size,
self.area_extent)
__repr__ = __str__
def to_cartopy_crs(self):
from pyresample._cartopy import from_proj
bounds = (self.area_extent[0],
self.area_extent[2],
self.area_extent[1],
self.area_extent[3])
crs = from_proj(self.proj_str, bounds=bounds)
return crs
def create_areas_def(self):
to_dump = OrderedDict()
res = OrderedDict()
......@@ -902,8 +945,6 @@ class AreaDefinition(BaseDefinition):
area_extent=self.area_extent)
return area_def_str
__repr__ = __str__
def __eq__(self, other):
"""Test for equality"""
......@@ -919,12 +960,14 @@ class AreaDefinition(BaseDefinition):
return not self.__eq__(other)
def __hash__(self):
return hash((
self.proj_str,
self.shape,
self.area_extent
))
def update_hash(self, the_hash=None):
"""Update a hash, or return a new one if needed."""
if the_hash is None:
the_hash = hashlib.sha1()
the_hash.update(self.proj_str.encode('utf-8'))
the_hash.update(np.array(self.shape))
the_hash.update(np.array(self.area_extent))
return the_hash
def colrow2lonlat(self, cols, rows):
"""
......
......@@ -175,7 +175,7 @@ def resample_gauss(source_geo_def, data, target_geo_def,
sigmas.__iter__()
sigma_list = sigmas
is_multi_channel = True
except: # noqa: E722
except AttributeError:
sigma_list = [sigmas]
for sigma in sigma_list:
......@@ -244,13 +244,13 @@ def resample_custom(source_geo_def, data, target_geo_def,
Counts of number of source values used in weighting per pixel
"""
try:
if not isinstance(weight_funcs, (list, tuple)):
if not isinstance(weight_funcs, types.FunctionType):
raise TypeError('weight_func must be function object')
else:
for weight_func in weight_funcs:
if not isinstance(weight_func, types.FunctionType):
raise TypeError('weight_func must be function object')
except: # noqa: E722
if not isinstance(weight_funcs, types.FunctionType):
raise TypeError('weight_func must be function object')
return _resample(source_geo_def, data, target_geo_def, 'custom',
radius_of_influence, neighbours=neighbours,
......
# pyresample, Resampling of remote sensing image data in python
#!/usr/bin/env python
# encoding: utf8
#
# Copyright (C) 2010-2015
# Copyright (C) 2010-2018
#
# Authors:
# Esben S. Nielsen
......@@ -16,8 +17,8 @@
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
import numpy as np
......@@ -103,6 +104,11 @@ def area_def2basemap(area_def, **kwargs):
bmap : Basemap object
"""
import warnings
warnings.warn("Basemap is no longer maintained. Please switch to cartopy "
"by using 'area_def.to_cartopy_crs()'. See the pyresample "
"documentation for more details.", DeprecationWarning)
from mpl_toolkits.basemap import Basemap
try:
a, b = ellps2axis(area_def.proj_dict['ellps'])
......@@ -153,12 +159,9 @@ def area_def2basemap(area_def, **kwargs):
return Basemap(**basemap_args)
def _get_quicklook(area_def, data, vmin=None, vmax=None,
def _basemap_get_quicklook(area_def, data, vmin=None, vmax=None,
label='Variable (units)', num_meridians=45,
num_parallels=10, coast_res='c', cmap='jet'):
"""Get default Basemap matplotlib plot
"""
num_parallels=10, coast_res='110m', cmap='jet'):
if area_def.shape != data.shape:
raise ValueError('area_def shape %s does not match data shape %s' %
(list(area_def.shape), list(data.shape)))
......@@ -175,9 +178,66 @@ def _get_quicklook(area_def, data, vmin=None, vmax=None,
return plt
def _get_quicklook(area_def, data, vmin=None, vmax=None,
label='Variable (units)', num_meridians=45,
num_parallels=10, coast_res='110m', cmap='jet'):
"""Get default Basemap matplotlib plot
"""
bmap_to_cartopy_res = {
'c': '110m',
'l': '110m',
'i': '50m',
'h': '10m',
'f': '10m'
}
try:
from pyresample import _cartopy # noqa
except ImportError:
if coast_res.endswith('m'):
_rev_map = {v: k for k, v in bmap_to_cartopy_res.items()}
coast_res = _rev_map[coast_res]
return _basemap_get_quicklook(
area_def, data, vmin, vmax, label, num_meridians,
num_parallels, coast_res=coast_res, cmap=cmap)
if coast_res and coast_res not in ['110m', '50m', '10m']:
import warnings
warnings.warn("'coast_res' should be either '110m', '50m', '10m'.")
coast_res = {
'c': '110m',
'l': '110m',
'i': '50m',
'h': '10m',
'f': '10m'
}[coast_res]
if area_def.shape != data.shape:
raise ValueError('area_def shape %s does not match data shape %s' %
(list(area_def.shape), list(data.shape)))
import matplotlib.pyplot as plt
crs = area_def.to_cartopy_crs()
ax = plt.axes(projection=crs)
ax.coastlines(resolution=coast_res)
ax.set_global()
xlocs = None
ylocs = None
if num_meridians:
xlocs = np.arange(-180, 180, num_meridians)
if num_parallels:
ylocs = np.arange(-90, 90, num_parallels)
ax.gridlines(xlocs=xlocs, ylocs=ylocs)
if not (np.ma.isMaskedArray(data) and data.mask.all()):
col = plt.imshow(data, transform=crs, extent=crs.bounds,
origin='upper', vmin=vmin, vmax=vmax, cmap=cmap)
plt.colorbar(col, shrink=0.5, pad=0.05).set_label(label)
return plt
def show_quicklook(area_def, data, vmin=None, vmax=None,
label='Variable (units)', num_meridians=45,
num_parallels=10, coast_res='c', cmap='jet'):
num_parallels=10, coast_res='110m', cmap='jet'):
"""Display default quicklook plot
Parameters
......@@ -214,7 +274,7 @@ def show_quicklook(area_def, data, vmin=None, vmax=None,
def save_quicklook(filename, area_def, data, vmin=None, vmax=None,
label='Variable (units)', num_meridians=45,
num_parallels=10, coast_res='c', backend='AGG',
num_parallels=10, coast_res='110m', backend='AGG',
cmap='jet'):
"""Display default quicklook plot
......