diff --git a/.github/workflows/basemap-data-hires.yml b/.github/workflows/basemap-data-hires.yml deleted file mode 100644 index a2030f33d..000000000 --- a/.github/workflows/basemap-data-hires.yml +++ /dev/null @@ -1,136 +0,0 @@ -name: basemap-data-hires - -env: - PKGDIR: "packages/basemap_data_hires" - PYTHONWARNINGS: "ignore:DEPRECATION" - PIP_DISABLE_PIP_VERSION_CHECK: 1 - PIP_PREFER_BINARY: 1 - PIP_TIMEOUT: 10 - PIP_RETRIES: 0 - -on: - push: - paths: - - ".github/workflows/basemap-data-hires.yml" - - "packages/basemap_data_hires/**" - pull_request: - paths: - - ".github/workflows/basemap-data-hires.yml" - - "packages/basemap_data_hires/**" - workflow_dispatch: - -jobs: - - checkout: - runs-on: ubuntu-latest - steps: - - - name: Checkout - uses: actions/checkout@v3 - - - name: Upload checkout - uses: actions/upload-artifact@v3 - with: - name: checkout - path: . - - build: - strategy: - matrix: - python-version: - ["2.7"] - max-parallel: 1 - needs: checkout - runs-on: ubuntu-latest - container: "pylegacy/python:${{ matrix.python-version }}-debian-9" - steps: - - - name: Download checkout - uses: actions/download-artifact@v3 - with: - name: checkout - path: . - - - name: Build sdist and wheel - run: | - cd ${{ env.PKGDIR }} - python setup.py sdist - pip wheel -w dist --no-deps dist/*.zip - - - name: Upload build artifacts - uses: actions/upload-artifact@v3 - with: - name: artifacts-build - path: ${{ env.PKGDIR }}/dist - - test: - strategy: - matrix: - python-version: - ["2.6", "2.7", "3.2", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", - "3.9", "3.10", "3.11"] - max-parallel: 3 - fail-fast: false - needs: build - runs-on: ubuntu-latest - container: "pylegacy/python:${{ matrix.python-version }}-debian-9" - steps: - - - name: Download checkout - uses: actions/download-artifact@v3 - with: - name: checkout - path: . - - - name: Download build artifacts - uses: actions/download-artifact@v3 - with: - name: artifacts-build - path: ${{ env.PKGDIR }}/dist - - - name: Install package - run: | - pip install ${{ env.PKGDIR }}/dist/*.whl - - - name: Test package - run: | - python -c "from mpl_toolkits import basemap_data; print(basemap_data)" - - upload: - strategy: - matrix: - python-version: - ["2.7"] - max-parallel: 1 - if: startsWith(github.event.ref, 'refs/tags/v') - needs: test - runs-on: ubuntu-latest - container: "pylegacy/python:${{ matrix.python-version }}-debian-9" - environment: PyPI - steps: - - - name: Download build artifacts - uses: actions/download-artifact@v3 - with: - name: artifacts-build - path: ${{ env.PKGDIR }}/dist - - - name: Install upload requirements - run: | - pip install twine - - - name: Check distributables - run: | - python -m twine check \ - ${{ env.PKGDIR }}/dist/*.zip \ - ${{ env.PKGDIR }}/dist/*.whl - - - name: Upload distributables - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: "${{ secrets.PYPI_TOKEN }}" - TWINE_REPOSITORY_URL: "${{ secrets.PYPI_REPOSITORY_URL }}" - run: | - python -m twine upload --skip-existing \ - ${{ env.PKGDIR }}/dist/*.zip \ - ${{ env.PKGDIR }}/dist/*.whl diff --git a/.github/workflows/basemap-data.yml b/.github/workflows/basemap-data.yml deleted file mode 100644 index 3958e1f09..000000000 --- a/.github/workflows/basemap-data.yml +++ /dev/null @@ -1,136 +0,0 @@ -name: basemap-data - -env: - PKGDIR: "packages/basemap_data" - PYTHONWARNINGS: "ignore:DEPRECATION" - PIP_DISABLE_PIP_VERSION_CHECK: 1 - PIP_PREFER_BINARY: 1 - PIP_TIMEOUT: 10 - PIP_RETRIES: 0 - -on: - push: - paths: - - ".github/workflows/basemap-data.yml" - - "packages/basemap_data/**" - pull_request: - paths: - - ".github/workflows/basemap-data.yml" - - "packages/basemap_data/**" - workflow_dispatch: - -jobs: - - checkout: - runs-on: ubuntu-latest - steps: - - - name: Checkout - uses: actions/checkout@v3 - - - name: Upload checkout - uses: actions/upload-artifact@v3 - with: - name: checkout - path: . - - build: - strategy: - matrix: - python-version: - ["2.7"] - max-parallel: 1 - needs: checkout - runs-on: ubuntu-latest - container: "pylegacy/python:${{ matrix.python-version }}-debian-9" - steps: - - - name: Download checkout - uses: actions/download-artifact@v3 - with: - name: checkout - path: . - - - name: Build sdist and wheel - run: | - cd ${{ env.PKGDIR }} - python setup.py sdist - pip wheel -w dist --no-deps dist/*.zip - - - name: Upload build artifacts - uses: actions/upload-artifact@v3 - with: - name: artifacts-build - path: ${{ env.PKGDIR }}/dist - - test: - strategy: - matrix: - python-version: - ["2.6", "2.7", "3.2", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", - "3.9", "3.10", "3.11"] - max-parallel: 3 - fail-fast: false - needs: build - runs-on: ubuntu-latest - container: "pylegacy/python:${{ matrix.python-version }}-debian-9" - steps: - - - name: Download checkout - uses: actions/download-artifact@v3 - with: - name: checkout - path: . - - - name: Download build artifacts - uses: actions/download-artifact@v3 - with: - name: artifacts-build - path: ${{ env.PKGDIR }}/dist - - - name: Install package - run: | - pip install ${{ env.PKGDIR }}/dist/*.whl - - - name: Test package - run: | - python -c "from mpl_toolkits import basemap_data; print(basemap_data)" - - upload: - strategy: - matrix: - python-version: - ["2.7"] - max-parallel: 1 - if: startsWith(github.event.ref, 'refs/tags/v') - needs: test - runs-on: ubuntu-latest - container: "pylegacy/python:${{ matrix.python-version }}-debian-9" - environment: PyPI - steps: - - - name: Download build artifacts - uses: actions/download-artifact@v3 - with: - name: artifacts-build - path: ${{ env.PKGDIR }}/dist - - - name: Install upload requirements - run: | - pip install twine - - - name: Check distributables - run: | - python -m twine check \ - ${{ env.PKGDIR }}/dist/*.zip \ - ${{ env.PKGDIR }}/dist/*.whl - - - name: Upload distributables - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: "${{ secrets.PYPI_TOKEN }}" - TWINE_REPOSITORY_URL: "${{ secrets.PYPI_REPOSITORY_URL }}" - run: | - python -m twine upload --skip-existing \ - ${{ env.PKGDIR }}/dist/*.zip \ - ${{ env.PKGDIR }}/dist/*.whl diff --git a/.github/workflows/basemap-for-manylinux.yml b/.github/workflows/basemap-for-manylinux.yml deleted file mode 100644 index dab8d28b0..000000000 --- a/.github/workflows/basemap-for-manylinux.yml +++ /dev/null @@ -1,383 +0,0 @@ -name: basemap-for-manylinux - -env: - PKGDIR: "packages/basemap" - PYTHONWARNINGS: "ignore:DEPRECATION" - PIP_DISABLE_PIP_VERSION_CHECK: 1 - PIP_PREFER_BINARY: 1 - PIP_TIMEOUT: 10 - PIP_RETRIES: 0 - -on: - push: - paths: - - ".github/workflows/basemap-for-manylinux.yml" - - "packages/basemap/**" - pull_request: - paths: - - ".github/workflows/basemap-for-manylinux.yml" - - "packages/basemap/**" - workflow_dispatch: - -jobs: - - checkout: - runs-on: ubuntu-latest - steps: - - - name: Checkout - uses: actions/checkout@v1 - - - name: Upload checkout - uses: actions/upload-artifact@v1 - with: - name: checkout - path: . - - lint: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: - ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] - max-parallel: 3 - fail-fast: false - needs: checkout - container: "pylegacy/python:${{ matrix.python-version }}-debian-9" - steps: - - - name: Download checkout - uses: actions/download-artifact@v1 - with: - name: checkout - path: . - - - name: Install lint requirements - run: | - cd ${{ env.PKGDIR }} - pip install -r requirements-lint.txt - - - name: Install library requirements - run: | - cd ${{ env.PKGDIR }} - pip install -r requirements.txt - - - name: Run Flake8 - run: | - cd ${{ env.PKGDIR }} - if [ -x "$(command -v flake8)" ]; then - flake8 src/mpl_toolkits/basemap/cm.py src/mpl_toolkits/basemap/diagnostic.py src/mpl_toolkits/basemap/proj.py src/mpl_toolkits/basemap/solar.py test; - fi - - - name: Run PyLint - run: | - cd ${{ env.PKGDIR }} - if [ -x "$(command -v pylint)" ]; then - pylint src/mpl_toolkits/basemap/cm.py src/mpl_toolkits/basemap/diagnostic.py src/mpl_toolkits/basemap/proj.py src/mpl_toolkits/basemap/solar.py test; - fi - - build-geos: - strategy: - matrix: - arch: - ["x64", "x86"] - max-parallel: 2 - fail-fast: false - needs: lint - runs-on: ubuntu-latest - container: "pylegacy/${{ matrix.arch }}-python:3.8-debian-4" - steps: - - - name: Download checkout - uses: actions/download-artifact@v1 - with: - name: checkout - path: . - - - name: Install CMake 3.6.2 - run: | - apt-get update - apt-get install -y libidn11 - pkgvers=3.6.2 - pkgname=cmake - pkgcode=cmake-${pkgvers} - case "${{ matrix.arch }}" in - x86) pkgfile=${pkgcode}-Linux-i386.tar.gz;; - *) pkgfile=${pkgcode}-Linux-x86_64.tar.gz;; - esac - wget https://github.com/Kitware/CMake/releases/download/v${pkgvers}/${pkgfile} -P /tmp - tar -xf /tmp/${pkgfile} --strip-components=1 -C /usr - rm -rf /tmp/${pkgfile} - - - name: Install GCC toolchain - run: | - apt-get update - apt-get install -y gcc g++ make - - - name: Build GEOS from source - run: | - cd ${{ env.PKGDIR }} - python -c "import utils; utils.GeosLibrary('3.6.5').build('extern', njobs=16)" - - - name: Upload GEOS artifacts - uses: actions/upload-artifact@v1 - with: - name: artifacts-geos-${{ matrix.arch }} - path: ${{ env.PKGDIR }}/extern - - build: - strategy: - matrix: - arch: - ["x64", "x86"] - python-version: - ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] - max-parallel: 3 - fail-fast: false - needs: build-geos - runs-on: ubuntu-latest - container: "pylegacy/${{ matrix.arch }}-python:${{ matrix.python-version }}-debian-4" - steps: - - - name: Download checkout - uses: actions/download-artifact@v1 - with: - name: checkout - path: . - - - name: Download GEOS artifacts - uses: actions/download-artifact@v1 - with: - name: artifacts-geos-${{ matrix.arch }} - path: ${{ env.PKGDIR }}/extern - - - name: Install GCC toolchain - run: | - apt-get update - apt-get install -y gcc g++ make - - - name: Build old numpy from source - run: | - case "${{ matrix.python-version }}" in - 2.6|3.[23]) pkgvers=1.11.3;; - 2.7|3.[456789]) pkgvers=1.16.6;; - 3.10) pkgvers=1.21.4;; - *) pkgvers=1.23.3;; - esac - # Dirty solution to get NumPy headers for Python 3.11. - if [ "${{ matrix.python-version }}" = "3.11" ]; then - case "${{ matrix.arch }}" in - x64) kwds="--plat=manylinux_2_17_x86_64" ;; - x86) kwds="--plat=manylinux_2_17_i686" ;; - esac - pip download --no-deps ${kwds} "numpy==${pkgvers}" - oldpkgfile=$(ls *.whl | head -n1) - newpkgfile=$(echo "${oldpkgfile}" | sed 's/manylinux_2_17/linux/') - mv "${oldpkgfile}" "${newpkgfile}" - pip install "${newpkgfile}" - rm "${newpkgfile}" - else - pip install "numpy == ${pkgvers}" - fi - - - name: Build wheel - run: | - sitepkgdir=$(pip show numpy 2>/dev/null | grep Location: | cut -d' ' -f2) - export GEOS_DIR="${GITHUB_WORKSPACE}/${{ env.PKGDIR }}/extern" - export NUMPY_INCLUDE_PATH=${sitepkgdir}/numpy/core/include - if [ "${{ matrix.python-version }}" = "3.11" ]; then - kwds="--no-build-isolation" - pip install setuptools wheel "cython >= 0.29, < 3.1" - fi - cd ${{ env.PKGDIR }} - python setup.py sdist - pip wheel -w dist --no-deps ${kwds} dist/*.zip - - - name: Upload build artifacts - uses: actions/upload-artifact@v1 - with: - name: artifacts-build-${{ matrix.arch }}-${{ matrix.python-version }} - path: ${{ env.PKGDIR }}/dist - - repair: - strategy: - matrix: - arch: - ["x64", "x86"] - python-version: - ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] - max-parallel: 3 - fail-fast: false - needs: build - runs-on: ubuntu-latest - container: "pylegacy/${{ matrix.arch }}-python:3.8-debian-9" - steps: - - - name: Download GEOS artifacts - uses: actions/download-artifact@v1 - with: - name: artifacts-geos-${{ matrix.arch }} - path: ${{ env.PKGDIR }}/extern - - - name: Download build artifacts - uses: actions/download-artifact@v1 - with: - name: artifacts-build-${{ matrix.arch }}-${{ matrix.python-version }} - path: ${{ env.PKGDIR }}/dist - - - name: Install auditwheel - run: | - apt-get update - apt-get install -y unzip - pip install patchelf - pip install "auditwheel < 4.0" - - - name: Repair wheel - run: | - cd ${{ env.PKGDIR }} - export LD_LIBRARY_PATH="$(readlink -f extern/lib)" - auditwheel repair -w dist dist/*.whl - - - name: Upload build artifacts - uses: actions/upload-artifact@v1 - with: - name: artifacts-build-${{ matrix.arch }}-${{ matrix.python-version }} - path: ${{ env.PKGDIR }}/dist - - test: - strategy: - matrix: - arch: - ["x64", "x86"] - python-version: - ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] - max-parallel: 3 - fail-fast: false - needs: repair - runs-on: ubuntu-latest - container: "pylegacy/${{ matrix.arch }}-python:${{ matrix.python-version }}-debian-9" - steps: - - - name: Download checkout - uses: actions/download-artifact@v1 - with: - name: checkout - path: . - - - name: Download build artifacts - uses: actions/download-artifact@v1 - with: - name: artifacts-build-${{ matrix.arch }}-${{ matrix.python-version }} - path: ${{ env.PKGDIR }}/dist - - - name: Install numpy from source - run: | - apt-get update - apt-get install -y gcc g++ make - pip install "numpy < 1.24" - if: matrix.arch == 'x86' && (matrix.python-version >= '3.8' || matrix.python-version >= '3.10') - - - name: Install test requirements - run: | - cd ${{ env.PKGDIR }} - pip install -r requirements-test.txt - - - name: Install package (full) - run: | - whlpath=$(ls ${{ env.PKGDIR }}/dist/*-manylinux1*.whl | head -n1) - pip install "${whlpath}[full]" - - - name: Fix CA certificates location - run: | - sslvers=$(python -c 'import ssl; print(".".join(map(str, ssl._OPENSSL_API_VERSION[:3])))') - sslfold=/opt/openssl-${sslvers}/ssl - mkdir -p "${sslfold}" - cp "/etc/ssl/cert.pem" "${sslfold}/cert.pem" - - - name: Test package - run: | - cd ${{ env.PKGDIR }} - export COVERAGE_FILE=.coverage.${{ matrix.python-version }} - python -m pytest \ - --cov="mpl_toolkits.basemap" --cov-report=term \ - --ignore=dist --ignore=build - - - name: Upload test artifacts - uses: actions/upload-artifact@v1 - with: - name: test - path: ${{ env.PKGDIR }}/.coverage.${{ matrix.python-version }} - - coverage: - needs: test - runs-on: ubuntu-latest - container: "pylegacy/python:3.8-debian-9" - steps: - - - name: Checkout - uses: actions/checkout@v1 - - - name: Download test artifacts - uses: actions/download-artifact@v1 - with: - name: test - path: ${{ env.PKGDIR }} - - - name: Install test requirements - run: | - cd ${{ env.PKGDIR }} - pip install -r requirements-test.txt - - - name: Compute combined coverage - run: | - cd ${{ env.PKGDIR }} - coverage combine - coverage html - coverage report - - - name: Upload coverage artifacts - uses: actions/upload-artifact@v1 - with: - name: coverage - path: ${{ env.PKGDIR }}/htmlcov - - upload: - strategy: - matrix: - arch: - ["x64", "x86"] - python-version: - ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] - max-parallel: 1 - if: startsWith(github.event.ref, 'refs/tags/v') - needs: test - runs-on: ubuntu-latest - container: "pylegacy/${{ matrix.arch }}-python:${{ matrix.python-version }}-debian-9" - environment: PyPI - steps: - - - name: Download build artifacts - uses: actions/download-artifact@v1 - with: - name: artifacts-build-${{ matrix.arch }}-${{ matrix.python-version }} - path: ${{ env.PKGDIR }}/dist - - - name: Install upload requirements - run: | - pip install twine - - - name: Check distributables - run: | - python -m twine check \ - ${{ env.PKGDIR }}/dist/*.zip \ - ${{ env.PKGDIR }}/dist/*-manylinux1*.whl - - - name: Upload distributables - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: "${{ secrets.PYPI_TOKEN }}" - TWINE_REPOSITORY_URL: "${{ secrets.PYPI_REPOSITORY_URL }}" - run: | - python -m twine upload --skip-existing \ - ${{ env.PKGDIR }}/dist/*.zip \ - ${{ env.PKGDIR }}/dist/*-manylinux1*.whl diff --git a/.github/workflows/basemap-for-windows.yml b/.github/workflows/basemap-for-windows.yml deleted file mode 100644 index c35705d0d..000000000 --- a/.github/workflows/basemap-for-windows.yml +++ /dev/null @@ -1,320 +0,0 @@ -name: basemap-for-windows - -env: - PKGDIR: "packages/basemap" - PYTHONWARNINGS: "ignore:DEPRECATION" - PIP_DISABLE_PIP_VERSION_CHECK: 1 - PIP_PREFER_BINARY: 1 - PIP_TIMEOUT: 10 - PIP_RETRIES: 0 - -on: - push: - paths: - - ".github/workflows/basemap-for-windows.yml" - - "!packages/basemap/doc/**" - - "packages/basemap/**" - pull_request: - paths: - - ".github/workflows/basemap-for-windows.yml" - - "!packages/basemap/doc/**" - - "packages/basemap/**" - workflow_dispatch: - -jobs: - - checkout: - runs-on: windows-2019 - steps: - - - name: Checkout - uses: actions/checkout@v3 - - - name: Upload checkout - uses: actions/upload-artifact@v3 - with: - name: checkout - path: . - - lint: - runs-on: windows-2019 - strategy: - matrix: - python-version: - ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] - max-parallel: 3 - fail-fast: false - needs: checkout - steps: - - - name: Download checkout - uses: actions/download-artifact@v3 - with: - name: checkout - path: . - - - name: Set Python - uses: pylegacy/actions/setup-pyenv-win@v2 - with: - architecture: ${{ matrix.arch }} - python-version: ${{ matrix.python-version }} - - - name: Set Python base packages - run: | - python -m pip install --upgrade pip setuptools wheel - - - name: Install lint requirements - run: | - cd ${{ env.PKGDIR }} - python -m pip install -r requirements-lint.txt - - - name: Install library requirements - run: | - cd ${{ env.PKGDIR }} - python -m pip install -r requirements.txt - - - name: Run Flake8 - run: | - cd ${{ env.PKGDIR }} - if (Get-Command flake8 -errorAction SilentlyContinue) - { - flake8 src/mpl_toolkits/basemap/cm.py src/mpl_toolkits/basemap/diagnostic.py src/mpl_toolkits/basemap/proj.py src/mpl_toolkits/basemap/solar.py test; - } - - - name: Run PyLint - run: | - cd ${{ env.PKGDIR }} - if (Get-Command pylint -errorAction SilentlyContinue) - { - pylint src/mpl_toolkits/basemap/cm.py src/mpl_toolkits/basemap/diagnostic.py src/mpl_toolkits/basemap/proj.py src/mpl_toolkits/basemap/solar.py test; - } - - build-geos: - strategy: - matrix: - arch: - ["x64", "x86"] - msvc-toolset: - ["9.0", "14.0"] - include: - - msvc-toolset: "9.0" - python-version: "2.7" - - msvc-toolset: "14.0" - python-version: "3.5" - max-parallel: 4 - fail-fast: false - needs: lint - runs-on: windows-2019 - steps: - - - name: Download checkout - uses: actions/download-artifact@v3 - with: - name: checkout - path: . - - - name: Set MSVC toolset - uses: pylegacy/actions/setup-msvc@v2 - with: - arch: ${{ matrix.arch }} - toolset: ${{ matrix.msvc-toolset }} - - - name: Set CMake - uses: jwlawson/actions-setup-cmake@v1.13 - with: - cmake-version: "3.24.2" - - - name: Set Python - uses: pylegacy/actions/setup-pyenv-win@v2 - with: - architecture: ${{ matrix.arch }} - python-version: ${{ matrix.python-version }} - - - name: Build GEOS from source - run: | - cd ${{ env.PKGDIR }} - python -c "import utils; utils.GeosLibrary('3.6.5').build('extern', toolset='${{ matrix.msvc-toolset }}', njobs=16)" - - - name: Upload GEOS artifacts - uses: actions/upload-artifact@v3 - with: - name: artifacts-geos-${{ matrix.arch }}-msvc${{ matrix.msvc-toolset }} - path: ${{ env.PKGDIR }}/extern - - build: - strategy: - matrix: - arch: - ["x64", "x86"] - python-version: - ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] - max-parallel: 3 - fail-fast: false - needs: build-geos - runs-on: windows-2019 - steps: - - - name: Download checkout - uses: actions/download-artifact@v3 - with: - name: checkout - path: . - - - name: Set Python - uses: pylegacy/actions/setup-pyenv-win@v2 - with: - architecture: ${{ matrix.arch }} - python-version: ${{ matrix.python-version }} - - - name: Set Python base packages - run: | - python -m pip install --upgrade pip setuptools wheel - - - name: Build old numpy from source - run: | - Switch -regex ("${{ matrix.python-version }}") { - "^2\.6|3\.[123]$" { Set-Variable -Name "pkgvers" -Value "1.11.3" } - "^2\.7|3\.[456789]$" { Set-Variable -Name "pkgvers" -Value "1.16.6" } - "^3\.10$" { Set-Variable -Name "pkgvers" -Value "1.21.4" } - default { Set-Variable -Name "pkgvers" -Value "1.23.3" } - } - $env:SETUPTOOLS_USE_DISTUTILS = "stdlib" - python -m pip install "numpy == ${pkgvers}" - - - name: Set MSVC toolset version - run: | - if ("${{ matrix.python-version }}" -eq "2.7") { - echo "msvc-toolset=9.0" >> $env:GITHUB_ENV - } else { - echo "msvc-toolset=14.0" >> $env:GITHUB_ENV - } - - - name: Set MSVC toolset - uses: pylegacy/actions/setup-msvc@v2 - with: - arch: ${{ matrix.arch }} - toolset: ${{ env.msvc-toolset }} - - - name: Download GEOS artifacts - uses: actions/download-artifact@v3 - with: - name: artifacts-geos-${{ matrix.arch }}-msvc${{ env.msvc-toolset }} - path: ${{ env.PKGDIR }}/extern - - - name: Build sdist and wheel - run: | - cd ${{ env.PKGDIR }} - $env:GEOS_DIR = "$env:GITHUB_WORKSPACE/${{ env.PKGDIR }}/extern" - python -m pip install -r requirements-setup.txt - python setup.py sdist - python -m pip wheel -w dist --no-deps (Get-Item dist/*.zip) - - - name: Upload build artifacts - uses: actions/upload-artifact@v3 - with: - name: artifacts-build-${{ matrix.arch }}-${{ matrix.python-version }} - path: ${{ env.PKGDIR }}/dist - - test: - strategy: - matrix: - arch: - ["x64", "x86"] - python-version: - ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] - max-parallel: 3 - fail-fast: false - needs: build - runs-on: windows-2019 - steps: - - - name: Download checkout - uses: actions/download-artifact@v3 - with: - name: checkout - path: . - - - name: Download build artifacts - uses: actions/download-artifact@v3 - with: - name: artifacts-build-${{ matrix.arch }}-${{ matrix.python-version }} - path: ${{ env.PKGDIR }}/dist - - - name: Set Python - uses: pylegacy/actions/setup-pyenv-win@v2 - with: - architecture: ${{ matrix.arch }} - python-version: ${{ matrix.python-version }} - - - name: Set Python base packages - run: | - python -m pip install --upgrade pip setuptools wheel - - - name: Install test requirements - run: | - cd ${{ env.PKGDIR }} - pip install -r requirements-test.txt - - - name: Install package (full) - run: | - $whlpath = "$(Get-Item ${{ env.PKGDIR }}/dist/*-win*.whl)" - python -m pip install "${whlpath}[full]" - - - name: Test package - run: | - cd ${{ env.PKGDIR }} - $env:COVERAGE_FILE = ".coverage.${{ matrix.python-version }}" - python -m pytest ` - --cov="mpl_toolkits.basemap" --cov-report=term ` - --ignore=dist --ignore=build - - - name: Upload test artifacts - uses: actions/upload-artifact@v1 - with: - name: test - path: ${{ env.PKGDIR }}/.coverage.${{ matrix.python-version }} - - upload: - strategy: - matrix: - arch: - ["x64", "x86"] - python-version: - ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] - max-parallel: 1 - if: startsWith(github.event.ref, 'refs/tags/v') - needs: test - runs-on: windows-2019 - environment: PyPI - steps: - - - name: Set Python - uses: pylegacy/actions/setup-pyenv-win@v2 - with: - architecture: ${{ matrix.arch }} - python-version: ${{ matrix.python-version }} - - - name: Download build artifacts - uses: actions/download-artifact@v3 - with: - name: artifacts-build-${{ matrix.arch }}-${{ matrix.python-version }} - path: ${{ env.PKGDIR }}/dist - - - name: Install upload requirements - run: | - python -m pip install twine - - - name: Check distributables - run: | - python -m twine check ` - ${{ env.PKGDIR }}/dist/*.zip ` - ${{ env.PKGDIR }}/dist/*.whl - - - name: Upload distributables - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: "${{ secrets.PYPI_TOKEN }}" - TWINE_REPOSITORY_URL: "${{ secrets.PYPI_REPOSITORY_URL }}" - run: | - python -m twine upload --skip-existing ` - ${{ env.PKGDIR }}/dist/*.whl diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..c2ca8e4bd --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,138 @@ +name: Build + +on: + push: + paths: + - ".github/workflows/**" + - "packages/basemap/**" + - "packages/basemap_data/**" + - "packages/basemap_data_hires/**" + pull_request: + paths: + - ".github/workflows/**" + - "packages/basemap/**" + - "packages/basemap_data/**" + - "packages/basemap_data_hires/**" + workflow_dispatch: + +jobs: + build_data: + name: Build data packages + strategy: + matrix: + package: [basemap_data, basemap_data_hires] + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.9" + + - name: Build sdist and wheels + run: | + cd packages/${{ matrix.package }} + python -m pip install build wheel + python -m build --sdist --wheel + + - uses: actions/upload-artifact@v4 + with: + path: | + packages/${{ matrix.package }}/dist/*.tar.gz + packages/${{ matrix.package }}/dist/*.whl + name: dist-${{ matrix.package }} + + build_basemap: + name: Build basemap package (${{ matrix.os }}) + needs: [build_data] + strategy: + matrix: + os: [ubuntu-22.04, windows-2019, macos-13, macos-14] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.9" + + - name: Build sdist + if: matrix.os == 'ubuntu-22.04' + run: | + cd packages/basemap + python -m pip install build + python -m build --sdist + + - name: Build wheels + uses: pypa/cibuildwheel@v2.22.0 + env: + CIBW_ARCHS: "native" + CIBW_BUILD: "cp39* cp310* cp311* cp312* cp313*" + CIBW_BUILD_VERBOSITY: 1 + CIBW_SKIP: "*-musllinux_*" + CIBW_BEFORE_ALL: "python {project}/.github/workflows/run_before_all.py" + CIBW_TEST_EXTRAS: "test" + CIBW_TEST_COMMAND: "python -m pytest {project}/packages/basemap" + CIBW_ENVIRONMENT: >- + GEOS_VERSION="3.6.5" + GEOS_DIR="$(pwd)/extern" + GEOS_NJOBS=4 + PIP_PREFER_BINARY=1 + PYTHONUNBUFFERED=1 + LD_LIBRARY_PATH="${GEOS_DIR}/lib" + # LD_LIBRARY_PATH in environment is needed by + # auditwheel (Linux) and delocate (MacOS). + with: + package-dir: "packages/basemap" + output-dir: "packages/basemap/dist" + + - uses: actions/upload-artifact@v4 + with: + path: | + packages/basemap/dist/*.tar.gz + packages/basemap/dist/*.whl + name: dist-basemap-${{ matrix.os }} + + check: + name: Check packages + needs: [build_data, build_basemap] + runs-on: ubuntu-22.04 + steps: + - uses: actions/download-artifact@v4 + with: + path: dist + pattern: "dist-*" + merge-multiple: true + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.9" + + - name: Check packages with twine + run: | + python -m pip install twine + python -m twine check dist/*.tar.gz + python -m twine check dist/*.whl + + upload: + name: Upload packages + needs: [build_data, build_basemap, check] + runs-on: ubuntu-22.04 + environment: PyPI + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') + steps: + - uses: actions/download-artifact@v4 + with: + path: dist + pattern: "dist-*" + merge-multiple: true + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_TOKEN }} + repository-url: ${{ secrets.PYPI_REPOSITORY_URL }} + skip-existing: true diff --git a/.github/workflows/run_before_all.py b/.github/workflows/run_before_all.py new file mode 100644 index 000000000..575a26763 --- /dev/null +++ b/.github/workflows/run_before_all.py @@ -0,0 +1,37 @@ +#! /usr/bin/env python +"""Helper script to be run by `cibuildwheel` as `before_all` step.""" + +import os +import sys + +HERE = os.path.abspath(__file__) +ROOT = os.path.dirname(os.path.dirname(os.path.dirname(HERE))) +sys.path.insert(0, os.path.join(ROOT, "packages", "basemap")) +import utils # noqa: E402 # pylint: disable=imports + + +def main(): + """Build the GEOS library based on parsed environment variables.""" + + geos_version = os.environ.get("GEOS_VERSION", None) + if geos_version is None: + raise ValueError("Undefined environment variable GEOS_VERSION") + + geos_dir = os.environ.get("GEOS_DIR", None) + if geos_dir is None: + raise ValueError("Undefined environment variable GEOS_DIR") + + geos_njobs = int(os.environ.get("GEOS_NJOBS", 1)) + + # pylint: disable=consider-using-f-string + print("Running before_all script with the following settings:") + print("GEOS_DIR: {0}".format(geos_dir)) + print("GEOS_VERSION: {0}".format(geos_version)) + print("GEOS_NJOBS: {0}".format(geos_njobs)) + + utils.GeosLibrary(geos_version).build(geos_dir, njobs=geos_njobs) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/CHANGELOG.md b/CHANGELOG.md index 294bec506..b14c8acd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,90 @@ https://semver.org/spec/v2.0.0.html ## [Unreleased] ### Added +- Python 3.13 support (PR [#619], solves issue [#608]). +- NumPy 2.0 support (PR [#614] by @cvanelteren, solves issue [#604]). +- Automated wheels for x86_64 and arm64 (PR [#620] by @cvanelteren, + solves issue [#608]). + +### Changed +- **BREAKING CHANGE**: Set Python minimum supported version to 3.9. +- **BREAKING CHANGE**: Migrate `basemap` libraries to use implicit + namespace packages (PR [#576] by @ksunden). +- Migrate workflows to use `cibuildwheel` (PRs [#614] and [#618] by + @cvanelteren and PR [#621], solves GitHub artifact actions v1 sunset). +- Update library dependencies: + - Upgrade upper limit for `basemap_data` to 3.0. + - Upgrade lower limit for `packaging` to 20.5. + - Upgrade upper limit for `packaging` to 25.0. + - Upgrade lower limit for `numpy` to 2.0. + - Upgrade upper limit for `numpy` to 2.3. + - Upgrade lower limit for `matplotlib` to 3.4. + - Upgrade upper limit for `matplotlib` to 3.11. + - Upgrade lower limit for `pyproj` to 3.0. + - Upgrade upper limit for `pyproj` to 3.8. + - Upgrade lower limit for `pyshp` to 2.0. +- Update optional library dependencies: + - Upgrade lower limit for `pillow` to 10.3 due to + vulnerabilities [CVE-2023-50447] and [CVE-2024-28219]. + - Upgrade upper limit for `pillow` to 11.2. + - Upgrade upper limit for `OWSLib` to 0.33. +- Update doc dependencies: + - Upgrade upper limit for `sphinx` to 8.0. + - Upgrade lower limit for `furo` to 2023.9.10. + - Upgrade upper limit for `furo` to 2024.8.7. + - Upgrade lower limit for `scipy` to 1.6. + - Upgrade upper limit for `scipy` to 1.16. + - Upgrade upper limit for `netCDF4` to 1.8.0. +- Update lint dependencies: + - Remove dependency on `unittest2`. + - Upgrade lower limit for `flake8` to 3.9. + - Upgrade upper limit for `flake8` to 7.2. + - Upgrade lower limit for `astroid` to 3.0. + - Upgrade upper limit for `astroid` to 3.4. + - Upgrade lower limit for `pylint` to 3.0. + - Upgrade upper limit for `pylint` to 3.4. +- Update test dependencies: + - Remove dependency on `unittest2`. + - Upgrade lower limit for `pytest` to 7.0. + - Upgrade upper limit for `pytest` to 8.4. + - Upgrade lower limit for `pytest-cov` to 3.0. + - Upgrade upper limit for `pytest-cov` to 6.1. + - Downgrade lower limit for `coverage` to 5.0. + - Upgrade upper limit for `coverage` to 7.7. + +### Fixed +- Fix Cython extension to use `noexcept` (PR [#615] by @cvanelteren). + +### Removed +- Deprecated `bdist_wheel.universal` option when building wheels. + +## [1.4.1] - 2024-02-15 + +### Changed +- Update workflow actions to use NodeJS 20: + - Update base actions from v3 to v4 when possible (`actions/checkout`, + `actions/upload-artifact` and `actions/download-artifact`). + - Update `jwlawson/actions-setup-cmake` from v1.13 to v2.0. +- Update base image for `basemap-data` and `basemap-data-hires` + GitHub workflows to use Debian 10. + +### Fixed +- Set recursive exclusion for `.DS_Store` folders in `MANIFEST.in`. +- Fix broken implementation and docstrings of `Basemap.arcgisimage` + method (PR [#598] by @nitram96). + +## [1.4.0] - 2024-01-09 + +### Added +- Support for Python 3.12 (solves issue [#590]). +- Complete support for `basemap` in `conda-forge` channel for the major + platforms on x64 and for MacOS on arm64 (solves issue [#286]). +- Precompiled wheels for MacOS x64 and arm64 on PyPI (solves issues + [#447] and [#574]). +- Renewed documentation, with fixes for the broken links and examples, + an improved section on the installation process, and without the + deprecation/sunsetting section (solves issues [#438], [#471], [#527] + and [#568]). - Optional argument `encoding_errors` for `Basemap.readshapefile` method (PR [#554] by @guziy, implements request [#552]). - Optional argument `cachedir` for `Basemap.arcgisimage` method to allow @@ -20,17 +104,33 @@ https://semver.org/spec/v2.0.0.html ### Changed - Upgrade bundled GEOS library to 3.6.5. -- Create optional library requirements file `requirements-full.txt`: - - Move optional dependency `pillow` to optional requirements. - - Upgrade `pillow` upper pin to 10.2.0. +- Create optional library requirements files: + - `requirements-owslib.txt` for optional dependency `OWSLib`. + - Set `OWSLib` lower limit to 0.28.1 for Python 3.6+ due to + vulnerability [CVE-2023-27476]. + - `requirements-pillow.txt` for optional dependency `pillow`: + - Upgrade `pillow` upper limit to 10.2.0. - Update library dependencies: - - Downgrade `pyproj` upper pin to 2.2.0 for Python 2.7. + - Upgrade upper limit for `numpy` to 1.27.0. + - Upgrade upper limit for `matplotlib` to 3.9.0. + - Downgrade upper limit for `pyproj` to 2.2.0 for Python 2.7. - Set dependency on `packaging` as replacement for `distutils`. - Update build dependencies: - - Upgrade `Cython` upper pin to 3.1. -- Update doc dependencies: + - Upgrade upper limit for `Cython` to 3.1. +- Update doc dependencies and require at least Python 3.8 for them: + - Upgrade upper limit for `sphinx` to 7.2. + - Upgrade upper limit for `furo` to 2023.9.11. - Move dependency on `netCDF4` to `requirements-doc.txt`. - Set dependency on `cftime` explicitly in `requirements-doc.txt`. + - Set dependency on `scipy` explicitly in `requirements-doc.txt`. +- Update lint dependencies: + - Downgrade upper limit for `flake8` to 6.2. + - Upgrade upper limit for `astropy` to 3.1. + - Upgrade lower limit for `pylint` to 3.1. +- Update test dependencies: + - Upgrade upper limit for `pytest` to 7.5. + - Upgrade upper limit for `coverage` to 7.4. + - Upgrade upper limit for `pytest-cov` to 4.2. ### Fixed - Reimplement `matplotlib` version checks without using `distutils` and @@ -44,8 +144,17 @@ https://semver.org/spec/v2.0.0.html precompiled Windows wheels (PR [#565]). - Fix `_geoslib.pyx` compilation with Cython 3.0+ using the compiler directive "legacy_implicit_noexcept" (PR [#593] by @musicinmybrain). +- Fix `_geoslib.pyx` syntax to comply with newer compilers such as + Clang 16 and GCC 14 (PR [#595] by @fweimer-rh). +- Apply basic cleanup of `_geoslib.pyx` source code (i.e. basic linting, + removal of commented code, version update). +- Fix breaking change from `matplotlib` 3.8 due to the promotion of + `QuadContourSet` objects into `Artist` objects, which affected + `Basemap.contour`, `Basemap.contourf` and `Basemap.nightshade` + (solves issue [#594], thanks to @qianwu2 and @rcomer). ### Removed +- Use of unicode literals within the library. - Attribute `__version__` in `mpl_toolkits.basemap.proj` module. - Module `mpl_toolkits.basemap.test`, whose content is migrated to the test suite in the `test` folder. @@ -53,25 +162,29 @@ https://semver.org/spec/v2.0.0.html or the deprecated `matplotlib.cbook.dedent`) to write multi-line error messages. -## [1.3.9] +## [1.3.9] - 2023-12-26 ### Fixed - Fix `GeosLibrary` wrapper to also work with CMake >= 3.27.0 and Python 2.7 on Windows by adding '/MANIFEST:NO' to override the new default '/MANIFEST:EMBED,ID=2' provided to linker. -- Fix references to removed `numpy.float` alias (solves issue [#589], - thanks to @quickbrett). -- Fix bug with elliptical maps causing warped images (Blue Marble, - ETOPO, Shaded Relief) to be shown behind the map background when the - map boundary is not initialised manually (solves issue [#577], thanks - to @YilongWang). +- Fix broken `Proj.__call__` when the input arguments are provided as + a combined single array. - Fix flipped coastlines with pseudocylindrical projections when `lon_0` is greater than 0 deg (solves issues [#443] and [#463], thanks to @YilongWang). -- Fix broken `Proj.__call__` when the input arguments are provided as - a combined single array. - Fix `antialiased` argument being ignored in `Basemap.drawcounties` and `Basemap.readshapefile` (solves issue [#501], thanks to @TheFizzWare). +- Fix `BaseGeometry.intersection` in `_geoslib` so that it also works + with `GEOS_GEOMETRYCOLLECTION` objects returned by `GEOSIntersection` + (solves issue [#566], where country boundaries are missing due to this + bug, thanks to @guidocioni). +- Fix bug with elliptical maps causing warped images (Blue Marble, + ETOPO, Shaded Relief) to be shown behind the map background when the + map boundary is not initialised manually (solves issue [#577], thanks + to @YilongWang). +- Fix references to removed `numpy.float` alias (solves issue [#589], + thanks to @quickbrett). - Fix wrong reference to `ireland.py` example in FAQ, which should be `hires.py` instead, and fix wrong use of locals and invalid syntax in this example (solves issue [#592], thanks to @timcoote). @@ -102,7 +215,8 @@ https://semver.org/spec/v2.0.0.html - Upgrade `matplotlib` upper pin to 3.8 (solves issue [#573]). - Upgrade `pyproj` upper pin to 3.6. - Upgrade test dependency `netCDF4` upper pin to 1.7. -- Upgrade test dependency `pillow` lower pin to 9.4. +- Upgrade test dependency `pillow` lower pin to 9.4 due to vulnerability + [CVE-2022-45198]. ## [1.3.6] - 2022-10-31 @@ -196,8 +310,8 @@ https://semver.org/spec/v2.0.0.html [CVE-2020-10177], [CVE-2020-10378], [CVE-2020-10379], [CVE-2020-10994] and [CVE-2020-11538]. - `pillow >= 6.2.2` For Python == 2.7 due to `pillow` vulnerabilities - [CVE-2019-16865], [CVE-2019-19911], [CVE-2020-5310], [CVE-2020-5312] - and [CVE-2020-5313]. + [CVE-2019-16865], [CVE-2019-19911], [CVE-2020-5310], + [CVE-2020-5311], [CVE-2020-5312] and [CVE-2020-5313]. ### Removed - Remove deprecation notices (issue [#527]). @@ -221,21 +335,21 @@ https://semver.org/spec/v2.0.0.html ### Added - Precompiled binary wheels available in PyPI. -- Complete workflow to build the project wheels for Windows and GNU/Linux - using GitHub Actions. +- Complete workflow to build the project wheels for Windows and + GNU/Linux using GitHub Actions. ### Changed -- Reorganise the package structure. In summary, the former `basemap` package - is split in three: +- Reorganise the package structure. In summary, the former `basemap` + package is split in three: - `basemap` itself contains the Python modules. - - `basemap-data` contains the mandatory data assets required by `basemap` - to provide minimal functionality. + - `basemap-data` contains the mandatory data assets required by + `basemap` to provide minimal functionality. - `basemap-data-hires` contains the high-resolution data assets. - This change together with the precompiled binary wheels in PyPI should solve - most of the former installation problems (see issues [#403], [#405], [#422], - [#436], [#445], [#456], [#461], [#488], [#489], [#491], [#510], [#513], - [#525], [#526] and [#535]). + This change together with the precompiled binary wheels in PyPI should + solve most of the former installation problems (see issues [#403], + [#405], [#422], [#436], [#445], [#456], [#461], [#488], [#489], + [#491], [#510], [#513], [#525], [#526] and [#535]). - Upgrade default GEOS library dependency to 3.5.1. - Update and clarify licenses. In summary: - `basemap`: MIT license. @@ -247,14 +361,14 @@ https://semver.org/spec/v2.0.0.html ### Fixed - Fix `Basemap.pcolormesh` for `"ortho"` projection (PR [#476]). - Fix `Basemap.arcgisimage` for cylindrical coordinates (PR [#505]). -- Force `setup.py` to cythonize `_geoslib.pyx` at compile time (issues [#487], - [#518] and [#521]). -- Update `README` files and apply corrections and changes to outdated content - (issue [#179]). +- Force `setup.py` to cythonize `_geoslib.pyx` at compile time (issues + [#487], [#518] and [#521]). +- Update `README` files and apply corrections and changes to outdated + content (issue [#179]). ### Removed -- Bundled GEOS source code. The same source code can be downloaded using the - `GeosLibrary` class in `utils` (issue [#228]). +- Bundled GEOS source code. The same source code can be downloaded using + the `GeosLibrary` class in `utils` (issue [#228]). - Precompiled `_geoslib.c` file (issue [#437]). ## [1.2.2] - 2020-08-04 @@ -1042,12 +1156,36 @@ https://semver.org/spec/v2.0.0.html - Fix glitches in drawing of parallels and meridians. +[#621]: +https://github.com/matplotlib/basemap/pull/621 +[#620]: +https://github.com/matplotlib/basemap/pull/620 +[#619]: +https://github.com/matplotlib/basemap/pull/619 +[#618]: +https://github.com/matplotlib/basemap/pull/618 +[#615]: +https://github.com/matplotlib/basemap/pull/615 +[#614]: +https://github.com/matplotlib/basemap/pull/614 +[#608]: +https://github.com/matplotlib/basemap/issues/608 +[#604]: +https://github.com/matplotlib/basemap/issues/604 +[#598]: +https://github.com/matplotlib/basemap/pull/598 +[#595]: +https://github.com/matplotlib/basemap/pull/595 +[#594]: +https://github.com/matplotlib/basemap/issues/594 [#593]: https://github.com/matplotlib/basemap/pull/593 [#592]: https://github.com/matplotlib/basemap/issues/592 [#591]: https://github.com/matplotlib/basemap/issues/591 +[#590]: +https://github.com/matplotlib/basemap/issues/590 [#589]: https://github.com/matplotlib/basemap/issues/589 [#583]: @@ -1062,8 +1200,16 @@ https://github.com/matplotlib/basemap/pull/580 https://github.com/matplotlib/basemap/issues/579 [#577]: https://github.com/matplotlib/basemap/issues/577 +[#576]: +https://github.com/matplotlib/basemap/pull/576 +[#574]: +https://github.com/matplotlib/basemap/issues/574 [#573]: https://github.com/matplotlib/basemap/issues/573 +[#568]: +https://github.com/matplotlib/basemap/issues/568 +[#566]: +https://github.com/matplotlib/basemap/issues/566 [#565]: https://github.com/matplotlib/basemap/pull/565 [#564]: @@ -1144,18 +1290,24 @@ https://github.com/matplotlib/basemap/issues/487 https://github.com/matplotlib/basemap/issues/481 [#476]: https://github.com/matplotlib/basemap/pull/476 +[#471]: +https://github.com/matplotlib/basemap/issues/471 [#463]: https://github.com/matplotlib/basemap/issues/463 [#461]: https://github.com/matplotlib/basemap/issues/461 [#456]: https://github.com/matplotlib/basemap/issues/456 +[#447]: +https://github.com/matplotlib/basemap/issues/447 [#445]: https://github.com/matplotlib/basemap/issues/445 [#444]: https://github.com/matplotlib/basemap/issues/444 [#443]: https://github.com/matplotlib/basemap/issues/443 +[#438]: +https://github.com/matplotlib/basemap/issues/438 [#437]: https://github.com/matplotlib/basemap/issues/437 [#436]: @@ -1170,13 +1322,19 @@ https://github.com/matplotlib/basemap/issues/403 https://github.com/matplotlib/basemap/issues/383 [#362]: https://github.com/matplotlib/basemap/issues/362 +[#286]: +https://github.com/matplotlib/basemap/issues/286 [#228]: https://github.com/matplotlib/basemap/issues/228 [#179]: https://github.com/matplotlib/basemap/issues/179 [Unreleased]: -https://github.com/matplotlib/basemap/compare/v1.3.9...develop +https://github.com/matplotlib/basemap/compare/v1.4.1...develop +[1.4.1]: +https://github.com/matplotlib/basemap/compare/v1.4.0...v1.4.1 +[1.4.0]: +https://github.com/matplotlib/basemap/compare/v1.3.9...v1.4.0 [1.3.9]: https://github.com/matplotlib/basemap/compare/v1.3.8...v1.3.9 [1.3.8]: @@ -1216,6 +1374,14 @@ https://github.com/matplotlib/basemap/compare/v1.0.3rel...v1.0.4rel [1.0.3]: https://github.com/matplotlib/basemap/tree/v1.0.3rel +[CVE-2024-28219]: +https://nvd.nist.gov/vuln/detail/CVE-2024-28219 +[CVE-2023-50447]: +https://nvd.nist.gov/vuln/detail/CVE-2023-50447 +[CVE-2023-27476]: +https://nvd.nist.gov/vuln/detail/CVE-2023-27476 +[CVE-2022-45198]: +https://nvd.nist.gov/vuln/detail/CVE-2022-45198 [CVE-2022-24303]: https://nvd.nist.gov/vuln/detail/CVE-2022-24303 [CVE-2022-22817]: @@ -1282,6 +1448,8 @@ https://nvd.nist.gov/vuln/detail/CVE-2020-10177 https://nvd.nist.gov/vuln/detail/CVE-2020-5313 [CVE-2020-5312]: https://nvd.nist.gov/vuln/detail/CVE-2020-5312 +[CVE-2020-5311]: +https://nvd.nist.gov/vuln/detail/CVE-2020-5311 [CVE-2020-5310]: https://nvd.nist.gov/vuln/detail/CVE-2020-5310 [CVE-2019-19911]: diff --git a/LICENSE b/LICENSE index b74d728bb..120eb7e3f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,5 @@ -Copyright (c) 2011 Jeffrey Whitaker +Copyright (c) 2011-2014 Jeffrey Whitaker +Copyright (c) 2015-2024 The Matplotlib development team Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README.md b/README.md index 78f05434c..21b98ad39 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Basic requirements are the following: Optional requirements include: * [OWSLib](https://github.com/geopython/OWSLib). It is needed for the - `Basemap.wmsimage` function. + method `Basemap.wmsimage`. * [Pillow](https://github.com/python-pillow/Pillow). It is needed for the methods `Basemap.bluemarble`, `Basemap.etopo`, @@ -25,19 +25,21 @@ Optional requirements include: ## Installation The `basemap-data` and `basemap-data-hires` packages are available in -PyPI and can be installed with [`pip`](https:/pip.pypa.io/): +PyPI and can be installed with [`pip`](https://pip.pypa.io/): ```sh python -m pip install basemap-data python -m pip install basemap-data-hires ``` -Precompiled `basemap` binary wheels for Windows and GNU/Linux are also -available in PyPI (architectures x86 and x64, Python 2.7 and 3.5+): +Precompiled `basemap` binary wheels for Windows and GNU/Linux +(architectures x86 and x64, Python 2.7 and 3.5+) as well as for MacOS +(architectures x64 and arm64, Python 3.9+) are also available in PyPI: ```sh python -m pip install basemap ``` -Otherwise, you will need to install `basemap` from source as follows: +Otherwise, you will need to install `basemap` from its source hosted +on GitHub as indicated in the following steps: 1. Install pre-requisite Python modules: - [cython](https://github.com/cython/cython) @@ -51,7 +53,8 @@ Otherwise, you will need to install `basemap` from source as follows: ``` 3. Build the [GEOS](https://github.com/libgeos/geos) library. You may - use the helper provided in `utils`, i.e. + use the helper provided in `utils`, (please note that you need + [`CMake`](https://cmake.org/) and a working C compiler in advance): ```sh export GEOS_DIR= python -c "import utils; utils.GeosLibrary('3.6.5').build(installdir='${GEOS_DIR}')" @@ -70,11 +73,10 @@ Otherwise, you will need to install `basemap` from source as follows: to build Cython extensions (e.g. on Debian-like systems, you should have the package `python-dev` installed). -5. Check that the package installed correctly by executing: +5. Check that the package was installed correctly by executing: ```sh python -c "from mpl_toolkits.basemap import Basemap" ``` - You can also test the examples available in the `examples` folder. ## License @@ -98,7 +100,7 @@ https://spdx.org/licenses/LGPL-3.0-or-later.html ## Documentation -See https://matplotlib.github.io/basemap/ +See https://matplotlib.org/basemap/ See scripts in `examples` directory for example usage. diff --git a/examples/geos_demo.py b/examples/geos_demo.py index e21377671..63bae91ff 100644 --- a/examples/geos_demo.py +++ b/examples/geos_demo.py @@ -20,11 +20,11 @@ def get_input(prompt): # plot land-sea mask. # land red, oceans blue. # lakes=True means plot inland lakes with ocean color. +m.drawmapboundary() m.drawlsmask(land_color='red',ocean_color='blue',lakes=True) # draw parallels and meridians. m.drawparallels(np.arange(-90.,120.,30.)) m.drawmeridians(np.arange(0.,420.,60.)) -m.drawmapboundary() plt.title('Geostationary Map Centered on Lon=%s' % (lon_0)) # map with continents drawn and filled. diff --git a/examples/geos_demo_2.py b/examples/geos_demo_2.py index 5b3bc258b..cbc0d3f2c 100644 --- a/examples/geos_demo_2.py +++ b/examples/geos_demo_2.py @@ -39,7 +39,7 @@ m = Basemap(projection='geos', lon_0=lon_0, satellite_height=satellite_height, resolution='l', llcrnrlon=ll_lon, llcrnrlat=ll_lat, urcrnrlon=ur_lon, urcrnrlat=ur_lat) # add data -m.imshow(data, cmap=plt.cm.gray, interpolation='nearest') +m.imshow(data[::-1], cmap=plt.cm.gray, interpolation='nearest') plt.clim(0, 255) # draw coastlines. m.drawcoastlines(linewidth=0.5, color=overlay_color) diff --git a/examples/hurrtracks.py b/examples/hurrtracks.py index 32a35663e..2670cb7b7 100644 --- a/examples/hurrtracks.py +++ b/examples/hurrtracks.py @@ -1,14 +1,13 @@ -from __future__ import (absolute_import, division, print_function) - """ draw Atlantic Hurricane Tracks for storms that reached Cat 4 or 5. part of the track for which storm is cat 4 or 5 is shown red. ESRI shapefile data from http://nationalatlas.gov/mld/huralll.html """ +import os import numpy as np import matplotlib.pyplot as plt -from mpl_toolkits.basemap import Basemap as Basemap -# Lambert Conformal Conic maplt. +from mpl_toolkits.basemap import Basemap +# Lambert Conformal Conic map. m = Basemap(llcrnrlon=-100.,llcrnrlat=0.,urcrnrlon=-20.,urcrnrlat=57., projection='lcc',lat_1=20.,lat_2=40.,lon_0=-60., resolution ='l',area_thresh=1000.) @@ -16,7 +15,6 @@ fig=plt.figure() # read shapefile. shp_info = m.readshapefile('huralll020','hurrtracks',drawbounds=False) -print(shp_info) # find names of storms that reached Cat 4. names = [] for shapedict in m.hurrtracks_info: @@ -25,8 +23,6 @@ if cat in ['H4','H5'] and name not in names: # only use named storms. if name != 'NOT NAMED': names.append(name) -print(names) -print(len(names)) # plot tracks of those storms. for shapedict,shape in zip(m.hurrtracks_info,m.hurrtracks): name = shapedict['NAME'] diff --git a/examples/ortho_demo.py b/examples/ortho_demo.py index 9fa1ed56b..4a16e8662 100644 --- a/examples/ortho_demo.py +++ b/examples/ortho_demo.py @@ -22,13 +22,13 @@ def get_input(prompt): # land coral, oceans aqua. # lakes=True means plot inland lakes with ocean color. # resolution = 5 (default) means use 5 min dataset (can use 2.5) +m.drawmapboundary() m.drawcoastlines() m.drawlsmask(land_color='coral',ocean_color='aqua', lakes=True,\ resolution=resolution,grid=grid) # draw parallels and meridians. m.drawparallels(np.arange(-90.,120.,30.)) m.drawmeridians(np.arange(0.,420.,60.)) -m.drawmapboundary() plt.title('Orthographic Map Centered on Lon=%s, Lat=%s' % (lon_0,lat_0)) # map with continents drawn and filled (continent filling fails for diff --git a/examples/plotcities.py b/examples/plotcities.py index a708b2f4c..6f8b2a6ca 100644 --- a/examples/plotcities.py +++ b/examples/plotcities.py @@ -1,20 +1,22 @@ from __future__ import (absolute_import, division, print_function) -from matplotlib.mlab import prctile_rank +import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.basemap import Basemap as Basemap +prctile_rank = lambda x, p: np.searchsorted(np.percentile(x, np.atleast_1d(p)), x) # cities colored by population rank. m = Basemap() shp_info = m.readshapefile('cities','cities') -x, y = zip(*m.cities) -pop = [] -for item in m.cities_info: +x, y, pop = [], [], [] +for item, (x_i, y_i) in zip(m.cities_info, m.cities): population = item['POPULATION'] - if population < 0: continue # population missing - pop.append(population) -popranks = prctile_rank(pop,100) + if population >= 0: + pop.append(population) + x.append(x_i) + y.append(y_i) +popranks = prctile_rank(pop,np.linspace(0, 100, 101)) colors = [] for rank in popranks: colors.append(plt.cm.jet(float(rank)/100.)) diff --git a/examples/plothighsandlows.py b/examples/plothighsandlows.py index f86fddda6..f5fa73345 100644 --- a/examples/plothighsandlows.py +++ b/examples/plothighsandlows.py @@ -27,7 +27,7 @@ def main(): """Main function.""" # Plot 00 UTC today. - url = "http://nomads.ncep.noaa.gov/dods/gfs_0p25/gfs%Y%m%d/gfs_0p25_00z" + url = "http://nomads.ncep.noaa.gov/dods/gfs_0p50/gfs%Y%m%d/gfs_0p50_00z" date = dt.datetime.now() # Open OPeNDAP dataset. diff --git a/examples/plotozone.py b/examples/plotozone.py index 1a4d41b5a..26c11c072 100644 --- a/examples/plotozone.py +++ b/examples/plotozone.py @@ -66,7 +66,7 @@ toplot = np.ma.masked_values(o3[0, 0], 0.) * 1000. bounds = np.percentile(toplot.compressed().ravel(), np.linspace(5, 95, 9).tolist()) -ptch = m.pcolor(X, Y, toplot, cmap = WhGrYlBu, norm = plt.matplotlib.colors.BoundaryNorm(bounds, 20), vmin = bounds[0], vmax = bounds[-1]) +ptch = m.pcolor(X, Y, toplot, cmap = WhGrYlBu, norm = plt.matplotlib.colors.BoundaryNorm(bounds, 20)) # Add a colorbar using proportional spacing, but # colors based on 10 distinct bins diff --git a/examples/plotsst.py b/examples/plotsst.py index e57a560db..a8652c34d 100644 --- a/examples/plotsst.py +++ b/examples/plotsst.py @@ -1,24 +1,33 @@ -from __future__ import (absolute_import, division, print_function) - from mpl_toolkits.basemap import Basemap from netCDF4 import Dataset, date2index import numpy as np import matplotlib.pyplot as plt from datetime import datetime +try: + from urllib.request import urlretrieve +except ImportError: + from urllib import urlretrieve date = datetime(2007,12,15,0) # date to plot. # open dataset. -dataset = \ -Dataset('http://www.ncdc.noaa.gov/thredds/dodsC/OISST-V2-AVHRR_agg') +sstpath, sstheader = urlretrieve("https://downloads.psl.noaa.gov/Datasets/noaa.oisst.v2.highres/sst.day.mean.{0}.nc".format(date.year)) +dataset = Dataset(sstpath) timevar = dataset.variables['time'] timeindex = date2index(date,timevar) # find time index for desired date. # read sst. Will automatically create a masked array using # missing_value variable attribute. 'squeeze out' singleton dimensions. sst = dataset.variables['sst'][timeindex,:].squeeze() # read ice. -ice = dataset.variables['ice'][timeindex,:].squeeze() +dataset.close() +icepath, iceheader = urlretrieve("https://downloads.psl.noaa.gov/Datasets/noaa.oisst.v2.highres/icec.day.mean.{0}.nc".format(date.year)) +dataset = Dataset(icepath) +ice = dataset.variables['icec'][timeindex,:].squeeze() # read lats and lons (representing centers of grid boxes). lats = dataset.variables['lat'][:] lons = dataset.variables['lon'][:] +dataset.close() +latstep, lonstep = np.diff(lats[:2]), np.diff(lons[:2]) +lats = np.append(lats - 0.5 * latstep, lats[-1] + 0.5 * latstep) +lons = np.append(lons - 0.5 * lonstep, lons[-1] + 0.5 * lonstep) lons, lats = np.meshgrid(lons,lats) # create figure, axes instances. fig = plt.figure() diff --git a/examples/warpimage.py b/examples/warpimage.py index 1bea87a59..705105d81 100644 --- a/examples/warpimage.py +++ b/examples/warpimage.py @@ -81,7 +81,7 @@ # define orthographic projection centered on Europe. m = Basemap(projection='ortho',lat_0=40,lon_0=40,resolution='l') # plot a gray-scale image specified from a URL. -im = m.warpimage("http://earthobservatory.nasa.gov/Features/BlueMarble/Images/gebco_bathy.5400x2700.jpg") +im = m.warpimage("https://eoimages.gsfc.nasa.gov/images/imagerecords/73000/73963/gebco_08_rev_bath_3600x1800_color.jpg") # draw coastlines. m.drawcoastlines(linewidth=0.5,color='0.5') # draw lat/lon grid lines every 30 degrees. diff --git a/packages/basemap/LICENSE b/packages/basemap/LICENSE index b74d728bb..68cbd3d24 100644 --- a/packages/basemap/LICENSE +++ b/packages/basemap/LICENSE @@ -1,4 +1,5 @@ -Copyright (c) 2011 Jeffrey Whitaker +Copyright (c) 2011-2014 Jeffrey Whitaker +Copyright (c) 2015-2025 The Matplotlib development team Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/packages/basemap/LICENSE.geos b/packages/basemap/LICENSE.geos index b1e3f5a26..f166cc57b 100644 --- a/packages/basemap/LICENSE.geos +++ b/packages/basemap/LICENSE.geos @@ -1,8 +1,8 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -10,7 +10,7 @@ as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] - Preamble + Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public @@ -112,7 +112,7 @@ modification follow. Pay close attention to the difference between a former contains code derived from the library, whereas the latter must be combined with the library in order to run. - GNU LESSER GENERAL PUBLIC LICENSE + GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other @@ -146,7 +146,7 @@ such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. - + 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an @@ -432,7 +432,7 @@ decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. - NO WARRANTY + NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. @@ -455,7 +455,7 @@ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - END OF TERMS AND CONDITIONS + END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries @@ -485,7 +485,7 @@ convey the exclusion of warranty; and each file should have at least the You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. @@ -499,6 +499,4 @@ necessary. Here is a sample; alter the names: , 1 April 1990 Ty Coon, President of Vice -That's all there is to it! - - +That's all there is to it! \ No newline at end of file diff --git a/packages/basemap/MANIFEST.in b/packages/basemap/MANIFEST.in index 0ea74f384..93b419369 100644 --- a/packages/basemap/MANIFEST.in +++ b/packages/basemap/MANIFEST.in @@ -4,5 +4,6 @@ recursive-exclude doc/build * recursive-include test * recursive-include utils *.py recursive-exclude **/__pycache__ * +recursive-exclude **/.DS_Store * exclude **/*.pyc exclude **/.gitkeep diff --git a/packages/basemap/README.md b/packages/basemap/README.md index cfe0f6bf0..be631e774 100644 --- a/packages/basemap/README.md +++ b/packages/basemap/README.md @@ -45,6 +45,6 @@ https://spdx.org/licenses/LGPL-2.1-only.html https://spdx.org/licenses/MIT.html [`LICENSE`]: -https://github.com/matplotlib/basemap/blob/v1.3.9/packages/basemap/LICENSE +https://github.com/matplotlib/basemap/blob/v1.4.1/packages/basemap/LICENSE [`LICENSE.geos`]: -https://github.com/matplotlib/basemap/blob/v1.3.9/packages/basemap/LICENSE.geos +https://github.com/matplotlib/basemap/blob/v1.4.1/packages/basemap/LICENSE.geos diff --git a/packages/basemap/doc/Makefile b/packages/basemap/doc/Makefile new file mode 100644 index 000000000..69fe55ecf --- /dev/null +++ b/packages/basemap/doc/Makefile @@ -0,0 +1,19 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/packages/basemap/doc/api/basemap_api.rst b/packages/basemap/doc/api/basemap_api.rst deleted file mode 100644 index 6d6537399..000000000 --- a/packages/basemap/doc/api/basemap_api.rst +++ /dev/null @@ -1,11 +0,0 @@ -************************** -matplotlib basemap toolkit -************************** - - -:mod:`mpl_toolkits.basemap` -============================= - -.. automodule:: mpl_toolkits.basemap - :members: - :undoc-members: diff --git a/packages/basemap/doc/api/index.rst b/packages/basemap/doc/api/index.rst deleted file mode 100644 index 7352d468f..000000000 --- a/packages/basemap/doc/api/index.rst +++ /dev/null @@ -1,12 +0,0 @@ -.. _api-index: - -#################################### - The Matplotlib Basemap Toolkit API -#################################### - -:Release: |version| -:Date: |today| - -.. toctree:: - - basemap_api.rst diff --git a/packages/basemap/doc/conf.py b/packages/basemap/doc/conf.py deleted file mode 100644 index 6d12a54cc..000000000 --- a/packages/basemap/doc/conf.py +++ /dev/null @@ -1,179 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Basemap documentation build configuration file, created by -# sphinx-quickstart on Fri May 2 12:33:25 2008. -# -# This file is execfile()d with the current directory set to its containing dir. -# -# The contents of this file are pickled, so don't put values in the namespace -# that aren't pickleable (module imports are okay, they're removed automatically). -# -# All configuration values have a default value; values that are commented out -# serve to show the default value. - -import sys, os - -# If your extensions are in another directory, add it here. If the directory -# is relative to the documentation root, use os.path.abspath to make it -# absolute, like shown here. -#sys.path.append(os.path.abspath('sphinxext')) - -# General configuration -# --------------------- - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', -#extensions = ['matplotlib.sphinxext.mathmpl', -# 'sphinx.ext.autodoc', 'matplotlib.sphinxext.only_directives', - 'matplotlib.sphinxext.plot_directive', -# 'sphinx.ext.inheritance_diagram', -# 'matplotlib.sphinxext.ipython_console_highlighting', - ] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General substitutions. -project = 'Basemap Matplotlib Toolkit' -copyright = '2011, Jeffrey Whitaker; 2016 The matplotlib development team' - -# The default replacements for |version| and |release|, also used in various -# other places throughout the built documents. -# -# The short X.Y version. -from mpl_toolkits.basemap import __version__ as bmversion -version = bmversion -# The full version, including alpha/beta/rc tags. -release = bmversion - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -today_fmt = '%B %d, %Y' - -# List of documents that shouldn't be included in the build. -unused_docs = [] - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - - -# Options for HTML output -# ----------------------- - -# The style sheet to use for HTML and HTML Help pages. A file of that name -# must exist either in Sphinx' static/ path, or in one of the custom paths -# given in html_static_path. -#html_style = 'mpl.css' - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# The name of an image file (within the static path) to place at the top of -# the sidebar. -#html_logo = 'logo.png' - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -#html_static_path = ['_static'] - -# If nonempty, this is the file name suffix for generated HTML files. The -# default is ``".html"``. -#html_file_suffix = '.xhtml' - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_use_modindex = True - -# If true, the reST sources are included in the HTML build as _sources/. -#html_copy_source = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. -html_use_opensearch = 'False' - -# Output file base name for HTML help builder. -htmlhelp_basename = 'Basemapdoc' - - -# Options for LaTeX output -# ------------------------ - -# The paper size ('letter' or 'a4'). -latex_paper_size = 'letter' - -# The font size ('10pt', '11pt' or '12pt'). -latex_font_size = '11pt' - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, document class [howto/manual]). - -latex_documents = [ - ('index', 'Basemap.tex', 'Basemap', 'Jeffrey Whitaker', 'manual'), -] - - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -latex_logo = None - -# Additional stuff for the LaTeX preamble. -latex_preamble = '' - -# Documents to append as an appendix to all manuals. -latex_appendices = [] - -# If false, no module index is generated. -latex_use_modindex = True - -latex_use_parts = True - -# Show both class-level docstring and __init__ docstring in class -# documentation -autoclass_content = 'both' - - - - -################ plot directive configurations ##################### -plot_html_show_formats = False -plot_include_source = True -plot_rcparams = {'figure.figsize':[8, 6]} -plot_formats = [('png', 100), # pngs for html building - ('pdf', 72), # pdfs for latex building - ] diff --git a/packages/basemap/doc/make.bat b/packages/basemap/doc/make.bat new file mode 100644 index 000000000..4d9eb83d9 --- /dev/null +++ b/packages/basemap/doc/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd diff --git a/packages/basemap/test/__init__.py b/packages/basemap/doc/source/_static/.gitkeep similarity index 100% rename from packages/basemap/test/__init__.py rename to packages/basemap/doc/source/_static/.gitkeep diff --git a/packages/basemap/test/mpl_toolkits/__init__.py b/packages/basemap/doc/source/_templates/.gitkeep similarity index 100% rename from packages/basemap/test/mpl_toolkits/__init__.py rename to packages/basemap/doc/source/_templates/.gitkeep diff --git a/packages/basemap/doc/source/_templates/autosummary/module.rst b/packages/basemap/doc/source/_templates/autosummary/module.rst new file mode 100644 index 000000000..6090b5e35 --- /dev/null +++ b/packages/basemap/doc/source/_templates/autosummary/module.rst @@ -0,0 +1,5 @@ +{{ fullname }} +{{ underline }} + +.. automodule:: {{ fullname }} + :members: diff --git a/packages/basemap/doc/source/api/basemap_api.rst b/packages/basemap/doc/source/api/basemap_api.rst new file mode 100644 index 000000000..f460dac35 --- /dev/null +++ b/packages/basemap/doc/source/api/basemap_api.rst @@ -0,0 +1,6 @@ +:mod:`mpl_toolkits.basemap` +--------------------------- + +.. automodule:: mpl_toolkits.basemap + :members: + :undoc-members: diff --git a/packages/basemap/doc/source/api/index.rst b/packages/basemap/doc/source/api/index.rst new file mode 100644 index 000000000..47b4044de --- /dev/null +++ b/packages/basemap/doc/source/api/index.rst @@ -0,0 +1,11 @@ +.. _api-index: + +Basemap API +=========== + +:Release: |release| +:Date: |today| + +.. toctree:: + + basemap_api.rst diff --git a/packages/basemap/doc/source/conf.py b/packages/basemap/doc/source/conf.py new file mode 100644 index 000000000..daa4b1286 --- /dev/null +++ b/packages/basemap/doc/source/conf.py @@ -0,0 +1,217 @@ +# -*- coding: utf-8 -*- +# pylint: disable=redefined-builtin,wrong-import-position +"""Configuration file for the Sphinx documentation builder. + +This file does only contain a selection of the most common options. +For a full list see the documentation: +http://www.sphinx-doc.org/en/master/config +""" + +# -- Path setup -------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another +# directory, add these directories to sys.path here. If the directory +# is relative to the documentation root, use os.path.abspath to make it +# absolute, like shown here. +import os +import sys +sys.path.insert(0, os.path.abspath("../../src")) +myself = getattr(__import__("mpl_toolkits.basemap"), "basemap") +PY2 = sys.version_info[0] == 2 + +# -- Project information ----------------------------------------------- + +project = myself.__name__.rsplit(".", 1)[-1] +copyright = "2011-2014 Jeffrey Whitaker; 2015-2025 The Matplotlib development team" +author = "Jeffrey Whitaker" + +# The short X.Y version +version = "" +# The full version, including alpha/beta/rc tags +release = myself.__version__ + + +# -- General configuration --------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = "1.0" + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named "sphinx.ext.*") or your custom +# ones. +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.napoleon", + "sphinx.ext.intersphinx", + "sphinx.ext.viewcode", + "matplotlib.sphinxext.plot_directive", +] + +autodoc_default_options = { + "member-order": "alphabetical", + "special-members": "__init__", + "undoc-members": True, + "exclude-members": "__weakref__", +} + +napoleon_use_ivar = True +napoleon_use_rtype = False +intersphinx_mapping = { + "python": + ("https://docs.python.org/3", None), + "numpy": + ("https://numpy.org/doc/stable/", None), + "matplotlib": + ("https://matplotlib.org/stable/", None), +} + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = [".rst", ".md"] +source_suffix = ".rst" + +# The master toctree document. +master_doc = "index" + +# The language for content autogenerated by Sphinx. Refer to the +# documentation for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = "en" + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = None + + +# -- Options for HTML output ------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation +# for a list of builtin themes. +html_theme = "furo" +html_context = {} + +# Theme options are theme-specific and customize the look and feel of a +# theme further. For a list of options available for each theme, see +# the documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) +# here, relative to this directory. They are copied after the builtin +# static files, so a file named "default.css" will overwrite the +# builtin "default.css". +html_static_path = ["_static"] + +# Custom sidebar templates, must be a dictionary that maps document +# names to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``["localtoc.html", "relations.html", "sourcelink.html", +# "searchbox.html"]``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = "{0}doc".format(project) + + +# -- Options for LaTeX output ------------------------------------------ + +latex_elements = { + # The paper size ("letterpaper" or "a4paper"). + "papersize": "letterpaper", + # The font size ("10pt", "11pt" or "12pt"). + "pointsize": "10pt", + # Additional stuff for the LaTeX preamble. + "preamble": "", + # Latex figure (float) alignment + "figure_align": "htbp", +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [( + master_doc, + "{0}.tex".format(project), + "{0} Documentation".format(project), + author, + "manual", +)] + + +# -- Options for manual page output ------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [( + master_doc, + project, + "{0} Documentation".format(project), + [author], + 1, +)] + + +# -- Options for Texinfo output ---------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [( + master_doc, + project, + "{0} Documentation".format(project), + author, + project, + myself.__doc__, + "Miscellaneous", +)] + + +# -- Options for Epub output ------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +# +# epub_identifier = "" + +# A unique identification for the text. +# +# epub_uid = "" + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ["search.html"] + + +# -- Extension configuration ------------------------------------------- + +# Plot directive configurations. +plot_html_show_formats = False +plot_include_source = True +plot_rcparams = { + "figure.figsize": + [8, 6], +} +plot_formats = [ + ("png", 100), # PNGs for HTML building + ("pdf", 72), # PDFs for LaTeX building +] diff --git a/packages/basemap/doc/index.rst b/packages/basemap/doc/source/index.rst similarity index 58% rename from packages/basemap/doc/index.rst rename to packages/basemap/doc/source/index.rst index 65f6b2c3c..a2cdbc306 100644 --- a/packages/basemap/doc/index.rst +++ b/packages/basemap/doc/source/index.rst @@ -1,5 +1,5 @@ -Welcome to the Matplotlib Basemap Toolkit documentation -======================================================= +Welcome to the basemap documentation! +===================================== .. toctree:: :maxdepth: 2 diff --git a/packages/basemap/doc/matplotlibrc b/packages/basemap/doc/source/matplotlibrc similarity index 100% rename from packages/basemap/doc/matplotlibrc rename to packages/basemap/doc/source/matplotlibrc diff --git a/packages/basemap/doc/users/aea.rst b/packages/basemap/doc/source/users/aea.rst similarity index 100% rename from packages/basemap/doc/users/aea.rst rename to packages/basemap/doc/source/users/aea.rst diff --git a/packages/basemap/doc/users/aeqd.rst b/packages/basemap/doc/source/users/aeqd.rst similarity index 100% rename from packages/basemap/doc/users/aeqd.rst rename to packages/basemap/doc/source/users/aeqd.rst diff --git a/packages/basemap/doc/users/cass.rst b/packages/basemap/doc/source/users/cass.rst similarity index 100% rename from packages/basemap/doc/users/cass.rst rename to packages/basemap/doc/source/users/cass.rst diff --git a/packages/basemap/doc/source/users/cea.rst b/packages/basemap/doc/source/users/cea.rst new file mode 100644 index 000000000..cf72603c7 --- /dev/null +++ b/packages/basemap/doc/source/users/cea.rst @@ -0,0 +1,8 @@ +.. _cea: + +Cylindrical Equal-Area Projection +================================= + +It is what is says. + +.. plot:: users/figures/cea.py diff --git a/packages/basemap/doc/users/cyl.rst b/packages/basemap/doc/source/users/cyl.rst similarity index 100% rename from packages/basemap/doc/users/cyl.rst rename to packages/basemap/doc/source/users/cyl.rst diff --git a/packages/basemap/doc/users/eck4.rst b/packages/basemap/doc/source/users/eck4.rst similarity index 100% rename from packages/basemap/doc/users/eck4.rst rename to packages/basemap/doc/source/users/eck4.rst diff --git a/packages/basemap/doc/users/eqdc.rst b/packages/basemap/doc/source/users/eqdc.rst similarity index 100% rename from packages/basemap/doc/users/eqdc.rst rename to packages/basemap/doc/source/users/eqdc.rst diff --git a/packages/basemap/doc/users/examples.rst b/packages/basemap/doc/source/users/examples.rst similarity index 94% rename from packages/basemap/doc/users/examples.rst rename to packages/basemap/doc/source/users/examples.rst index 00f21aba2..9d0daca31 100644 --- a/packages/basemap/doc/users/examples.rst +++ b/packages/basemap/doc/source/users/examples.rst @@ -32,7 +32,7 @@ For more specifics of how to use the Basemap instance methods, see :ref:`api-index`. Here are the examples (many of which utilize the -`netcdf4-python `__ module +`netcdf4-python `__ module to retrieve datasets over http): * Plot contour lines on a basemap @@ -56,7 +56,7 @@ to retrieve datasets over http): .. plot:: users/figures/plotetopo5.py -* Plot markers at locations of `ARGO `__ floats. +* Plot markers at locations of `ARGO `__ floats. .. plot:: users/figures/plotargo.py diff --git a/packages/basemap/doc/users/figures/aea.py b/packages/basemap/doc/source/users/figures/aea.py similarity index 100% rename from packages/basemap/doc/users/figures/aea.py rename to packages/basemap/doc/source/users/figures/aea.py diff --git a/packages/basemap/doc/users/figures/aeqd.py b/packages/basemap/doc/source/users/figures/aeqd.py similarity index 100% rename from packages/basemap/doc/users/figures/aeqd.py rename to packages/basemap/doc/source/users/figures/aeqd.py diff --git a/packages/basemap/doc/users/figures/aeqd_fulldisk.py b/packages/basemap/doc/source/users/figures/aeqd_fulldisk.py similarity index 100% rename from packages/basemap/doc/users/figures/aeqd_fulldisk.py rename to packages/basemap/doc/source/users/figures/aeqd_fulldisk.py diff --git a/packages/basemap/doc/users/figures/azeqd.py b/packages/basemap/doc/source/users/figures/azeqd.py similarity index 100% rename from packages/basemap/doc/users/figures/azeqd.py rename to packages/basemap/doc/source/users/figures/azeqd.py diff --git a/packages/basemap/doc/users/figures/background1.py b/packages/basemap/doc/source/users/figures/background1.py similarity index 100% rename from packages/basemap/doc/users/figures/background1.py rename to packages/basemap/doc/source/users/figures/background1.py diff --git a/packages/basemap/doc/users/figures/background2.py b/packages/basemap/doc/source/users/figures/background2.py similarity index 100% rename from packages/basemap/doc/users/figures/background2.py rename to packages/basemap/doc/source/users/figures/background2.py diff --git a/packages/basemap/doc/users/figures/background3.py b/packages/basemap/doc/source/users/figures/background3.py similarity index 100% rename from packages/basemap/doc/users/figures/background3.py rename to packages/basemap/doc/source/users/figures/background3.py diff --git a/packages/basemap/doc/users/figures/background4.py b/packages/basemap/doc/source/users/figures/background4.py similarity index 100% rename from packages/basemap/doc/users/figures/background4.py rename to packages/basemap/doc/source/users/figures/background4.py diff --git a/packages/basemap/doc/users/figures/background5.py b/packages/basemap/doc/source/users/figures/background5.py similarity index 100% rename from packages/basemap/doc/users/figures/background5.py rename to packages/basemap/doc/source/users/figures/background5.py diff --git a/packages/basemap/doc/users/figures/cass.py b/packages/basemap/doc/source/users/figures/cass.py similarity index 100% rename from packages/basemap/doc/users/figures/cass.py rename to packages/basemap/doc/source/users/figures/cass.py diff --git a/packages/basemap/doc/users/figures/cea.py b/packages/basemap/doc/source/users/figures/cea.py similarity index 100% rename from packages/basemap/doc/users/figures/cea.py rename to packages/basemap/doc/source/users/figures/cea.py diff --git a/packages/basemap/doc/users/figures/contour1.py b/packages/basemap/doc/source/users/figures/contour1.py similarity index 100% rename from packages/basemap/doc/users/figures/contour1.py rename to packages/basemap/doc/source/users/figures/contour1.py diff --git a/packages/basemap/doc/users/figures/cyl.py b/packages/basemap/doc/source/users/figures/cyl.py similarity index 100% rename from packages/basemap/doc/users/figures/cyl.py rename to packages/basemap/doc/source/users/figures/cyl.py diff --git a/packages/basemap/doc/users/figures/eck4.py b/packages/basemap/doc/source/users/figures/eck4.py similarity index 100% rename from packages/basemap/doc/users/figures/eck4.py rename to packages/basemap/doc/source/users/figures/eck4.py diff --git a/packages/basemap/doc/users/figures/eqdc.py b/packages/basemap/doc/source/users/figures/eqdc.py similarity index 100% rename from packages/basemap/doc/users/figures/eqdc.py rename to packages/basemap/doc/source/users/figures/eqdc.py diff --git a/packages/basemap/doc/users/figures/gall.py b/packages/basemap/doc/source/users/figures/gall.py similarity index 100% rename from packages/basemap/doc/users/figures/gall.py rename to packages/basemap/doc/source/users/figures/gall.py diff --git a/packages/basemap/doc/users/figures/geos_full.py b/packages/basemap/doc/source/users/figures/geos_full.py similarity index 86% rename from packages/basemap/doc/users/figures/geos_full.py rename to packages/basemap/doc/source/users/figures/geos_full.py index 1ccf6cfba..7afe27a4d 100644 --- a/packages/basemap/doc/users/figures/geos_full.py +++ b/packages/basemap/doc/source/users/figures/geos_full.py @@ -5,7 +5,7 @@ # resolution = 'l' means use low resolution coastlines. # optional parameter 'satellite_height' may be used to # specify height of orbit above earth (default 35,786 km). -m = Basemap(projection='geos',lon_0=-105,resolution='l') +m = Basemap(projection='geos',lon_0=-105,resolution='l',rsphere=(6378137.00,6356752.3142)) m.drawcoastlines() m.fillcontinents(color='coral',lake_color='aqua') # draw parallels and meridians. diff --git a/packages/basemap/doc/users/figures/geos_partial.py b/packages/basemap/doc/source/users/figures/geos_partial.py similarity index 79% rename from packages/basemap/doc/users/figures/geos_partial.py rename to packages/basemap/doc/source/users/figures/geos_partial.py index 3d7329073..c3c6ad9cf 100644 --- a/packages/basemap/doc/users/figures/geos_partial.py +++ b/packages/basemap/doc/source/users/figures/geos_partial.py @@ -1,20 +1,25 @@ from mpl_toolkits.basemap import Basemap import numpy as np +import matplotlib as mpl import matplotlib.pyplot as plt +mpl_version = tuple(map(int, mpl.__version__.split("."))) +axkwds = {"axisbg" if mpl_version < (2,) else "facecolor": "k"} + fig = plt.figure() # global geostationary map centered on lon_0 lon_0=57. # resolution = None means don't process the boundary datasets. m1 = Basemap(projection='geos',lon_0=lon_0,resolution=None) # add an axes with a black background -ax = fig.add_axes([0.1,0.1,0.8,0.8],axisbg='k') +ax = fig.add_axes([0.1,0.1,0.8,0.8], **axkwds) # plot just upper right quadrant (corners determined from global map). # keywords llcrnrx,llcrnry,urcrnrx,urcrnry used to define the lower # left and upper right corners in map projection coordinates. # llcrnrlat,llcrnrlon,urcrnrlon,urcrnrlat could be used to define # lat/lon values of corners - but this won't work in cases such as this # where one of the corners does not lie on the earth. -m = Basemap(projection='geos',lon_0=lon_0,resolution='l',\ +m = Basemap(projection='geos',lon_0=lon_0,resolution='l', + rsphere=(6378137.00,6356752.3142), llcrnrx=0.,llcrnry=0.,urcrnrx=m1.urcrnrx/2.,urcrnry=m1.urcrnry/2.) m.drawcoastlines() m.drawmapboundary(fill_color='aqua') diff --git a/packages/basemap/doc/users/figures/gnomon.py b/packages/basemap/doc/source/users/figures/gnomon.py similarity index 100% rename from packages/basemap/doc/users/figures/gnomon.py rename to packages/basemap/doc/source/users/figures/gnomon.py diff --git a/packages/basemap/doc/users/figures/graticule.py b/packages/basemap/doc/source/users/figures/graticule.py similarity index 100% rename from packages/basemap/doc/users/figures/graticule.py rename to packages/basemap/doc/source/users/figures/graticule.py diff --git a/packages/basemap/doc/users/figures/hammer.py b/packages/basemap/doc/source/users/figures/hammer.py similarity index 100% rename from packages/basemap/doc/users/figures/hammer.py rename to packages/basemap/doc/source/users/figures/hammer.py diff --git a/packages/basemap/doc/users/figures/hurrtracks.py b/packages/basemap/doc/source/users/figures/hurrtracks.py similarity index 89% rename from packages/basemap/doc/users/figures/hurrtracks.py rename to packages/basemap/doc/source/users/figures/hurrtracks.py index 2c09020c6..1d1674c83 100644 --- a/packages/basemap/doc/users/figures/hurrtracks.py +++ b/packages/basemap/doc/source/users/figures/hurrtracks.py @@ -3,15 +3,17 @@ part of the track for which storm is cat 4 or 5 is shown red. ESRI shapefile data from http://nationalatlas.gov/mld/huralll.html """ +import os import numpy as np import matplotlib.pyplot as plt -from mpl_toolkits.basemap import Basemap +from mpl_toolkits.basemap import Basemap # Lambert Conformal Conic map. m = Basemap(llcrnrlon=-100.,llcrnrlat=0.,urcrnrlon=-20.,urcrnrlat=57., projection='lcc',lat_1=20.,lat_2=40.,lon_0=-60., resolution ='l',area_thresh=1000.) # read shapefile. -shp_info = m.readshapefile('../../../examples/huralll020','hurrtracks',drawbounds=False) +shp_path = os.path.join(*6 * [".."] + ["examples", "huralll020"]) +shp_info = m.readshapefile(shp_path,'hurrtracks',drawbounds=False) # find names of storms that reached Cat 4. names = [] for shapedict in m.hurrtracks_info: diff --git a/packages/basemap/doc/users/figures/kav7.py b/packages/basemap/doc/source/users/figures/kav7.py similarity index 100% rename from packages/basemap/doc/users/figures/kav7.py rename to packages/basemap/doc/source/users/figures/kav7.py diff --git a/packages/basemap/doc/users/figures/laea.py b/packages/basemap/doc/source/users/figures/laea.py similarity index 100% rename from packages/basemap/doc/users/figures/laea.py rename to packages/basemap/doc/source/users/figures/laea.py diff --git a/packages/basemap/doc/users/figures/lcc.py b/packages/basemap/doc/source/users/figures/lcc.py similarity index 100% rename from packages/basemap/doc/users/figures/lcc.py rename to packages/basemap/doc/source/users/figures/lcc.py diff --git a/packages/basemap/doc/users/figures/mbtfpq.py b/packages/basemap/doc/source/users/figures/mbtfpq.py similarity index 100% rename from packages/basemap/doc/users/figures/mbtfpq.py rename to packages/basemap/doc/source/users/figures/mbtfpq.py diff --git a/packages/basemap/doc/users/figures/merc.py b/packages/basemap/doc/source/users/figures/merc.py similarity index 100% rename from packages/basemap/doc/users/figures/merc.py rename to packages/basemap/doc/source/users/figures/merc.py diff --git a/packages/basemap/doc/users/figures/mill.py b/packages/basemap/doc/source/users/figures/mill.py similarity index 100% rename from packages/basemap/doc/users/figures/mill.py rename to packages/basemap/doc/source/users/figures/mill.py diff --git a/packages/basemap/doc/users/figures/moll.py b/packages/basemap/doc/source/users/figures/moll.py similarity index 100% rename from packages/basemap/doc/users/figures/moll.py rename to packages/basemap/doc/source/users/figures/moll.py diff --git a/packages/basemap/doc/users/figures/npaeqd.py b/packages/basemap/doc/source/users/figures/npaeqd.py similarity index 100% rename from packages/basemap/doc/users/figures/npaeqd.py rename to packages/basemap/doc/source/users/figures/npaeqd.py diff --git a/packages/basemap/doc/users/figures/nplaea.py b/packages/basemap/doc/source/users/figures/nplaea.py similarity index 100% rename from packages/basemap/doc/users/figures/nplaea.py rename to packages/basemap/doc/source/users/figures/nplaea.py diff --git a/packages/basemap/doc/users/figures/npstere.py b/packages/basemap/doc/source/users/figures/npstere.py similarity index 100% rename from packages/basemap/doc/users/figures/npstere.py rename to packages/basemap/doc/source/users/figures/npstere.py diff --git a/packages/basemap/doc/users/figures/nsper_full.py b/packages/basemap/doc/source/users/figures/nsper_full.py similarity index 100% rename from packages/basemap/doc/users/figures/nsper_full.py rename to packages/basemap/doc/source/users/figures/nsper_full.py diff --git a/packages/basemap/doc/users/figures/nsper_partial.py b/packages/basemap/doc/source/users/figures/nsper_partial.py similarity index 87% rename from packages/basemap/doc/users/figures/nsper_partial.py rename to packages/basemap/doc/source/users/figures/nsper_partial.py index 89795398b..0e9762169 100644 --- a/packages/basemap/doc/users/figures/nsper_partial.py +++ b/packages/basemap/doc/source/users/figures/nsper_partial.py @@ -1,6 +1,10 @@ from mpl_toolkits.basemap import Basemap import numpy as np +import matplotlib as mpl import matplotlib.pyplot as plt +mpl_version = tuple(map(int, mpl.__version__.split("."))) +axkwds = {"axisbg" if mpl_version < (2,) else "facecolor": "k"} + fig = plt.figure() # global ortho map centered on lon_0,lat_0 lat_0=10.; lon_0=57. @@ -10,7 +14,7 @@ m1 = Basemap(projection='nsper',satellite_height=h*1000.,\ lon_0=lon_0,lat_0=lat_0,resolution=None) # add an axes with a black background -ax = fig.add_axes([0.1,0.1,0.8,0.8],axisbg='k') +ax = fig.add_axes([0.1,0.1,0.8,0.8], **axkwds) # plot just upper right quadrant (corners determined from global map). # keywords llcrnrx,llcrnry,urcrnrx,urcrnry used to define the lower # left and upper right corners in map projection coordinates. diff --git a/packages/basemap/doc/users/figures/omerc.py b/packages/basemap/doc/source/users/figures/omerc.py similarity index 100% rename from packages/basemap/doc/users/figures/omerc.py rename to packages/basemap/doc/source/users/figures/omerc.py diff --git a/packages/basemap/doc/users/figures/ortho_full.py b/packages/basemap/doc/source/users/figures/ortho_full.py similarity index 100% rename from packages/basemap/doc/users/figures/ortho_full.py rename to packages/basemap/doc/source/users/figures/ortho_full.py diff --git a/packages/basemap/doc/users/figures/ortho_partial.py b/packages/basemap/doc/source/users/figures/ortho_partial.py similarity index 86% rename from packages/basemap/doc/users/figures/ortho_partial.py rename to packages/basemap/doc/source/users/figures/ortho_partial.py index e1adc9c01..c41656311 100644 --- a/packages/basemap/doc/users/figures/ortho_partial.py +++ b/packages/basemap/doc/source/users/figures/ortho_partial.py @@ -1,13 +1,17 @@ from mpl_toolkits.basemap import Basemap import numpy as np +import matplotlib as mpl import matplotlib.pyplot as plt +mpl_version = tuple(map(int, mpl.__version__.split("."))) +axkwds = {"axisbg" if mpl_version < (2,) else "facecolor": "k"} + fig = plt.figure() # global ortho map centered on lon_0,lat_0 lat_0=10.; lon_0=57. # resolution = None means don't process the boundary datasets. m1 = Basemap(projection='ortho',lon_0=lon_0,lat_0=lat_0,resolution=None) # add an axes with a black background -ax = fig.add_axes([0.1,0.1,0.8,0.8],axisbg='k') +ax = fig.add_axes([0.1,0.1,0.8,0.8], **axkwds) # plot just upper right quadrant (corners determined from global map). # keywords llcrnrx,llcrnry,urcrnrx,urcrnry used to define the lower # left and upper right corners in map projection coordinates. diff --git a/packages/basemap/doc/users/figures/plotargo.py b/packages/basemap/doc/source/users/figures/plotargo.py similarity index 68% rename from packages/basemap/doc/users/figures/plotargo.py rename to packages/basemap/doc/source/users/figures/plotargo.py index 6c8fa05f0..8209b7118 100644 --- a/packages/basemap/doc/users/figures/plotargo.py +++ b/packages/basemap/doc/source/users/figures/plotargo.py @@ -2,14 +2,18 @@ import time, calendar, datetime, numpy from mpl_toolkits.basemap import Basemap import matplotlib.pyplot as plt -import urllib, os +import os +try: + from urllib.request import urlretrieve +except ImportError: + from urllib import urlretrieve # data downloaded from the form at -# http://coastwatch.pfeg.noaa.gov/erddap/tabledap/apdrcArgoAll.html -filename, headers = urllib.urlretrieve('http://coastwatch.pfeg.noaa.gov/erddap/tabledap/apdrcArgoAll.nc?longitude,latitude,time&longitude>=0&longitude<=360&latitude>=-90&latitude<=90&time>=2010-01-01&time<=2010-01-08&distinct()') +# http://coastwatch.pfeg.noaa.gov/erddap/tabledap/apdrcArgoAll.html +filename, headers = urlretrieve("https://erddap.ifremer.fr/erddap/tabledap/ArgoFloats-index.nc?date%2Clatitude%2Clongitude&date%3E=2010-01-01&date%3C=2010-01-08&latitude%3E=-90&latitude%3C=90&longitude%3E=-180&longitude%3C=180&distinct()") dset = Dataset(filename) lats = dset.variables['latitude'][:] lons = dset.variables['longitude'][:] -time = dset.variables['time'] +time = dset.variables['date'] # seconds since epoch times = time[:] t1 = times.min(); t2 = times.max() date1 = num2date(t1, units=time.units) diff --git a/packages/basemap/doc/users/figures/plotboulder.py b/packages/basemap/doc/source/users/figures/plotboulder.py similarity index 100% rename from packages/basemap/doc/users/figures/plotboulder.py rename to packages/basemap/doc/source/users/figures/plotboulder.py diff --git a/packages/basemap/doc/users/figures/plotdaynight.py b/packages/basemap/doc/source/users/figures/plotdaynight.py similarity index 100% rename from packages/basemap/doc/users/figures/plotdaynight.py rename to packages/basemap/doc/source/users/figures/plotdaynight.py diff --git a/packages/basemap/doc/users/figures/plotetopo5.py b/packages/basemap/doc/source/users/figures/plotetopo5.py similarity index 100% rename from packages/basemap/doc/users/figures/plotetopo5.py rename to packages/basemap/doc/source/users/figures/plotetopo5.py diff --git a/packages/basemap/doc/users/figures/plotgreatcircle.py b/packages/basemap/doc/source/users/figures/plotgreatcircle.py similarity index 100% rename from packages/basemap/doc/users/figures/plotgreatcircle.py rename to packages/basemap/doc/source/users/figures/plotgreatcircle.py diff --git a/packages/basemap/doc/users/figures/plothighsandlows.py b/packages/basemap/doc/source/users/figures/plothighsandlows.py similarity index 94% rename from packages/basemap/doc/users/figures/plothighsandlows.py rename to packages/basemap/doc/source/users/figures/plothighsandlows.py index cf93f2c9c..3a7c3f963 100644 --- a/packages/basemap/doc/users/figures/plothighsandlows.py +++ b/packages/basemap/doc/source/users/figures/plothighsandlows.py @@ -23,13 +23,10 @@ def extrema(mat,mode='wrap',window=10): date = datetime.now().strftime('%Y%m%d')+'00' # open OpenDAP dataset. -#data=Dataset("http://nomads.ncep.noaa.gov:9090/dods/gfs/gfs/%s/gfs_%sz_anl" %\ -# (date[0:8],date[8:10])) -data=Dataset("http://nomads.ncep.noaa.gov:9090/dods/gfs_hd/gfs_hd%s/gfs_hd_%sz"%\ +data=Dataset("https://nomads.ncep.noaa.gov/dods/gfs_0p50/gfs%s/gfs_0p50_%sz"%\ (date[0:8],date[8:10])) - # read lats,lons. lats = data.variables['lat'][:] lons1 = data.variables['lon'][:] diff --git a/packages/basemap/doc/users/figures/plotprecip.py b/packages/basemap/doc/source/users/figures/plotprecip.py similarity index 93% rename from packages/basemap/doc/users/figures/plotprecip.py rename to packages/basemap/doc/source/users/figures/plotprecip.py index 8a33afa0f..95fd7ef67 100644 --- a/packages/basemap/doc/users/figures/plotprecip.py +++ b/packages/basemap/doc/source/users/figures/plotprecip.py @@ -1,13 +1,15 @@ from mpl_toolkits.basemap import Basemap, cm # requires netcdf4-python (netcdf4-python.googlecode.com) from netCDF4 import Dataset as NetCDFFile +import os import numpy as np import matplotlib.pyplot as plt # plot rainfall from NWS using special precipitation # colormap used by the NWS, and included in basemap. -nc = NetCDFFile('../../../examples/nws_precip_conus_20061222.nc') +ncpath = os.path.join(*6 * [".."] + ["examples", "nws_precip_conus_20061222.nc"]) +nc = NetCDFFile(ncpath) # data from http://water.weather.gov/precip/ prcpvar = nc.variables['amountofprecip'] data = 0.01*prcpvar[:] diff --git a/packages/basemap/doc/users/figures/plotsst.py b/packages/basemap/doc/source/users/figures/plotsst.py similarity index 69% rename from packages/basemap/doc/users/figures/plotsst.py rename to packages/basemap/doc/source/users/figures/plotsst.py index 485e6ffd2..a8652c34d 100644 --- a/packages/basemap/doc/users/figures/plotsst.py +++ b/packages/basemap/doc/source/users/figures/plotsst.py @@ -3,20 +3,31 @@ import numpy as np import matplotlib.pyplot as plt from datetime import datetime +try: + from urllib.request import urlretrieve +except ImportError: + from urllib import urlretrieve date = datetime(2007,12,15,0) # date to plot. # open dataset. -dataset = \ -Dataset('http://www.ncdc.noaa.gov/thredds/dodsC/OISST-V2-AVHRR_agg') +sstpath, sstheader = urlretrieve("https://downloads.psl.noaa.gov/Datasets/noaa.oisst.v2.highres/sst.day.mean.{0}.nc".format(date.year)) +dataset = Dataset(sstpath) timevar = dataset.variables['time'] timeindex = date2index(date,timevar) # find time index for desired date. # read sst. Will automatically create a masked array using # missing_value variable attribute. 'squeeze out' singleton dimensions. sst = dataset.variables['sst'][timeindex,:].squeeze() # read ice. -ice = dataset.variables['ice'][timeindex,:].squeeze() +dataset.close() +icepath, iceheader = urlretrieve("https://downloads.psl.noaa.gov/Datasets/noaa.oisst.v2.highres/icec.day.mean.{0}.nc".format(date.year)) +dataset = Dataset(icepath) +ice = dataset.variables['icec'][timeindex,:].squeeze() # read lats and lons (representing centers of grid boxes). lats = dataset.variables['lat'][:] lons = dataset.variables['lon'][:] +dataset.close() +latstep, lonstep = np.diff(lats[:2]), np.diff(lons[:2]) +lats = np.append(lats - 0.5 * latstep, lats[-1] + 0.5 * latstep) +lons = np.append(lons - 0.5 * lonstep, lons[-1] + 0.5 * lonstep) lons, lats = np.meshgrid(lons,lats) # create figure, axes instances. fig = plt.figure() diff --git a/packages/basemap/doc/users/figures/plotwindvec.py b/packages/basemap/doc/source/users/figures/plotwindvec.py similarity index 85% rename from packages/basemap/doc/users/figures/plotwindvec.py rename to packages/basemap/doc/source/users/figures/plotwindvec.py index de0797617..0c542bca3 100644 --- a/packages/basemap/doc/users/figures/plotwindvec.py +++ b/packages/basemap/doc/source/users/figures/plotwindvec.py @@ -4,10 +4,10 @@ from mpl_toolkits.basemap import Basemap, shiftgrid from netCDF4 import Dataset # specify date to plot. -yyyy=1993; mm=03; dd=14; hh=00 +yyyy=1993; mm=3; dd=14; hh=0 date = datetime.datetime(yyyy,mm,dd,hh) # set OpenDAP server URL. -URLbase="http://nomads.ncdc.noaa.gov/thredds/dodsC/modeldata/cmd_pgbh/" +URLbase="https://www.ncei.noaa.gov/thredds/dodsC/model-cfs_reanl_6h_pgb/" URL=URLbase+"%04i/%04i%02i/%04i%02i%02i/pgbh00.gdas.%04i%02i%02i%02i.grb2" %\ (yyyy,yyyy,mm,yyyy,mm,dd,yyyy,mm,dd,hh) data = Dataset(URL) @@ -18,8 +18,8 @@ # get sea level pressure and 10-m wind data. # mult slp by 0.01 to put in units of hPa. slpin = 0.01*data.variables['Pressure_msl'][:].squeeze() -uin = data.variables['U-component_of_wind_height_above_ground'][:].squeeze() -vin = data.variables['V-component_of_wind_height_above_ground'][:].squeeze() +uin = data.variables['u-component_of_wind_height_above_ground'][:].squeeze() +vin = data.variables['v-component_of_wind_height_above_ground'][:].squeeze() # add cyclic points manually (could use addcyclic function) slp = np.zeros((slpin.shape[0],slpin.shape[1]+1),np.float64) slp[:,0:-1] = slpin[::-1]; slp[:,-1] = slpin[::-1,0] @@ -43,8 +43,8 @@ parallels = np.arange(-80.,90,20.) meridians = np.arange(0.,360.,20.) # plot SLP contours. -CS1 = m.contour(x,y,slp,clevs,linewidths=0.5,colors='k',animated=True) -CS2 = m.contourf(x,y,slp,clevs,cmap=plt.cm.RdBu_r,animated=True) +CS1 = m.contour(x,y,slp,clevs,linewidths=0.5,colors='k') +CS2 = m.contourf(x,y,slp,clevs,cmap=plt.cm.RdBu_r) # plot wind vectors on projection grid. # first, shift grid so it goes from -180 to 180 (instead of 0 to 360 # in longitude). Otherwise, interpolation is messed up. @@ -72,8 +72,8 @@ fig2 = plt.figure(figsize=(8,10)) ax = fig2.add_axes([0.1,0.1,0.8,0.8]) # plot SLP contours -CS1 = m.contour(x,y,slp,clevs,linewidths=0.5,colors='k',animated=True) -CS2 = m.contourf(x,y,slp,clevs,cmap=plt.cm.RdBu_r,animated=True) +CS1 = m.contour(x,y,slp,clevs,linewidths=0.5,colors='k') +CS2 = m.contourf(x,y,slp,clevs,cmap=plt.cm.RdBu_r) # plot wind barbs over map. barbs = m.barbs(xx,yy,uproj,vproj,length=5,barbcolor='k',flagcolor='r',linewidth=0.5) # draw coastlines, parallels, meridians. diff --git a/packages/basemap/doc/users/figures/poly.py b/packages/basemap/doc/source/users/figures/poly.py similarity index 100% rename from packages/basemap/doc/users/figures/poly.py rename to packages/basemap/doc/source/users/figures/poly.py diff --git a/packages/basemap/doc/users/figures/robin.py b/packages/basemap/doc/source/users/figures/robin.py similarity index 100% rename from packages/basemap/doc/users/figures/robin.py rename to packages/basemap/doc/source/users/figures/robin.py diff --git a/packages/basemap/doc/users/figures/sinu.py b/packages/basemap/doc/source/users/figures/sinu.py similarity index 100% rename from packages/basemap/doc/users/figures/sinu.py rename to packages/basemap/doc/source/users/figures/sinu.py diff --git a/packages/basemap/doc/users/figures/spaeqd.py b/packages/basemap/doc/source/users/figures/spaeqd.py similarity index 100% rename from packages/basemap/doc/users/figures/spaeqd.py rename to packages/basemap/doc/source/users/figures/spaeqd.py diff --git a/packages/basemap/doc/users/figures/splaea.py b/packages/basemap/doc/source/users/figures/splaea.py similarity index 100% rename from packages/basemap/doc/users/figures/splaea.py rename to packages/basemap/doc/source/users/figures/splaea.py diff --git a/packages/basemap/doc/users/figures/spstere.py b/packages/basemap/doc/source/users/figures/spstere.py similarity index 100% rename from packages/basemap/doc/users/figures/spstere.py rename to packages/basemap/doc/source/users/figures/spstere.py diff --git a/packages/basemap/doc/users/figures/stere.py b/packages/basemap/doc/source/users/figures/stere.py similarity index 100% rename from packages/basemap/doc/users/figures/stere.py rename to packages/basemap/doc/source/users/figures/stere.py diff --git a/packages/basemap/doc/users/figures/tmerc.py b/packages/basemap/doc/source/users/figures/tmerc.py similarity index 100% rename from packages/basemap/doc/users/figures/tmerc.py rename to packages/basemap/doc/source/users/figures/tmerc.py diff --git a/packages/basemap/doc/users/figures/vandg.py b/packages/basemap/doc/source/users/figures/vandg.py similarity index 100% rename from packages/basemap/doc/users/figures/vandg.py rename to packages/basemap/doc/source/users/figures/vandg.py diff --git a/packages/basemap/doc/users/gall.rst b/packages/basemap/doc/source/users/gall.rst similarity index 100% rename from packages/basemap/doc/users/gall.rst rename to packages/basemap/doc/source/users/gall.rst diff --git a/packages/basemap/doc/users/geography.rst b/packages/basemap/doc/source/users/geography.rst similarity index 87% rename from packages/basemap/doc/users/geography.rst rename to packages/basemap/doc/source/users/geography.rst index e69e8df8a..ce71334c4 100644 --- a/packages/basemap/doc/users/geography.rst +++ b/packages/basemap/doc/source/users/geography.rst @@ -3,11 +3,10 @@ Drawing a Map Background ======================== -Basemap includes the GSSH (now -`GSHHG `_) +Basemap includes the `GSHHG `_ coastline dataset, as well as datasets for rivers, state and country boundaries from -`GMT `_. +`GMT `_. These datasets can be used to draw coastlines, rivers and political boundaries on maps at several different resolutions. The relevant Basemap methods are: @@ -36,13 +35,13 @@ used as a map background. Basemap provides several options for this: mask is derived from the GSHHS coastline data, and there are several coastline options and pixel sizes to choose from. * :func:`~mpl_toolkits.basemap.Basemap.bluemarble`: draw a NASA - `Blue Marble `_ + `Blue Marble `_ image as a map background. * :func:`~mpl_toolkits.basemap.Basemap.shadedrelief`: draw a - `shaded relief `_ image + `shaded relief `_ image as a map background. * :func:`~mpl_toolkits.basemap.Basemap.etopo`: draw an - `etopo `_ + `etopo `_ relief image as map background. * :func:`~mpl_toolkits.basemap.Basemap.warpimage`: use an abitrary image as a map background. The image must be global, covering the diff --git a/packages/basemap/doc/users/geos.rst b/packages/basemap/doc/source/users/geos.rst similarity index 100% rename from packages/basemap/doc/users/geos.rst rename to packages/basemap/doc/source/users/geos.rst diff --git a/packages/basemap/doc/users/gnomon.rst b/packages/basemap/doc/source/users/gnomon.rst similarity index 100% rename from packages/basemap/doc/users/gnomon.rst rename to packages/basemap/doc/source/users/gnomon.rst diff --git a/packages/basemap/doc/users/graticule.rst b/packages/basemap/doc/source/users/graticule.rst similarity index 100% rename from packages/basemap/doc/users/graticule.rst rename to packages/basemap/doc/source/users/graticule.rst diff --git a/packages/basemap/doc/users/hammer.rst b/packages/basemap/doc/source/users/hammer.rst similarity index 100% rename from packages/basemap/doc/users/hammer.rst rename to packages/basemap/doc/source/users/hammer.rst diff --git a/packages/basemap/doc/source/users/index.rst b/packages/basemap/doc/source/users/index.rst new file mode 100644 index 000000000..d79f0783c --- /dev/null +++ b/packages/basemap/doc/source/users/index.rst @@ -0,0 +1,17 @@ +.. _users-guide-index: + +Basemap User's Guide +==================== + +:Release: |release| +:Date: |today| + +.. toctree:: + + introduction.rst + installation.rst + mapsetup.rst + geography.rst + graticule.rst + mapcoords.rst + examples.rst diff --git a/packages/basemap/doc/source/users/installation.rst b/packages/basemap/doc/source/users/installation.rst new file mode 100644 index 000000000..f9bd57c4e --- /dev/null +++ b/packages/basemap/doc/source/users/installation.rst @@ -0,0 +1,98 @@ +Installation +============ + +Installing from PyPI +-------------------- + +Precompiled binary wheels for Windows and GNU/Linux are available in +PyPI (architectures x86 and x64, Python 2.7 and 3.5+) and can be +installed with `pip`_: + +.. code-block:: sh + + python -m pip install basemap + +Installing ``basemap`` will also install ``basemap-data``, containing the +minimal data assets required by ``basemap``. If you also need the +high-resolution data assets, you can install them with `pip`_ too: + +.. code-block:: sh + + python -m pip install basemap-data-hires + +Installing from conda-forge +--------------------------- + +For Miniforge users, ``basemap`` packages are available through the +``conda-forge`` channel for Windows and GNU/Linux (x64) as well as +for MacOS (x64 and arm64): + +.. code-block:: sh + + conda install -c conda-forge basemap + +Similarly to the PyPI installation, the high-resolution data assets +can be installed separately if needed: + +.. code-block:: sh + + conda install -c conda-forge basemap-data-hires + +Installing from source +---------------------- + +Optionally, you can also install ``basemap`` from its source hosted +on GitHub as indicated in the following steps: + +1. Install pre-requisite Python modules: + + - `cython`_ + - `numpy`_ + +2. Download the ``basemap`` source code and move to the + ``packages/basemap`` folder: + + .. code-block:: sh + + git clone --depth 1 https://github.com/matplotlib/basemap.git + cd basemap/packages/basemap + +3. Build the `GEOS`_ library. You may use the helper provided in the + ``utils`` folder (please note that you need `CMake`_ and a working + C compiler in advance): + + .. code-block:: sh + + export GEOS_DIR= + python -c "import utils; utils.GeosLibrary('3.6.5').build(installdir='${GEOS_DIR}')" + + or you can link directly to the system library if it is already + installed. ``GEOS_DIR`` must point to the GEOS installation prefix; + e.g. if ``libgeos_c.so`` is located in ``/usr/lib`` and ``geos_c.h`` + is located in ``/usr/include``, then you must set ``GEOS_DIR`` to + ``/usr``. + +4. Build and install the ``basemap`` binary wheel: + + .. code-block:: sh + + python -m pip install . + + On GNU/Linux, if your Python was installed through a package + management system, make sure that you have the Python header + ``Python.h`` required to build Cython extensions (e.g. on + Debian-like systems, you should have the package ``python-dev`` + installed). + +5. Check that the package was installed correctly by executing: + + .. code-block:: sh + + python -c "from mpl_toolkits.basemap import Basemap" + + +.. _pip: https://pip.pypa.io/ +.. _cython: https://github.com/cython/cython +.. _numpy: https://github.com/numpy/numpy +.. _GEOS: https://github.com/libgeos/geos +.. _CMake: https://cmake.org/ diff --git a/packages/basemap/doc/source/users/introduction.rst b/packages/basemap/doc/source/users/introduction.rst new file mode 100644 index 000000000..ac5567a51 --- /dev/null +++ b/packages/basemap/doc/source/users/introduction.rst @@ -0,0 +1,38 @@ +Introduction +============ + +The matplotlib basemap toolkit is a library for plotting 2D data on maps +in `Python`_. It is similar in functionality to `GrADS`_, `GMT`_, the +`MATLAB Mapping Toolbox`_ and the `IDL Mapping Facilities`_. `CDAT`_ +and `PyNGL`_ are other Python libraries with similar capabilities. + +Basemap does not plot on its own, but provides the facilities to +transform coordinates to one of 25 different map projections (using +`pyproj`_ and therefore the `PROJ`_ C library). Then `matplotlib`_ is +used to plot contours, images, vectors, lines or points in the +transformed coordinates. Shoreline, river and political boundary +datasets (extracted from `GMT`_) are provided, together with methods +for plotting them. The `GEOS`_ library is used internally to clip the +coastline and political boundary features to the map projection region. + +Basemap is geared towards the needs of Earth scientists, particularly +oceanographers and meteorologists. Jeff Whitaker originally wrote +Basemap to help in his research (climate and weather forecasting), +since at the time `CDAT`_ was the only other tool in Python for +plotting data on map projections. Over the years, the capabilities +of basemap have evolved as scientists in other disciplines (such as +biology, geology and geophysics) requested and contributed new features. + + +.. _Python: https://www.python.org/ +.. _GMT: https://www.generic-mapping-tools.org/ +.. _GrADS: http://cola.gmu.edu/grads/ +.. _MATLAB Mapping Toolbox: https://www.mathworks.com/help/map/map.html +.. _IDL Mapping Facilities: https://www.nv5geospatialsoftware.com/docs/mapping_funct_list.html +.. _CDAT: https://cdat.llnl.gov/ +.. _PyNGL: https://www.pyngl.ucar.edu/ + +.. _pyproj: https://pyproj4.github.io/pyproj +.. _PROJ: https://proj.org/ +.. _matplotlib: https://matplotlib.org/ +.. _GEOS: https://libgeos.org/ diff --git a/packages/basemap/doc/users/kav7.rst b/packages/basemap/doc/source/users/kav7.rst similarity index 100% rename from packages/basemap/doc/users/kav7.rst rename to packages/basemap/doc/source/users/kav7.rst diff --git a/packages/basemap/doc/users/laea.rst b/packages/basemap/doc/source/users/laea.rst similarity index 100% rename from packages/basemap/doc/users/laea.rst rename to packages/basemap/doc/source/users/laea.rst diff --git a/packages/basemap/doc/users/lcc.rst b/packages/basemap/doc/source/users/lcc.rst similarity index 100% rename from packages/basemap/doc/users/lcc.rst rename to packages/basemap/doc/source/users/lcc.rst diff --git a/packages/basemap/doc/users/mapcoords.rst b/packages/basemap/doc/source/users/mapcoords.rst similarity index 100% rename from packages/basemap/doc/users/mapcoords.rst rename to packages/basemap/doc/source/users/mapcoords.rst diff --git a/packages/basemap/doc/users/mapsetup.rst b/packages/basemap/doc/source/users/mapsetup.rst similarity index 100% rename from packages/basemap/doc/users/mapsetup.rst rename to packages/basemap/doc/source/users/mapsetup.rst diff --git a/packages/basemap/doc/users/mbtfpq.rst b/packages/basemap/doc/source/users/mbtfpq.rst similarity index 100% rename from packages/basemap/doc/users/mbtfpq.rst rename to packages/basemap/doc/source/users/mbtfpq.rst diff --git a/packages/basemap/doc/users/merc.rst b/packages/basemap/doc/source/users/merc.rst similarity index 100% rename from packages/basemap/doc/users/merc.rst rename to packages/basemap/doc/source/users/merc.rst diff --git a/packages/basemap/doc/users/mill.rst b/packages/basemap/doc/source/users/mill.rst similarity index 100% rename from packages/basemap/doc/users/mill.rst rename to packages/basemap/doc/source/users/mill.rst diff --git a/packages/basemap/doc/users/moll.rst b/packages/basemap/doc/source/users/moll.rst similarity index 100% rename from packages/basemap/doc/users/moll.rst rename to packages/basemap/doc/source/users/moll.rst diff --git a/packages/basemap/doc/users/nsper.rst b/packages/basemap/doc/source/users/nsper.rst similarity index 100% rename from packages/basemap/doc/users/nsper.rst rename to packages/basemap/doc/source/users/nsper.rst diff --git a/packages/basemap/doc/users/omerc.rst b/packages/basemap/doc/source/users/omerc.rst similarity index 100% rename from packages/basemap/doc/users/omerc.rst rename to packages/basemap/doc/source/users/omerc.rst diff --git a/packages/basemap/doc/users/ortho.rst b/packages/basemap/doc/source/users/ortho.rst similarity index 100% rename from packages/basemap/doc/users/ortho.rst rename to packages/basemap/doc/source/users/ortho.rst diff --git a/packages/basemap/doc/users/paeqd.rst b/packages/basemap/doc/source/users/paeqd.rst similarity index 100% rename from packages/basemap/doc/users/paeqd.rst rename to packages/basemap/doc/source/users/paeqd.rst diff --git a/packages/basemap/doc/users/plaea.rst b/packages/basemap/doc/source/users/plaea.rst similarity index 100% rename from packages/basemap/doc/users/plaea.rst rename to packages/basemap/doc/source/users/plaea.rst diff --git a/packages/basemap/doc/users/poly.rst b/packages/basemap/doc/source/users/poly.rst similarity index 100% rename from packages/basemap/doc/users/poly.rst rename to packages/basemap/doc/source/users/poly.rst diff --git a/packages/basemap/doc/users/pstere.rst b/packages/basemap/doc/source/users/pstere.rst similarity index 100% rename from packages/basemap/doc/users/pstere.rst rename to packages/basemap/doc/source/users/pstere.rst diff --git a/packages/basemap/doc/users/robin.rst b/packages/basemap/doc/source/users/robin.rst similarity index 100% rename from packages/basemap/doc/users/robin.rst rename to packages/basemap/doc/source/users/robin.rst diff --git a/packages/basemap/doc/users/sinu.rst b/packages/basemap/doc/source/users/sinu.rst similarity index 100% rename from packages/basemap/doc/users/sinu.rst rename to packages/basemap/doc/source/users/sinu.rst diff --git a/packages/basemap/doc/users/stere.rst b/packages/basemap/doc/source/users/stere.rst similarity index 100% rename from packages/basemap/doc/users/stere.rst rename to packages/basemap/doc/source/users/stere.rst diff --git a/packages/basemap/doc/users/tmerc.rst b/packages/basemap/doc/source/users/tmerc.rst similarity index 100% rename from packages/basemap/doc/users/tmerc.rst rename to packages/basemap/doc/source/users/tmerc.rst diff --git a/packages/basemap/doc/users/vandg.rst b/packages/basemap/doc/source/users/vandg.rst similarity index 100% rename from packages/basemap/doc/users/vandg.rst rename to packages/basemap/doc/source/users/vandg.rst diff --git a/packages/basemap/doc/users/cea.rst b/packages/basemap/doc/users/cea.rst deleted file mode 100644 index 7271c7f64..000000000 --- a/packages/basemap/doc/users/cea.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. _cea: - -Cylindrial Equal-Area Projection -================================ - -It is what is says. - -.. plot:: users/figures/cea.py diff --git a/packages/basemap/doc/users/download.rst b/packages/basemap/doc/users/download.rst deleted file mode 100644 index 40eabf307..000000000 --- a/packages/basemap/doc/users/download.rst +++ /dev/null @@ -1,9 +0,0 @@ -Download -======== - -Source code can be found -`here `__ - -The recommended installation method is using anaconda through the -conda-forge channel. Basemap is no longer uploaded to PyPI due to its -size and non-python external dependencies. diff --git a/packages/basemap/doc/users/index.rst b/packages/basemap/doc/users/index.rst deleted file mode 100644 index 69dea0050..000000000 --- a/packages/basemap/doc/users/index.rst +++ /dev/null @@ -1,19 +0,0 @@ -.. _users-guide-index: - -############################################# - The Matplotlib Basemap Toolkit User's Guide -############################################# - -:Release: |version| -:Date: |today| - -.. toctree:: - - download.rst - intro.rst - installing.rst - mapsetup.rst - geography.rst - graticule.rst - mapcoords.rst - examples.rst diff --git a/packages/basemap/doc/users/installing.rst b/packages/basemap/doc/users/installing.rst deleted file mode 100644 index b27b161aa..000000000 --- a/packages/basemap/doc/users/installing.rst +++ /dev/null @@ -1,76 +0,0 @@ -.. _installing: - -********** -Installing -********** - -Dependencies -============ - -**Requirements** - -These are external packages which you will need to install before -installing Basemap. - - -Matplotlib 1.0.0 (or later, `download `__) - -Python 2.6 (or later, including Python 3) (`download `__) - Matplotlib 2.2 LTS requires Python 2.7 or later - Matplotlib 3.0 requires Python 3.5 or later - -NumPy 1.2.1 (or later) - Array support for Python (`download `__) - -`PROJ4 `__ Cartographic Projections Library. - -**Required library that ships with Basemap** - -`GEOS `__ (Geometry Engine - Open Source) library 3.1.1 or later. - Source code is included in the geos-3.3.3 directory. - When building from source, must be built and installed separately - from basemap (see build instructions below). - Included in Windows binary installers. - -**Optional libraries** - -Pillow - Python Imaging Library (`download `__), - only needed for :func:`~mpl_toolkits.basemap.Basemap.bluemarble`, :func:`~mpl_toolkits.basemap.Basemap.etopo`, :func:`~mpl_toolkits.basemap.Basemap.shadedrelief` and :func:`~mpl_toolkits.basemap.Basemap.warpimage` instance methods. - -Installation -============ - -Download either Windows binary installers or source tarballs -`here `__. - -To install from the source, follow these steps: - - -* Install pre-requisite requirements. - -* Untar the basemap version X.Y.Z source tar.gz file, and - and cd to the basemap-X.Y.Z directory. - -* Install the GEOS library. If you already have it on your - system, just set the environment variable GEOS_DIR to point to the location - of libgeos_c and geos_c.h (if libgeos_c is in /usr/local/lib and - geos_c.h is in /usr/local/include, set GEOS_DIR to /usr/local). - Then go to next step. If you don't have it, you can build it from - the source code included with basemap by following these steps:: - - cd geos-3.3.3 - export GEOS_DIR= - # A reasonable choice on a Unix-like system is /usr/local, or - # if you don't have permission to write there, your home directory. - ./configure --prefix=$GEOS_DIR - make; make install - -* cd back to the top level basemap directory (basemap-X.Y.Z) and - run the usual ``python setup.py install``. Check your installation - by running ``from mpl_toolkits.basemap import Basemap`` at the Python - prompt. - -* To test, cd to the examples directory and run ``python simpletest.py``. - To run all the examples (except those that have extra dependencies - or require an internet connection), execute ``python run_all.py``. diff --git a/packages/basemap/doc/users/intro.rst b/packages/basemap/doc/users/intro.rst deleted file mode 100644 index 46965fcf3..000000000 --- a/packages/basemap/doc/users/intro.rst +++ /dev/null @@ -1,31 +0,0 @@ -Introduction -============ - -The matplotlib basemap toolkit is a library for plotting 2D data on maps -in `Python `_. It is similar in functionality to -the `matlab mapping toolbox `_, -the `IDL mapping facilities `_, -`GrADS `_, or the -`Generic Mapping Tools `_. -`PyNGL `_ and -`CDAT `_ -are other libraries that provide similar capabilities in Python. - -Basemap does not do any plotting on it's own, but provides the facilities to transform coordinates to one of 25 different map projections (using the -`PROJ.4 `_ C library). `Matplotlib -`_ is then -used to plot contours, images, vectors, lines or points -in the transformed coordinates. -Shoreline, river and political boundary -datasets (from `Generic Mapping Tools `_) -are provided, along with methods for plotting them. The `GEOS library -`_ is used internally to clip the coastline and polticial boundary features to the desired map projection region. - -Basemap is geared toward the needs of earth scientists, particularly -oceanographers and meteorologists. Jeff Whitaker originally wrote Basemap -to help in his research (climate and weather forecasting), since at the time -`CDAT `_ was -the only other tool in python for plotting data on map projections. Over -the years, the capabilities of Basemap have evolved as scientists in other -disciplines (such as biology, geology and geophysics) requested and -contributed new features. diff --git a/packages/basemap/pyproject.toml b/packages/basemap/pyproject.toml index 26e78d87a..a7d900689 100644 --- a/packages/basemap/pyproject.toml +++ b/packages/basemap/pyproject.toml @@ -1,14 +1,9 @@ [build-system] requires = [ - 'setuptools', - 'wheel', - 'numpy == 1.23.3; python_version >= "3.11"', - 'numpy == 1.21.4; python_version == "3.10"', - 'numpy == 1.21.4; sys_platform == "darwin" and (python_version >= "3.7" and python_version <= "3.9")', - 'numpy == 1.16.6; sys_platform != "darwin" and (python_version >= "3.7" and python_version <= "3.9")', - 'numpy == 1.16.6; python_version == "2.7" or (python_version >= "3.4" and python_version <= "3.6")', - 'numpy == 1.11.3; python_version == "2.6" or (python_version >= "3.2" and python_version <= "3.3")', - 'cython >= 0.29, < 3.1; python_version >= "3.3" or python_version < "3.0"', - 'cython >= 0.26, < 0.27; python_version == "3.2"' + 'setuptools >= 67.0, < 76.0', + 'wheel >= 0.40, < 0.46', + 'cython >= 0.29.31, < 3.1', + 'numpy == 2.1.0; python_version == "3.13"', + 'numpy == 2.0.0; python_version <= "3.12"', ] build-backend = "setuptools.build_meta" diff --git a/packages/basemap/requirements-doc.txt b/packages/basemap/requirements-doc.txt index 6b88a848c..e89d7e235 100644 --- a/packages/basemap/requirements-doc.txt +++ b/packages/basemap/requirements-doc.txt @@ -1,5 +1,6 @@ -sphinx >= 5.3, < 6.3; python_version >= "3.6" -furo >= 2022.4.7, < 2023.5.21; python_version >= "3.6" +sphinx >= 7.0, < 8.0 +furo >= 2023.9.10, < 2024.8.7 -netCDF4 >= 1.5.6, < 1.7.0; python_version >= "3.6" -cftime >= 1.4.0, < 1.7.0; python_version >= "3.6" +scipy >= 1.6, < 1.16 +cftime >= 1.4.0, < 1.7.0 +netCDF4 >= 1.5.6, < 1.8.0 diff --git a/packages/basemap/requirements-full.txt b/packages/basemap/requirements-full.txt deleted file mode 100644 index 647257799..000000000 --- a/packages/basemap/requirements-full.txt +++ /dev/null @@ -1,8 +0,0 @@ -pillow >= 3.4.0, < 4.0.0; python_version == "2.6" -pillow >= 6.2.2, < 7.0.0; python_version == "2.7" -pillow >= 3.4.0, < 4.0.0; python_version == "3.2" -pillow >= 4.3.0, < 5.0.0; python_version == "3.3" -pillow >= 5.4.0, < 6.0.0; python_version == "3.4" -pillow >= 7.1.0, < 8.0.0; python_version == "3.5" -pillow >= 8.3.2, < 9.0.0; python_version == "3.6" -pillow >= 9.4.0, < 10.2.0; python_version >= "3.7" diff --git a/packages/basemap/requirements-lint.txt b/packages/basemap/requirements-lint.txt index 5669b9475..a13cd4285 100644 --- a/packages/basemap/requirements-lint.txt +++ b/packages/basemap/requirements-lint.txt @@ -1,17 +1,4 @@ -unittest2; python_version <= "3.9" +flake8 >= 3.9, < 7.2 -flake8 >= 2.6, < 3.0; python_version == "2.6" -flake8 >= 2.6, < 4.0; python_version == "2.7" -flake8 >= 2.6, < 3.0; python_version == "3.2" -flake8 >= 2.6, < 3.0; python_version == "3.3" -flake8 >= 2.6, < 3.9; python_version == "3.4" -flake8 >= 2.6, < 7.1; python_version >= "3.5" - -astroid >= 1.6, < 2.0; python_version == "2.7" -astroid >= 2.4, < 2.5; python_version == "3.5" -astroid >= 2.5, < 2.7; python_version == "3.6" -astroid >= 2.8, < 3.0; python_version >= "3.7" -pylint >= 1.9, < 2.0; python_version == "2.7" -pylint >= 2.6, < 2.7; python_version == "3.5" -pylint >= 2.7, < 2.10; python_version == "3.6" -pylint >= 2.11, < 3.0; python_version >= "3.7" +astroid >= 3.0, < 3.4 +pylint >= 3.0, < 3.4 diff --git a/packages/basemap/requirements-owslib.txt b/packages/basemap/requirements-owslib.txt new file mode 100644 index 000000000..5c7425ee0 --- /dev/null +++ b/packages/basemap/requirements-owslib.txt @@ -0,0 +1 @@ +OWSLib >= 0.28.1, < 0.33 diff --git a/packages/basemap/requirements-pillow.txt b/packages/basemap/requirements-pillow.txt new file mode 100644 index 000000000..89493b01d --- /dev/null +++ b/packages/basemap/requirements-pillow.txt @@ -0,0 +1 @@ +pillow >= 10.3, < 11.2 diff --git a/packages/basemap/requirements-setup.txt b/packages/basemap/requirements-setup.txt index 6f39a1a05..d12bb0661 100644 --- a/packages/basemap/requirements-setup.txt +++ b/packages/basemap/requirements-setup.txt @@ -1,2 +1 @@ -cython >= 0.29, < 3.1; python_version >= "3.3" or python_version < "3.0" -cython >= 0.26, < 0.27; python_version == "3.2" +cython >= 0.29.31, < 3.1 diff --git a/packages/basemap/requirements-test.txt b/packages/basemap/requirements-test.txt index 6b0e3cd96..6a0458527 100644 --- a/packages/basemap/requirements-test.txt +++ b/packages/basemap/requirements-test.txt @@ -1,18 +1,4 @@ -unittest2; python_version <= "3.9" +pytest >= 7.0, < 8.4 -typing >= 3.5, < 3.11; python_version == "3.4" -pytest >= 3.2, < 3.3; python_version == "2.6" -pytest >= 3.2, < 5.0; python_version == "2.7" -pytest >= 2.9, < 3.0; python_version == "3.2" -pytest >= 3.2, < 3.3; python_version == "3.3" -pytest >= 3.2, < 5.0; python_version == "3.4" -pytest >= 3.2, < 6.2; python_version == "3.5" -pytest >= 6.2.5, < 6.3; python_version >= "3.6" - -coverage >= 3.7, < 4.0; python_version == "3.2" -pytest-cov >= 2.5, < 2.6; python_version == "2.6" -pytest-cov >= 2.5, < 3.0; python_version == "2.7" -pytest-cov >= 2.5, < 2.6; python_version == "3.2" -pytest-cov >= 2.5, < 2.6; python_version == "3.3" -pytest-cov >= 2.5, < 2.9; python_version == "3.4" -pytest-cov >= 2.5, < 3.1; python_version >= "3.5" +pytest-cov >= 3.0, < 6.1 +coverage >= 5.0, < 7.7 diff --git a/packages/basemap/requirements.txt b/packages/basemap/requirements.txt index e19d5ebfa..3f20dc53c 100644 --- a/packages/basemap/requirements.txt +++ b/packages/basemap/requirements.txt @@ -1,38 +1,8 @@ -basemap_data >= 1.3.2, < 1.4 +basemap_data >= 1.3.2, < 3.0 +packaging >= 20.5, < 25.0 -numpy >= 1.11, < 1.12; python_version == "2.6" -numpy >= 1.16, < 1.17; python_version == "2.7" -numpy >= 1.11, < 1.12; python_version == "3.2" -numpy >= 1.11, < 1.12; python_version == "3.3" -numpy >= 1.15, < 1.17; python_version == "3.4" -numpy >= 1.16, < 1.19; python_version == "3.5" -numpy >= 1.19, < 1.20; python_version == "3.6" -numpy >= 1.21, < 1.22; python_version == "3.7" -numpy >= 1.21, < 1.26; python_version >= "3.8" +numpy >= 2.0, < 2.3 +matplotlib >= 3.4, < 3.11 -cycler < 0.11; python_version == "3.2" -pyparsing >= 1.5, < 2.4.1; python_version == "2.6" -pyparsing >= 1.5, < 2.3.1; python_version == "3.2" -matplotlib >= 1.5, < 2.0; python_version == "2.6" -matplotlib >= 1.5, < 3.0; python_version == "2.7" -matplotlib >= 1.5, < 2.0; python_version == "3.2" -matplotlib >= 1.5, < 2.0; python_version == "3.3" -matplotlib >= 1.5, < 3.0; python_version == "3.4" -matplotlib >= 1.5, < 3.8; python_version >= "3.5" - -pyproj >= 1.9.3, < 2.1.0; python_version == "2.6" -pyproj >= 1.9.3, < 2.2.0; python_version == "2.7" -pyproj >= 1.9.3, < 1.9.6; python_version == "3.2" -pyproj >= 1.9.3, < 2.1.0; python_version == "3.3" -pyproj >= 1.9.3, < 2.1.0; python_version == "3.4" -pyproj >= 1.9.3, < 3.7.0; python_version >= "3.5" - -pyshp >= 1.2, < 2.0; python_version == "2.6" -pyshp >= 1.2, < 2.4; python_version >= "2.7" - -packaging >= 16.0, < 17.0; python_version == "2.6" -packaging >= 16.0, < 21.0; python_version == "2.7" -packaging >= 16.0, < 17.0; python_version == "3.2" -packaging >= 16.0, < 17.0; python_version == "3.3" -packaging >= 16.0, < 21.0; python_version == "3.4" -packaging >= 16.0, < 24.0; python_version >= "3.5" +pyproj >= 3.0, < 3.8 +pyshp >= 2.0, < 2.4 diff --git a/packages/basemap/setup.cfg b/packages/basemap/setup.cfg index 6661e4249..643dee05f 100644 --- a/packages/basemap/setup.cfg +++ b/packages/basemap/setup.cfg @@ -22,7 +22,6 @@ ignore = [tool:pytest] filterwarnings = error - ignore::DeprecationWarning:unittest2.compatibility: [coverage:paths] source = diff --git a/packages/basemap/setup.py b/packages/basemap/setup.py index a7ab1eeac..8927ac115 100644 --- a/packages/basemap/setup.py +++ b/packages/basemap/setup.py @@ -10,17 +10,10 @@ import glob import warnings from setuptools import setup -from setuptools import find_packages +from setuptools import find_namespace_packages from setuptools.command.sdist import sdist -from setuptools.dist import Distribution from setuptools.extension import Extension -try: - import Cython - cython_major_version = int(Cython.__version__.split(".")[0]) -except ImportError: - cython_major_version = 0 - def get_content(name, splitlines=False): """Return the file contents with project root as root folder.""" @@ -84,7 +77,7 @@ def get_geos_install_prefix(): return None -class basemap_sdist(sdist): +class basemap_sdist(sdist): # pylint: disable=invalid-name """Custom `sdist` so that it will not pack DLLs on Windows if present.""" def run(self): @@ -117,8 +110,8 @@ def run(self): import numpy include_dirs.append(numpy.get_include()) except ImportError as err: - build_cmds = ("bdist_wheel", "build", "install") - if any(cmd in sys.argv[1:] for cmd in build_cmds): + cmds = ("bdist_wheel", "build", "install") + if any(cmd in sys.argv[1:] for cmd in cmds): warnings.warn("unable to locate NumPy headers", RuntimeWarning) # Define GEOS include, library and runtime dirs. @@ -163,28 +156,7 @@ def run(self): for ext in ext_modules: ext.cython_directives = [ ("language_level", str(sys.version_info[0])), - ("legacy_implicit_noexcept", True), - ][:1 + int(cython_major_version >= 3)] - -# Define all the different requirements. -setup_requires = get_content("requirements-setup.txt", splitlines=True) -install_requires = get_content("requirements.txt", splitlines=True) -if sys.version_info[:2] == (3, 2): - # Hack for Python 3.2 because pip < 8 cannot handle version markers. - marker1 = '; python_version == "3.2"' - marker2 = '; python_version >= "2.7"' - setup_requires = [ - item.replace(marker1, "").replace(marker2, "") for item in setup_requires - if item.endswith(marker1) or item.endswith(marker2) - or "python_version" not in item] - install_requires = [ - item.replace(marker1, "").replace(marker2, "") for item in install_requires - if item.endswith(marker1) or item.endswith(marker2) - or "python_version" not in item] -else: - marker1 = '; python_version == "3.2"' - setup_requires = [item for item in setup_requires if not item.endswith(marker1)] - install_requires = [item for item in install_requires if not item.endswith(marker1)] + ] setup(**{ "name": @@ -215,7 +187,6 @@ def run(self): "Intended Audience :: Science/Research", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", - "Programming Language :: Python :: 2", "Programming Language :: Python :: 3", "Topic :: Scientific/Engineering :: Visualization", "Topic :: Software Development :: Libraries :: Python Modules", @@ -225,28 +196,23 @@ def run(self): "maps", "plots", ], - "namespace_packages": [ - "mpl_toolkits", - ], "package_dir": {"": "src"}, "packages": - find_packages(where="src"), + find_namespace_packages(where="src"), "ext_modules": ext_modules, "data_files": data_files, "python_requires": ", ".join([ - ">=2.6", - "!=3.0.*", - "!=3.1.*", - "<3.12", + ">=3.9", + "<3.14", ]), "setup_requires": - setup_requires, + get_content("requirements-setup.txt", splitlines=True), "install_requires": - install_requires, + get_content("requirements.txt", splitlines=True), "extras_require": { "doc": get_content("requirements-doc.txt", splitlines=True), @@ -254,8 +220,10 @@ def run(self): get_content("requirements-lint.txt", splitlines=True), "test": get_content("requirements-test.txt", splitlines=True), - "full": - get_content("requirements-full.txt", splitlines=True), + "owslib": + get_content("requirements-owslib.txt", splitlines=True), + "pillow": + get_content("requirements-pillow.txt", splitlines=True), }, "cmdclass": { "sdist": basemap_sdist, diff --git a/packages/basemap/src/_geoslib.pyx b/packages/basemap/src/_geoslib.pyx index e078b4f30..1298e6e91 100644 --- a/packages/basemap/src/_geoslib.pyx +++ b/packages/basemap/src/_geoslib.pyx @@ -1,42 +1,42 @@ import sys import numpy +cimport numpy as cnp -__version__ = "0.3" +__version__ = "2.0.0-dev" -# need some python C API functions for strings. + +# Need some Python C-API functions for strings. cdef extern from "Python.h": object PyBytes_FromString(char *) -# taken from numpy.pxi in numpy 1.0rc2. + +# Taken from `numpy.pxi` in numpy 1.0rc2. cdef extern from "numpy/arrayobject.h": - ctypedef int npy_intp + ctypedef int npy_intp ctypedef extern class numpy.ndarray [object PyArrayObject]: cdef char *data cdef int nd cdef npy_intp *dimensions cdef npy_intp *strides cdef object base -# cdef dtype descr cdef int flags npy_intp PyArray_SIZE(ndarray arr) npy_intp PyArray_ISCONTIGUOUS(ndarray arr) - void import_array() -# Initialize numpy -import_array() -# GENERAL NOTES: -# -# - Remember to call initGEOS() before any use of this library's -# functions, and call finishGEOS() when done. -# -# - Currently you have to explicitly GEOSGeom_destroy() all -# GEOSGeom objects to avoid memory leaks, and to free() -# all returned char * (unless const). This might change -# before first release to ensure greater API stability. +# Initialize numpy. +cnp.import_array() + +# GENERAL NOTES: +# - Remember to call initGEOS() before any use of this library's +# functions, and call finishGEOS() when done. +# - Currently you have to explicitly GEOSGeom_destroy() all +# GEOSGeom objects to avoid memory leaks, and to free() +# all returned char * (unless const). This might change +# before first release to ensure greater API stability. cdef extern from "geos_c.h": -# Supported geometry type IDs + # Supported geometry type IDs. cdef enum: GEOS_POINT GEOS_LINESTRING @@ -47,71 +47,72 @@ cdef extern from "geos_c.h": GEOS_MULTIPOLYGON GEOS_GEOMETRYCOLLECTION GEOS_VERSION_MAJOR - ctypedef struct GEOSGeom: + ctypedef struct GEOSGeometry: pass - ctypedef struct GEOSCoordSeq: + ctypedef struct GEOSCoordSequence: pass # Cython 3: Next ctypedef needs "noexcept" declaration unless # the compiler directive "legacy_implicit_noexcept" is used # ("noexcept" syntax supported since Cython 0.29.31). - ctypedef void (*GEOSMessageHandler)(char *fmt, char *list) + ctypedef void (*GEOSMessageHandler)(const char *fmt, ...) char *GEOSversion() void initGEOS(GEOSMessageHandler notice_function, GEOSMessageHandler error_function) void finishGEOS() - GEOSCoordSeq *GEOSCoordSeq_create(unsigned int size, unsigned int dims) - void GEOSCoordSeq_destroy(GEOSCoordSeq* s) - int GEOSCoordSeq_setX(GEOSCoordSeq* s,unsigned int idx, double val) - int GEOSCoordSeq_setY(GEOSCoordSeq* s,unsigned int idx, double val) - int GEOSCoordSeq_getX(GEOSCoordSeq* s, unsigned int idx, double *val) - int GEOSCoordSeq_getY(GEOSCoordSeq* s, unsigned int idx, double *val) - GEOSGeom *GEOSUnion(GEOSGeom* g1, GEOSGeom* g2) - GEOSGeom *GEOSUnaryUnion(GEOSGeom* g1) - GEOSGeom *GEOSEnvelope(GEOSGeom* g1) - GEOSGeom *GEOSConvexHull(GEOSGeom* g1) - GEOSGeom *GEOSGeom_createPoint(GEOSCoordSeq* s) - GEOSGeom *GEOSGeom_createLineString(GEOSCoordSeq* s) - GEOSGeom *GEOSGeom_createPolygon(GEOSGeom* shell, GEOSGeom** holes, unsigned int nholes) - GEOSGeom *GEOSGeom_createLinearRing(GEOSCoordSeq* s) - void GEOSGeom_destroy(GEOSGeom* g) -# Topology operations - return NULL on exception. - GEOSGeom *GEOSIntersection(GEOSGeom* g1, GEOSGeom* g2) - GEOSGeom *GEOSSimplify(GEOSGeom* g1, double tolerance) - GEOSGeom *GEOSBuffer(GEOSGeom* g1, double width, int quadsegs) - GEOSGeom *GEOSTopologyPreserveSimplify(GEOSGeom* g1, double tolerance) -# Binary/Unary predicate - return 2 on exception, 1 on true, 0 on false - char GEOSIntersects(GEOSGeom* g1, GEOSGeom* g2) - char GEOSWithin(GEOSGeom* g1, GEOSGeom* g2) - char GEOSContains(GEOSGeom* g1, GEOSGeom* g2) - char GEOSisEmpty(GEOSGeom* g1) - char GEOSisValid(GEOSGeom* g1) - char GEOSisSimple(GEOSGeom* g1) - char GEOSisRing(GEOSGeom* g1) -# Geometry info - char *GEOSGeomType(GEOSGeom* g1) - int GEOSGeomTypeId(GEOSGeom* g1) -# Functions: Return 0 on exception, 1 otherwise - int GEOSArea(GEOSGeom* g1, double *area) - int GEOSLength(GEOSGeom* g1, double *length) -# returns -1 on error and 1 for non-multi geoms - int GEOSGetNumGeometries(GEOSGeom* g1) -# Return NULL on exception, Geometry must be a Collection. -# Returned object is a pointer to internal storage: -# it must NOT be destroyed directly. - GEOSGeom *GEOSGetGeometryN(GEOSGeom* g, int n) - int GEOSGetNumInteriorRings(GEOSGeom* g1) -# Return NULL on exception, Geometry must be a Polygon. -# Returned object is a pointer to internal storage: -# it must NOT be destroyed directly. - GEOSGeom *GEOSGetExteriorRing(GEOSGeom* g) -# Return NULL on exception. -# Geometry must be a LineString, LinearRing or Point. - GEOSCoordSeq *GEOSGeom_getCoordSeq(GEOSGeom* g) - int GEOSCoordSeq_getSize(GEOSCoordSeq *s, unsigned int *size) + GEOSCoordSequence *GEOSCoordSeq_create(unsigned int size, unsigned int dims) + void GEOSCoordSeq_destroy(GEOSCoordSequence* s) + int GEOSCoordSeq_setX(GEOSCoordSequence* s, unsigned int idx, double val) + int GEOSCoordSeq_setY(GEOSCoordSequence* s, unsigned int idx, double val) + int GEOSCoordSeq_getX(GEOSCoordSequence* s, unsigned int idx, double *val) + int GEOSCoordSeq_getY(GEOSCoordSequence* s, unsigned int idx, double *val) + GEOSGeometry *GEOSUnion(GEOSGeometry* g1, GEOSGeometry* g2) + GEOSGeometry *GEOSUnaryUnion(GEOSGeometry* g1) + GEOSGeometry *GEOSEnvelope(GEOSGeometry* g1) + GEOSGeometry *GEOSConvexHull(GEOSGeometry* g1) + GEOSGeometry *GEOSGeom_createPoint(GEOSCoordSequence* s) + GEOSGeometry *GEOSGeom_createLineString(GEOSCoordSequence* s) + GEOSGeometry *GEOSGeom_createPolygon(GEOSGeometry* shell, GEOSGeometry** holes, unsigned int nholes) + GEOSGeometry *GEOSGeom_createLinearRing(GEOSCoordSequence* s) + void GEOSGeom_destroy(GEOSGeometry* g) + # Topology operations: Return NULL on exception. + GEOSGeometry *GEOSIntersection(GEOSGeometry* g1, GEOSGeometry* g2) + GEOSGeometry *GEOSSimplify(GEOSGeometry* g1, double tolerance) + GEOSGeometry *GEOSBuffer(GEOSGeometry* g1, double width, int quadsegs) + GEOSGeometry *GEOSTopologyPreserveSimplify(GEOSGeometry* g1, double tolerance) + # Binary/Unary predicate: Return 2 on exception, 1 on true, 0 on false. + char GEOSIntersects(GEOSGeometry* g1, GEOSGeometry* g2) + char GEOSWithin(GEOSGeometry* g1, GEOSGeometry* g2) + char GEOSContains(GEOSGeometry* g1, GEOSGeometry* g2) + char GEOSisEmpty(GEOSGeometry* g1) + char GEOSisValid(GEOSGeometry* g1) + char GEOSisSimple(GEOSGeometry* g1) + char GEOSisRing(GEOSGeometry* g1) + # Geometry info. + char *GEOSGeomType(GEOSGeometry* g1) + int GEOSGeomTypeId(GEOSGeometry* g1) + # Functions: Return 0 on exception, 1 otherwise. + int GEOSArea(GEOSGeometry* g1, double *area) + int GEOSLength(GEOSGeometry* g1, double *length) + # Returns -1 on error and 1 for non-multi geoms. + int GEOSGetNumGeometries(GEOSGeometry* g1) + # Return NULL on exception, Geometry must be a Collection. + # Returned object is a pointer to internal storage: + # it must NOT be destroyed directly. + GEOSGeometry *GEOSGetGeometryN(GEOSGeometry* g, int n) + int GEOSGetNumInteriorRings(GEOSGeometry* g1) + # Return NULL on exception, Geometry must be a Polygon. + # Returned object is a pointer to internal storage: + # it must NOT be destroyed directly. + GEOSGeometry *GEOSGetExteriorRing(GEOSGeometry* g) + # Return NULL on exception. + # Geometry must be a LineString, LinearRing or Point. + GEOSCoordSequence *GEOSGeom_getCoordSeq(const GEOSGeometry* g) + int GEOSCoordSeq_getSize(const GEOSCoordSequence *s, unsigned int *size) + # Cython 3: Next cdef needs "noexcept" declaration unless # the compiler directive "legacy_implicit_noexcept" is used # ("noexcept" syntax supported since Cython 0.29.31). -cdef void notice_h(char *fmt, char*msg): +cdef void notice_h(const char *fmt, ...) noexcept: pass #format = PyBytes_FromString(fmt) #message = PyBytes_FromString(msg) @@ -121,10 +122,13 @@ cdef void notice_h(char *fmt, char*msg): # warn_msg = format #sys.stdout.write('GEOS_NOTICE: %s\n' % warn_msg) + # Cython 3: Next cdef needs "noexcept" declaration unless # the compiler directive "legacy_implicit_noexcept" is used # ("noexcept" syntax supported since Cython 0.29.31). -cdef void error_h(char *fmt, char*msg): +# FIXME: The type should be: error_h(const char *fmt, ...), but +# Cython does not currently support varargs functions. +cdef void error_h(const char *fmt, char*msg): format = PyBytes_FromString(fmt) message = PyBytes_FromString(msg) try: @@ -133,19 +137,23 @@ cdef void error_h(char *fmt, char*msg): warn_msg = format sys.stderr.write('GEOS_ERROR: %s\n' % warn_msg) -# check library version + +# Check library version. cdef geos_version(): return PyBytes_FromString(GEOSversion()) -__geos_version__ = geos_version() # module variable. + +# Module variables. +__geos_version__ = geos_version() __geos_major_version__ = GEOS_VERSION_MAJOR -#if __geos_version__ != "2.2.3-CAPI-1.1.1": -# raise ValueError('version 2.2.3 of the geos library is required') -# intialize GEOS (parameters are notice and error function callbacks). -initGEOS(notice_h, error_h) + +# Initialize GEOS (parameters are notice and error function callbacks). +initGEOS(notice_h, error_h) + cdef class BaseGeometry: - cdef GEOSGeom *_geom + + cdef GEOSGeometry *_geom cdef unsigned int _npts cdef public object boundary @@ -161,22 +169,22 @@ cdef class BaseGeometry: return PyBytes_FromString(GEOSGeomType(self._geom)) def within(self, BaseGeometry geom): - cdef GEOSGeom *g1 - cdef GEOSGeom *g2 + cdef GEOSGeometry *g1 + cdef GEOSGeometry *g2 cdef char answer g1 = self._geom g2 = geom._geom - answer = GEOSWithin(g1, g2) + answer = GEOSWithin(g1, g2) if answer: return True else: return False def union(self, BaseGeometry geom): - cdef GEOSGeom *g1 - cdef GEOSGeom *g2 - cdef GEOSGeom *g3 - cdef GEOSGeom *gout + cdef GEOSGeometry *g1 + cdef GEOSGeometry *g2 + cdef GEOSGeometry *g3 + cdef const GEOSGeometry *gout cdef int numgeoms, i, typeid g1 = self._geom g2 = geom._geom @@ -188,7 +196,7 @@ cdef class BaseGeometry: elif typeid == GEOS_LINESTRING: b = _get_coords(g3) p = LineString(b) - # for multi-geom structures, just return first one. + # For multi-geom structures, just return first one. elif typeid == GEOS_MULTIPOLYGON: numgeoms = GEOSGetNumGeometries(g3) gout = GEOSGetGeometryN(g3, 0) @@ -206,14 +214,14 @@ cdef class BaseGeometry: return p def simplify(self, tol): - cdef GEOSGeom *g1 - cdef GEOSGeom *g3 - cdef GEOSGeom *gout + cdef GEOSGeometry *g1 + cdef GEOSGeometry *g3 + cdef const GEOSGeometry *gout cdef double tolerance cdef int numgeoms, i, typeid g1 = self._geom tolerance = tol - g3 = GEOSSimplify(g1,tolerance) + g3 = GEOSSimplify(g1, tolerance) typeid = GEOSGeomTypeId(g3) if typeid == GEOS_POLYGON: b = _get_coords(g3) @@ -221,7 +229,7 @@ cdef class BaseGeometry: elif typeid == GEOS_LINESTRING: b = _get_coords(g3) p = LineString(b) - # for multi-geom structures, just return first one. + # For multi-geom structures, just return first one. elif typeid == GEOS_MULTIPOLYGON: numgeoms = GEOSGetNumGeometries(g3) gout = GEOSGetGeometryN(g3, 0) @@ -239,9 +247,9 @@ cdef class BaseGeometry: return p def fix(self): - cdef GEOSGeom *g1 - cdef GEOSGeom *g3 - cdef GEOSGeom *gout + cdef GEOSGeometry *g1 + cdef GEOSGeometry *g3 + cdef const GEOSGeometry *gout cdef int numgeoms, i, typeid g1 = self._geom g3 = GEOSBuffer(g1, 0., 0) @@ -252,7 +260,7 @@ cdef class BaseGeometry: elif typeid == GEOS_LINESTRING: b = _get_coords(g3) p = LineString(b) - # for multi-geom structures, just return first one. + # For multi-geom structures, just return first one. elif typeid == GEOS_MULTIPOLYGON: numgeoms = GEOSGetNumGeometries(g3) gout = GEOSGetGeometryN(g3, 0) @@ -270,27 +278,27 @@ cdef class BaseGeometry: return p def intersects(self, BaseGeometry geom): - cdef GEOSGeom *g1 - cdef GEOSGeom *g2 + cdef GEOSGeometry *g1 + cdef GEOSGeometry *g2 cdef char answer g1 = self._geom g2 = geom._geom - answer = GEOSIntersects(g1, g2) + answer = GEOSIntersects(g1, g2) if answer: return True else: return False def intersection(self, BaseGeometry geom): - cdef GEOSGeom *g1 - cdef GEOSGeom *g2 - cdef GEOSGeom *g3 - cdef GEOSGeom *gout + cdef GEOSGeometry *g1 + cdef GEOSGeometry *g2 + cdef GEOSGeometry *g3 + cdef const GEOSGeometry *gout cdef char answer cdef int numgeoms, i, typeid g1 = self._geom g2 = geom._geom - g3 = GEOSIntersection(g1, g2) + g3 = GEOSIntersection(g1, g2) typeid = GEOSGeomTypeId(g3) if typeid == GEOS_POLYGON: b = _get_coords(g3) @@ -303,7 +311,7 @@ cdef class BaseGeometry: elif typeid == GEOS_MULTIPOLYGON: numgeoms = GEOSGetNumGeometries(g3) pout = [] - for i from 0 <= i < numgeoms: + for i in range(numgeoms): gout = GEOSGetGeometryN(g3, i) b = _get_coords(gout) p = Polygon(b) @@ -311,11 +319,35 @@ cdef class BaseGeometry: elif typeid == GEOS_MULTILINESTRING: numgeoms = GEOSGetNumGeometries(g3) pout = [] - for i from 0 <= i < numgeoms: + for i in range(numgeoms): gout = GEOSGetGeometryN(g3, i) b = _get_coords(gout) p = LineString(b) pout.append(p) + elif typeid == GEOS_GEOMETRYCOLLECTION: + numgeoms = GEOSGetNumGeometries(g3) + pout = [] + for i in range(numgeoms): + gout = GEOSGetGeometryN(g3, i) + typeid = GEOSGeomTypeId(gout) + if typeid == GEOS_POLYGON: + b = _get_coords(gout) + p = Polygon(b) + pout.append(p) + elif typeid == GEOS_LINESTRING: + b = _get_coords(gout) + p = LineString(b) + pout.append(p) + else: + # More cases might need to be handled here: + # - GEOS_MULTILINESTRING + # - GEOS_MULTIPOLYGON + # - GEOS_GEOMETRYCOLLECTION + # The underlying problem is the need of a generic + # converter from GEOSGeom pointers to `_geoslib` + # objects, since postprocessing `GeometryCollections` + # might need recursiveness. + pass else: #type = PyBytes_FromString(GEOSGeomType(g3)) #raise NotImplementedError("intersections of type '%s' not yet implemented" % (type)) @@ -333,43 +365,40 @@ cdef class BaseGeometry: def __reduce__(self): """special method that allows geos instance to be pickled""" - return (self.__class__,(self.boundary,)) - + return (self.__class__, (self.boundary,)) + + cdef class Polygon(BaseGeometry): def __init__(self, ndarray b): cdef unsigned int M, m, i cdef double dx, dy cdef double *bbuffer - cdef GEOSCoordSeq *cs - cdef GEOSGeom *lr - - + cdef GEOSCoordSequence *cs + cdef GEOSGeometry *lr - # make sure data is contiguous. - # if not, make a local copy. + # Make sure data is contiguous. If not, make a local copy. if not PyArray_ISCONTIGUOUS(b): b = b.copy() m = b.shape[0] - + # Add closing coordinates to sequence? - if m > 0 and (b[-1,0] != b[0,0] or b[-1,1] != b[0,1]): + if m > 0 and (b[-1, 0] != b[0, 0] or b[-1, 1] != b[0, 1]): M = m + 1 else: M = m self._npts = M - # Create a coordinate sequence + # Create a coordinate sequence. cs = GEOSCoordSeq_create(M, 2) - # add to coordinate sequence + # Add to coordinate sequence. bbuffer = b.data - for i from 0 <= i < m: - dx = bbuffer[2*i] - dy = bbuffer[2*i+1] - # Because of a bug in the GEOS C API, - # always set X before Y + for i in range(m): + dx = bbuffer[2 * i] + dy = bbuffer[2 * i + 1] + # Because of a bug in the GEOS C API, always set X before Y. GEOSCoordSeq_setX(cs, i, dx) GEOSCoordSeq_setY(cs, i, dy) @@ -377,71 +406,78 @@ cdef class Polygon(BaseGeometry): if M > m: dx = bbuffer[0] dy = bbuffer[1] - GEOSCoordSeq_setX(cs, M-1, dx) - GEOSCoordSeq_setY(cs, M-1, dy) + GEOSCoordSeq_setX(cs, M - 1, dx) + GEOSCoordSeq_setY(cs, M - 1, dy) - # create LinearRing + # Create LinearRing. lr = GEOSGeom_createLinearRing(cs) - # create Polygon from LinearRing (assuming no holes) - self._geom = GEOSGeom_createPolygon(lr,NULL,0) + # Create Polygon from LinearRing (assuming no holes). + self._geom = GEOSGeom_createPolygon(lr, NULL, 0) self.boundary = b - def area(self): cdef double area GEOSArea(self._geom, &area) return area + cdef class LineString(BaseGeometry): + def __init__(self, ndarray b): + cdef double dx, dy - cdef GEOSCoordSeq *cs + cdef GEOSCoordSequence *cs cdef int i, M cdef double *bbuffer - # make sure data is contiguous. - # if not, make a local copy. + # Make sure data is contiguous. If not, make a local copy. if not PyArray_ISCONTIGUOUS(b): b = b.copy() M = b.shape[0] self._npts = M - # Create a coordinate sequence + # Create a coordinate sequence. cs = GEOSCoordSeq_create(M, 2) - # add to coordinate sequence + # Add to coordinate sequence. bbuffer = b.data - for i from 0 <= i < M: - dx = bbuffer[2*i] - dy = bbuffer[2*i+1] - # Because of a bug in the GEOS C API, - # always set X before Y + for i in range(M): + dx = bbuffer[2 * i] + dy = bbuffer[2 * i + 1] + # Because of a bug in the GEOS C API, always set X before Y. GEOSCoordSeq_setX(cs, i, dx) GEOSCoordSeq_setY(cs, i, dy) - # create LineString + # Create LineString. self._geom = GEOSGeom_createLineString(cs) self.boundary = b + cdef class Point(BaseGeometry): - cdef public x,y + + cdef public x, y def __init__(self, b): + cdef double dx, dy - cdef GEOSCoordSeq *cs - # Create a coordinate sequence + cdef GEOSCoordSequence *cs + + # Create a coordinate sequence. cs = GEOSCoordSeq_create(1, 2) - dx = b[0]; dy = b[1] + dx = b[0] + dy = b[1] GEOSCoordSeq_setX(cs, 0, dx) GEOSCoordSeq_setY(cs, 0, dy) self._geom = GEOSGeom_createPoint(cs) self._npts = 1 self.boundary = b -cdef _get_coords(GEOSGeom *geom): - cdef GEOSCoordSeq *cs - cdef GEOSGeom *lr + +cdef _get_coords(const GEOSGeometry *geom): + + cdef const GEOSCoordSequence *cs + cdef const GEOSGeometry *lr cdef unsigned int i, M cdef double dx, dy cdef ndarray b @@ -452,11 +488,11 @@ cdef _get_coords(GEOSGeom *geom): else: cs = GEOSGeom_getCoordSeq(geom) GEOSCoordSeq_getSize(cs, &M) - b = numpy.empty((M,2), numpy.float64) + b = numpy.empty((M, 2), numpy.float64) bbuffer = b.data - for i from 0 <= i < M: + for i in range(M): GEOSCoordSeq_getX(cs, i, &dx) GEOSCoordSeq_getY(cs, i, &dy) - bbuffer[2*i] = dx - bbuffer[2*i+1] = dy + bbuffer[2 * i] = dx + bbuffer[2 * i + 1] = dy return b diff --git a/packages/basemap/src/mpl_toolkits/__init__.py b/packages/basemap/src/mpl_toolkits/__init__.py deleted file mode 100644 index b5cd40f18..000000000 --- a/packages/basemap/src/mpl_toolkits/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from __future__ import (absolute_import, division, print_function) - -try: - __import__('pkg_resources').declare_namespace(__name__) -except ImportError: - pass # must not have setuptools diff --git a/packages/basemap/src/mpl_toolkits/basemap/__init__.py b/packages/basemap/src/mpl_toolkits/basemap/__init__.py index 5714864f2..3f61c2c4f 100644 --- a/packages/basemap/src/mpl_toolkits/basemap/__init__.py +++ b/packages/basemap/src/mpl_toolkits/basemap/__init__.py @@ -31,6 +31,7 @@ import numpy.ma as ma import matplotlib as mpl +from matplotlib.artist import Artist from matplotlib.collections import LineCollection from matplotlib.collections import PolyCollection from matplotlib.image import imread @@ -47,7 +48,7 @@ from . proj import Proj -__version__ = "1.4.0-dev" +__version__ = "2.0.0-dev" # basemap data files now installed in lib/matplotlib/toolkits/basemap/data # check to see if environment variable BASEMAPDATA set to a directory, @@ -2070,9 +2071,9 @@ def readshapefile(self,shapefile,name,drawbounds=True,zorder=None, .. tabularcolumns:: |l|L| - ============== ==================================================== + ================ ==================================================== Argument Description - ============== ==================================================== + ================ ==================================================== shapefile path to shapefile components. Example: shapefile='/home/jeff/esri/world_borders' assumes that world_borders.shp, world_borders.shx and @@ -2090,7 +2091,7 @@ def readshapefile(self,shapefile,name,drawbounds=True,zorder=None, shapes are split out into separate polygons, and additional keys 'RINGNUM' and 'SHAPENUM' are added to the shape attribute dictionary. - ============== ==================================================== + ================ ==================================================== The following optional keyword arguments are only relevant for Polyline and Polygon shape types, for Point and MultiPoint shapes they are @@ -2098,9 +2099,9 @@ def readshapefile(self,shapefile,name,drawbounds=True,zorder=None, .. tabularcolumns:: |l|L| - ============== ==================================================== + ================ ===================================================== Keyword Description - ============== ==================================================== + ================ ===================================================== drawbounds draw boundaries of shapes (default True). zorder shape boundary zorder (if not specified, default for mathplotlib.lines.LineCollection @@ -2114,7 +2115,7 @@ def readshapefile(self,shapefile,name,drawbounds=True,zorder=None, (default utf-8) encoding_errors encoding error handling (default strict), other possible values: ignore, replace and backslashreplace - ============== ==================================================== + ================ ===================================================== A tuple (num_shapes, type, min, max) containing shape file info is returned. @@ -3592,7 +3593,11 @@ def contour(self,x,y,data,*args,**kwargs): # set axes limits to fit map region. self.set_axes_limits(ax=ax) # clip to map limbs - CS.collections,c = self._cliplimb(ax,CS.collections) + if isinstance(CS, Artist): + # Since MPL 3.8, `QuadContourSet` objects are `Artist` objects too. + CS, c = self._cliplimb(ax, CS) + else: + CS.collections, c = self._cliplimb(ax, CS.collections) return CS @_transform @@ -3688,7 +3693,11 @@ def contourf(self,x,y,data,*args,**kwargs): # set axes limits to fit map region. self.set_axes_limits(ax=ax) # clip to map limbs - CS.collections,c = self._cliplimb(ax,CS.collections) + if isinstance(CS, Artist): + # Since MPL 3.8, `QuadContourSet` objects are `Artist` objects too. + CS, c = self._cliplimb(ax, CS) + else: + CS.collections, c = self._cliplimb(ax, CS.collections) return CS @_transformuv @@ -4248,45 +4257,56 @@ def pil_to_array(*args, **kwargs): im,c = self._cliplimb(ax,im) return im - def arcgisimage(self,server='http://server.arcgisonline.com/ArcGIS',\ - service='World_Imagery',xpixels=400,ypixels=None,\ - dpi=96,cachedir=None,verbose=False,**kwargs): - """ - Retrieve an image using the ArcGIS Server REST API and display it on - the map. In order to use this method, the Basemap instance must be - created using the ``epsg`` keyword to define the map projection, unless - the ``cyl`` projection is used (in which case the epsg code 4326 is - assumed). + def arcgisimage(self, server="http://server.arcgisonline.com/ArcGIS", + service="World_Imagery", xpixels=400, ypixels=None, + dpi=96, cachedir=None, verbose=False, **kwargs): + r"""Display background image using ArcGIS Server REST API. - .. tabularcolumns:: |l|L| + In order to use this method, the :class:`Basemap` instance + must be created using the ``epsg`` keyword to define the + map projection, unless the "cyl" projection is used (in + which case the EPSG code 4326 is assumed). - ============== ==================================================== - Keywords Description - ============== ==================================================== - server web map server URL (default - http://server.arcgisonline.com/ArcGIS). - service service (image type) hosted on server (default - 'World_Imagery', which is NASA 'Blue Marble' - image). - xpixels requested number of image pixels in x-direction - (default 400). - ypixels requested number of image pixels in y-direction. - Default (None) is to infer the number from - from xpixels and the aspect ratio of the - map projection region. - dpi The device resolution of the exported image (dots per - inch, default 96). - cachedir An optional directory to use as cache folder for the retrieved images. - verbose if True, print URL used to retrieve image (default - False). - ============== ==================================================== + Parameters + ---------- - Extra keyword ``ax`` can be used to override the default axis instance. + server : str, optional + base URL of the web map server - returns a matplotlib.image.AxesImage instance. + service : str, optional + service (image type) hosted by the server + + xpixels : int, optional + requested number of image pixels in the `x`-direction + + ypixels : int, optional + requested number of image pixels in the `y`-direction; + if not given, it is inferred from ``xpixels`` and the + aspect ratio of the map projection region + + dpi : int, optional + device resolution of the exported image + + cachedir : str, optional + if given, directory to use as cache folder for the images + retrieved from the server + + verbose : bool, optional + if True, print debugging information + + \**kwargs : dict, optional + keyword-only arguments; currently, only ``ax`` is supported + to override the default :class:`matplotlib.axes.Axes` + instance + + Returns + ------- + + aximg : matplotlib.image.AxesImage + image axes instance """ - # fix PIL import on some versions of OSX and scipy + # Fix PIL import on some versions of OSX and scipy. try: from PIL import Image except ImportError: @@ -4296,70 +4316,71 @@ def arcgisimage(self,server='http://server.arcgisonline.com/ArcGIS',\ raise ImportError("arcgisimage method requires PIL " "(http://pillow.readthedocs.io)") - if not hasattr(self,'epsg'): + if not hasattr(self, "epsg"): raise ValueError("the Basemap instance must be created using " "an EPSG code (http://spatialreference.org) " "in order to use the wmsmap method") - ax = kwargs.pop('ax', None) or self._check_ax() - # find the x,y values at the corner points. + + ax = kwargs.pop("ax", None) or self._check_ax() + + # Find the `(x, y)` values at the corner points. with warnings.catch_warnings(): warnings.simplefilter("ignore", category=FutureWarning) p = pyproj.Proj(init="epsg:%s" % self.epsg, preserve_units=True) - xmin,ymin = p(self.llcrnrlon,self.llcrnrlat) - xmax,ymax = p(self.urcrnrlon,self.urcrnrlat) + xmin, ymin = p(self.llcrnrlon, self.llcrnrlat) + xmax, ymax = p(self.urcrnrlon, self.urcrnrlat) if self.projection in _cylproj: - Dateline =\ - _geoslib.Point(self(180.,0.5*(self.llcrnrlat+self.urcrnrlat))) - hasDateline = Dateline.within(self._boundarypolyxy) - if hasDateline: + dateline = _geoslib.Point(self(180., 0.5 * (self.llcrnrlat + self.urcrnrlat))) + if dateline.within(self._boundarypolyxy): raise ValueError("arcgisimage cannot handle images that cross " "the dateline for cylindrical projections") - # ypixels not given, find by scaling xpixels by the map aspect ratio. + + # If ypixels is not given, compute it with xpixels and aspect ratio. if ypixels is None: - ypixels = int(self.aspect*xpixels) - # construct a URL using the ArcGIS Server REST API. - basemap_url = \ -"%s/rest/services/%s/MapServer/export?\ -bbox=%s,%s,%s,%s&\ -bboxSR=%s&\ -imageSR=%s&\ -size=%s,%s&\ -dpi=%s&\ -format=png32&\ -transparent=true&\ -f=image" %\ -(server,service,xmin,ymin,xmax,ymax,self.epsg,self.epsg,xpixels,ypixels,dpi) - # print URL? - if verbose: print(basemap_url) - - if cachedir != None: + ypixels = int(self.aspect * xpixels) + + # Construct a URL using the ArcGIS Server REST API. + basemap_url = "".join([ + "%s/rest/services/%s/MapServer/export?", + "bbox=%s,%s,%s,%s&", + "bboxSR=%s&", + "imageSR=%s&", + "size=%s,%s&", + "dpi=%s&", + "format=png32&", + "transparent=true&", + "f=image", + ]) % (server, service, xmin, ymin, xmax, ymax, self.epsg, self.epsg, xpixels, ypixels, dpi) + + # Print URL in verbose mode. + if verbose: # pragma: no cover + print(basemap_url) + + # Try to return fast if cache is enabled. + if cachedir is not None: # Generate a filename for the cached file. - filename = "%s-bbox-%s-%s-%s-%s-bboxsr%s-imagesr%s-size-%s-%s-dpi%s.png" %\ - (service,xmin,ymin,xmax,ymax,self.epsg,self.epsg,xpixels,ypixels,dpi) - - # Check if the cache directory exists, if not create it. - if not os.path.exists(cachedir): - os.makedirs(cachedir) - - # Check if the image is already in the cachedir folder. - cache_path = cachedir + filename - - if os.path.isfile(cache_path) and verbose: - print('Image already in cache') + filename = "%s-bbox-%s-%s-%s-%s-bboxsr%s-imagesr%s-size-%s-%s-dpi%s.png" % \ + (service, xmin, ymin, xmax, ymax, self.epsg, self.epsg, xpixels, ypixels, dpi) + # Return fast if the image is already in the cache. + cache_path = os.path.join(cachedir, filename) + if os.path.isfile(cache_path): + if verbose: # pragma: no cover + print("Image already in cache") img = Image.open(cache_path) - return basemap.imshow(img, ax=ax, origin='upper') + return self.imshow(img, ax=ax, origin="upper") - # Retrieve image from remote server. + # Retrieve image from the remote server. import contextlib conn = urlopen(basemap_url) with contextlib.closing(conn): img = Image.open(conn) # Save to cache if requested. - if cachedir != None: + if cachedir is not None: + # Check if the cache directory exists, if not create it. + if not os.path.exists(cachedir): + os.makedirs(cachedir) img.save(cache_path) - - # Return AxesImage instance. - return self.imshow(img, ax=ax, origin='upper') + return self.imshow(img, ax=ax, origin="upper") def wmsimage(self,server,\ xpixels=400,ypixels=None,\ @@ -4519,20 +4540,21 @@ def drawmapscale(self,lon,lat,lon0,lat0,length,barstyle='simple',\ xc,yc = self(lon,lat) # make sure lon_0 between -180 and 180 lon_0 = ((lon0+360) % 360) - 360 + degchar = b"\xc2\xb0".decode("utf-8") if lat0>0: if lon>0: - lonlatstr = u'%g\N{DEGREE SIGN}N, %g\N{DEGREE SIGN}E' % (lat0,lon_0) + lonlatstr = '%g%sN, %g%sE' % (lat0, degchar, lon_0, degchar) elif lon<0: - lonlatstr = u'%g\N{DEGREE SIGN}N, %g\N{DEGREE SIGN}W' % (lat0,lon_0) + lonlatstr = '%g%sN, %g%sW' % (lat0, degchar, lon_0, degchar) else: - lonlatstr = u'%g\N{DEGREE SIGN}, %g\N{DEGREE SIGN}W' % (lat0,lon_0) + lonlatstr = '%g%s, %g%sW' % (lat0, degchar, lon_0, degchar) else: if lon>0: - lonlatstr = u'%g\N{DEGREE SIGN}S, %g\N{DEGREE SIGN}E' % (lat0,lon_0) + lonlatstr = '%g%sS, %g%sE' % (lat0, degchar, lon_0, degchar) elif lon<0: - lonlatstr = u'%g\N{DEGREE SIGN}S, %g\N{DEGREE SIGN}W' % (lat0,lon_0) + lonlatstr = '%g%sS, %g%sW' % (lat0, degchar, lon_0, degchar) else: - lonlatstr = u'%g\N{DEGREE SIGN}S, %g\N{DEGREE SIGN}' % (lat0,lon_0) + lonlatstr = '%g%sS, %g%s' % (lat0, degchar, lon_0, degchar) # left edge of scale lon1,lat1 = self(x0-length/2,y0,inverse=True) x1,y1 = self(lon1,lat1) @@ -4733,12 +4755,18 @@ def nightshade(self,date,color="k",delta=0.25,alpha=0.5,ax=None,zorder=2): # contour the day-night grid, coloring the night area # with the specified color and transparency. CS = self.contourf(x,y,daynight,1,colors=[color],alpha=alpha,ax=ax) - # set zorder on ContourSet collections show night shading - # is on top. - for c in CS.collections: - c.set_zorder(zorder) - # clip to map limbs - CS.collections,c = self._cliplimb(ax,CS.collections) + if isinstance(CS, Artist): + # Since MPL 3.8, `QuadContourSet` objects are `Artist` objects too. + CS.set_zorder(zorder) + # clip to map limbs + CS, c = self._cliplimb(ax, CS) + else: + # set zorder on ContourSet collections show night shading + # is on top. + for c in CS.collections: + c.set_zorder(zorder) + # clip to map limbs + CS.collections, c = self._cliplimb(ax, CS.collections) return CS def _check_ax(self): @@ -4785,17 +4813,17 @@ def shiftdata(self,lonsin,datain=None,lon_0=None,fix_wrap_around=True): .. tabularcolumns:: |l|L| - ============== ==================================================== + ================ ====================================================== Arguments Description - ============== ==================================================== + ================ ====================================================== lonsin original 1-d or 2-d longitudes. - ============== ==================================================== + ================ ====================================================== .. tabularcolumns:: |l|L| - ============== ==================================================== + ================ ====================================================== Keywords Description - ============== ==================================================== + ================ ====================================================== datain original 1-d or 2-d data. Default None. lon_0 center of map projection region. Defaut None, given by current map projection. @@ -4806,7 +4834,7 @@ def shiftdata(self,lonsin,datain=None,lon_0=None,fix_wrap_around=True): If False do not reindex longitudes and data, but do make sure that longitudes are in the [lon_0-180, lon_0+180] range. - ============== ==================================================== + ================ ====================================================== if datain given, returns ``dataout,lonsout`` (data and longitudes shifted to fit in interval [lon_0-180,lon_0+180]), otherwise just returns longitudes. If @@ -5301,76 +5329,86 @@ def __delitem__(self,key): self[key].remove() super(_dict, self).__delitem__(key) -def _setlonlab(fmt,lon,labelstyle): - # set lon label string (called by Basemap.drawmeridians) - try: # fmt is a function that returns a formatted string + +def _setlonlab(fmt, lon, labelstyle): + """Set longitude label string (called by :meth:`Basemap.drawmeridians`).""" + + try: + # `fmt` is a function that returns a formatted string. lonlab = fmt(lon) - except: # fmt is a format string. - if lon>180: - if mpl.rcParams['text.usetex']: - if labelstyle=='+/-': - lonlabstr = r'${\/-%s\/^{\circ}}$'%fmt + except: + # `fmt` is a format string. + degchar = b"\xc2\xb0".decode("utf-8") + if lon > 180: + if mpl.rcParams["text.usetex"]: + if labelstyle == "+/-": + lonlabstr = r"${\/-%s\/^{\circ}}$" % fmt else: - lonlabstr = r'${%s\/^{\circ}\/W}$'%fmt + lonlabstr = r"${%s\/^{\circ}\/W}$" % fmt else: - if labelstyle=='+/-': - lonlabstr = u'-%s\N{DEGREE SIGN}'%fmt + if labelstyle == "+/-": + lonlabstr = r"-%s%s" % (fmt, degchar) else: - lonlabstr = u'%s\N{DEGREE SIGN}W'%fmt - lonlab = lonlabstr%np.fabs(lon-360) - elif lon<180 and lon != 0: - if mpl.rcParams['text.usetex']: - if labelstyle=='+/-': - lonlabstr = r'${\/+%s\/^{\circ}}$'%fmt + lonlabstr = r"%s%sW" % (fmt, degchar) + lonlab = lonlabstr % np.fabs(lon - 360) + elif lon < 180 and lon != 0: + if mpl.rcParams["text.usetex"]: + if labelstyle == "+/-": + lonlabstr = r"${\/+%s\/^{\circ}}$" % fmt else: - lonlabstr = r'${%s\/^{\circ}\/E}$'%fmt + lonlabstr = r"${%s\/^{\circ}\/E}$" % fmt else: - if labelstyle=='+/-': - lonlabstr = u'+%s\N{DEGREE SIGN}'%fmt + if labelstyle == "+/-": + lonlabstr = r"+%s%s" % (fmt, degchar) else: - lonlabstr = u'%s\N{DEGREE SIGN}E'%fmt - lonlab = lonlabstr%lon + lonlabstr = r"%s%sE" % (fmt, degchar) + lonlab = lonlabstr % lon else: - if mpl.rcParams['text.usetex']: - lonlabstr = r'${%s\/^{\circ}}$'%fmt + if mpl.rcParams["text.usetex"]: + lonlabstr = r"${%s\/^{\circ}}$" % fmt else: - lonlabstr = u'%s\N{DEGREE SIGN}'%fmt - lonlab = lonlabstr%lon + lonlabstr = r"%s%s" % (fmt, degchar) + lonlab = lonlabstr % lon return lonlab -def _setlatlab(fmt,lat,labelstyle): - # set lat label string (called by Basemap.drawparallels) - try: # fmt is a function that returns a formatted string - latlab = fmt(lat) - except: # fmt is a format string. - if lat<0: - if mpl.rcParams['text.usetex']: - if labelstyle=='+/-': - latlabstr = r'${\/-%s\/^{\circ}}$'%fmt + +def _setlatlab(fmt, lat, labelstyle): + """Set latitude label string (called by :meth:`Basemap.drawparallels`).""" + + try: + # `fmt` is a function that returns a formatted string. + latlab = fmt(lat) + except: + # `fmt` is a format string. + degchar = b"\xc2\xb0".decode("utf-8") + if lat < 0: + if mpl.rcParams["text.usetex"]: + if labelstyle == "+/-": + latlabstr = r"${\/-%s\/^{\circ}}$" % fmt else: - latlabstr = r'${%s\/^{\circ}\/S}$'%fmt + latlabstr = r"${%s\/^{\circ}\/S}$" % fmt else: - if labelstyle=='+/-': - latlabstr = u'-%s\N{DEGREE SIGN}'%fmt + if labelstyle == "+/-": + latlabstr = r"-%s%s" % (fmt, degchar) else: - latlabstr = u'%s\N{DEGREE SIGN}S'%fmt - latlab = latlabstr%np.fabs(lat) - elif lat>0: - if mpl.rcParams['text.usetex']: - if labelstyle=='+/-': - latlabstr = r'${\/+%s\/^{\circ}}$'%fmt + latlabstr = r"%s%sS" % (fmt, degchar) + latlab = latlabstr % np.fabs(lat) + elif lat > 0: + if mpl.rcParams["text.usetex"]: + if labelstyle == "+/-": + latlabstr = r"${\/+%s\/^{\circ}}$" % fmt else: - latlabstr = r'${%s\/^{\circ}\/N}$'%fmt + latlabstr = r"${%s\/^{\circ}\/N}$" % fmt else: - if labelstyle=='+/-': - latlabstr = u'+%s\N{DEGREE SIGN}'%fmt + if labelstyle == "+/-": + latlabstr = r"+%s%s" % (fmt, degchar) else: - latlabstr = u'%s\N{DEGREE SIGN}N'%fmt - latlab = latlabstr%lat + latlabstr = r"%s%sN" % (fmt, degchar) + latlab = latlabstr % lat else: - if mpl.rcParams['text.usetex']: - latlabstr = r'${%s\/^{\circ}}$'%fmt + if mpl.rcParams["text.usetex"]: + latlabstr = r"${%s\/^{\circ}}$" % fmt else: - latlabstr = u'%s\N{DEGREE SIGN}'%fmt - latlab = latlabstr%lat + latlabstr = r"%s%s" % (fmt, degchar) + latlab = latlabstr % lat return latlab diff --git a/packages/basemap/test/mpl_toolkits/basemap/test_Basemap.py b/packages/basemap/test/mpl_toolkits/basemap/test_Basemap.py index 9861a3383..f18b2c29e 100644 --- a/packages/basemap/test/mpl_toolkits/basemap/test_Basemap.py +++ b/packages/basemap/test/mpl_toolkits/basemap/test_Basemap.py @@ -1,13 +1,16 @@ """Import test for the :mod:`mpl_toolkits.basemap.Basemap` class.""" -try: - import unittest2 as unittest -except ImportError: - import unittest +import os +import shutil +import tempfile +import datetime as dt +import unittest import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt +from matplotlib.collections import LineCollection +from matplotlib.contour import QuadContourSet from matplotlib.image import AxesImage from matplotlib.patches import Polygon from mpl_toolkits.basemap import Basemap @@ -85,6 +88,46 @@ def test_init_with_optional_casting(self): bmap2 = Basemap(lat_1=bmap2_lat_1, **kwds) self.assertEqual(bmap1.proj4string, bmap2.proj4string) + def test_drawcoastlines(self, axs=None, axslen0=10): + """Test that no lines are missing when drawing coastlines.""" + + axs_obj = plt.gca() if axs is None else axs + axs_children = axs_obj.get_children() + self.assertEqual(len(axs_children), axslen0) + + bmap = Basemap(projection="merc", resolution="i", lat_ts=20, + llcrnrlat=36.0, llcrnrlon=6.0, + urcrnrlat=47.7, urcrnrlon=19.0) + + collection = bmap.drawcoastlines(linewidth=1, color="red") + self.assertIsInstance(collection, LineCollection) + + axs_children = axs_obj.get_children() + self.assertEqual(len(axs_children), axslen0 + 1) + + lines = collection.get_paths() + self.assertEqual(len(lines), 27) + + def test_drawcountries(self, axs=None, axslen0=10): + """Test that no lines are missing when drawing country boundaries.""" + + axs_obj = plt.gca() if axs is None else axs + axs_children = axs_obj.get_children() + self.assertEqual(len(axs_children), axslen0) + + bmap = Basemap(projection="merc", resolution="i", lat_ts=20, + llcrnrlat=36.0, llcrnrlon=6.0, + urcrnrlat=47.7, urcrnrlon=19.0) + + collection = bmap.drawcountries(linewidth=1, color="blue") + self.assertIsInstance(collection, LineCollection) + + axs_children = axs_obj.get_children() + self.assertEqual(len(axs_children), axslen0 + 1) + + lines = collection.get_paths() + self.assertEqual(len(lines), 29) + @unittest.skipIf(PIL is None, reason="pillow unavailable") def test_arcgisimage_with_cyl(self, axs=None, axslen0=10): """Test showing an ArcGIS image as background.""" @@ -102,6 +145,49 @@ def test_arcgisimage_with_cyl(self, axs=None, axslen0=10): axs_children = axs_obj.get_children() self.assertEqual(len(axs_children), axslen0 + 1) + @unittest.skipIf(PIL is None, reason="pillow unavailable") + def test_arcgisimage_with_cyl_using_cache(self, existing=False, axs=None, axslen0=10): + """Test showing an ArcGIS image as background.""" + + axs_obj = plt.gca() if axs is None else axs + axs_children = axs_obj.get_children() + self.assertEqual(len(axs_children), axslen0) + + bmap = Basemap(ax=axs, projection="cyl", resolution=None, + llcrnrlon=-90, llcrnrlat=30, + urcrnrlon=-60, urcrnrlat=60) + + # Create cache directory string and check it is empty. + tmpdir = tempfile.mkdtemp(prefix="tmp-basemap-cachedir-") + cachedir = tmpdir if existing else os.path.join(tmpdir, "cachedir") + if os.path.isdir(cachedir): + self.assertEqual(len(os.listdir(cachedir)), 0) + + try: + # Check that the first call populates the cache. + img = bmap.arcgisimage(verbose=False, cachedir=cachedir) + self.assertEqual(len(os.listdir(cachedir)), 1) + # Check output properties after the first call. + self.assertIsInstance(img, AxesImage) + axs_children = axs_obj.get_children() + self.assertEqual(len(axs_children), axslen0 + 1) + # Check that the second call does not update the cache. + img = bmap.arcgisimage(verbose=False, cachedir=cachedir) + self.assertEqual(len(os.listdir(cachedir)), 1) + # Check output properties after the second call. + self.assertIsInstance(img, AxesImage) + axs_children = axs_obj.get_children() + self.assertEqual(len(axs_children), axslen0 + 2) + finally: + if os.path.isdir(tmpdir): + shutil.rmtree(tmpdir) + + @unittest.skipIf(PIL is None, reason="pillow unavailable") + def test_arcgisimage_with_cyl_using_cache_already_existing(self): + """Test showing an ArcGIS image as background.""" + + self.test_arcgisimage_with_cyl_using_cache(existing=True) + def _test_basemap_data_warpimage(self, method, axs=None, axslen0=10): """Test drawing a map background from :mod:`basemap_data`.""" @@ -163,6 +249,48 @@ def test_shadedrelief_with_custom_axes(self): _, axs = plt.subplots() self.test_shadedrelief(axs=axs, axslen0=10) + def _test_generic_contour_function(self, function): + """Generic test for the `contour` and `contourf` methods.""" + + bmap = Basemap(projection="ortho", lat_0=45, lon_0=-100, resolution=None) + + # Create a regular lat/lon grid. + nlats = 73 + nlons = 145 + delta = 2 * np.pi / (nlons - 1) + indx = np.indices((nlats, nlons)) + lats = (0.5 * np.pi - delta * indx[0, :, :]) + lons = (delta * indx[1, :, :]) + + # Create some data the regular lat/lon grid. + mean = 0.50 * np.cos(2 * lats) * ((np.sin(2 * lats))**2 + 2) + wave = 0.75 * np.cos(4 * lons) * np.sin(2 * lats)**8 + data = mean + wave + + # Compute native map projection coordinates of lat/lon grid. + x, y = bmap(np.degrees(lons), np.degrees(lats)) + + # Contour data over the map and check output. + cset = getattr(bmap, function)(x, y, data, 15) + self.assertIsInstance(cset, QuadContourSet) + + def test_contour(self): + """Test drawing contours on a map.""" + + self._test_generic_contour_function("contour") + + def test_contourf(self): + """Test drawing filled contours on a map.""" + + self._test_generic_contour_function("contourf") + + def test_nightshade(self): + """Test drawing the day/night terminator and night shade on a map.""" + + bmap = Basemap(projection="mill", lon_0=180) + cset = bmap.nightshade(date=dt.datetime(1970, 1, 1)) + self.assertIsInstance(cset, QuadContourSet) + class TestMplToolkitsBasemapBasemapCall(unittest.TestCase): """Unittest class for :meth:`mpl_toolkits.basemap.Basemap.__call__`.""" diff --git a/packages/basemap/test/mpl_toolkits/basemap/test_cm.py b/packages/basemap/test/mpl_toolkits/basemap/test_cm.py index 77df7d3bf..66d8ef665 100644 --- a/packages/basemap/test/mpl_toolkits/basemap/test_cm.py +++ b/packages/basemap/test/mpl_toolkits/basemap/test_cm.py @@ -1,10 +1,6 @@ """Import test for :mod:`mpl_toolkits.basemap.cm`.""" -try: - import unittest2 as unittest -except ImportError: - import unittest - +import unittest from mpl_toolkits.basemap import cm diff --git a/packages/basemap/test/mpl_toolkits/basemap/test_diagnostic.py b/packages/basemap/test/mpl_toolkits/basemap/test_diagnostic.py index b5bacce3a..f5ac65564 100644 --- a/packages/basemap/test/mpl_toolkits/basemap/test_diagnostic.py +++ b/packages/basemap/test/mpl_toolkits/basemap/test_diagnostic.py @@ -1,11 +1,7 @@ """Import test for :mod:`mpl_toolkits.basemap.diagnostic`.""" +import unittest from collections import namedtuple -try: - import unittest2 as unittest -except ImportError: - import unittest - from mpl_toolkits.basemap import diagnostic diff --git a/packages/basemap/test/mpl_toolkits/basemap/test_proj.py b/packages/basemap/test/mpl_toolkits/basemap/test_proj.py index dfdcd69ba..4385c8f6f 100644 --- a/packages/basemap/test/mpl_toolkits/basemap/test_proj.py +++ b/packages/basemap/test/mpl_toolkits/basemap/test_proj.py @@ -1,10 +1,6 @@ """Import test for :mod:`mpl_toolkits.basemap.proj`.""" -try: - import unittest2 as unittest -except ImportError: - import unittest - +import unittest from mpl_toolkits.basemap.proj import Proj diff --git a/packages/basemap/test/mpl_toolkits/test_basemap.py b/packages/basemap/test/mpl_toolkits/test_basemap.py index 80a31cb2e..2070c2e50 100644 --- a/packages/basemap/test/mpl_toolkits/test_basemap.py +++ b/packages/basemap/test/mpl_toolkits/test_basemap.py @@ -1,10 +1,6 @@ """Import test for the :mod:`mpl_toolkits.basemap` package.""" -try: - import unittest2 as unittest -except ImportError: - import unittest - +import unittest from mpl_toolkits import basemap diff --git a/packages/basemap/utils/GeosLibrary.py b/packages/basemap/utils/GeosLibrary.py index 24bdff3b0..0462d6775 100644 --- a/packages/basemap/utils/GeosLibrary.py +++ b/packages/basemap/utils/GeosLibrary.py @@ -1,18 +1,18 @@ #! /usr/bin/env python # -*- coding: utf-8 -*- # -# Copyright (c) 2021 Víctor Molina García - +# Copyright (c) 2021-2025 Víctor Molina García +# # GeosLibrary.py 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. - +# # GeosLibrary.py 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 GeosLibrary.py. If not, see . # @@ -62,7 +62,7 @@ def __init__(self, version, root=None): def __del__(self): """Clean up after :class:`GeosLibrary` destruction.""" - if self.temp: + if getattr(self, "temp", None) and getattr(self, "root", None): try: shutil.rmtree(self.root) except OSError: diff --git a/packages/basemap_data/setup.cfg b/packages/basemap_data/setup.cfg index 46fc44d00..e22ef7143 100644 --- a/packages/basemap_data/setup.cfg +++ b/packages/basemap_data/setup.cfg @@ -7,6 +7,3 @@ license_files = [sdist] formats = zip - -[bdist_wheel] -universal = 1 diff --git a/packages/basemap_data/setup.py b/packages/basemap_data/setup.py index 2d8e4e620..d56dd243d 100644 --- a/packages/basemap_data/setup.py +++ b/packages/basemap_data/setup.py @@ -7,7 +7,7 @@ import os import itertools from setuptools import setup -from setuptools import find_packages +from setuptools import find_namespace_packages def get_content(name, splitlines=False): @@ -73,7 +73,7 @@ def get_content(name, splitlines=False): "name": "basemap_data", "version": - "1.3.2", + "2.0.0-dev", "license": "GNU Lesser General Public License v3 or later (LGPLv3+)", "description": @@ -98,7 +98,6 @@ def get_content(name, splitlines=False): "Intended Audience :: Science/Research", "License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)", "Operating System :: OS Independent", - "Programming Language :: Python :: 2", "Programming Language :: Python :: 3", "Topic :: Scientific/Engineering :: Visualization", "Topic :: Software Development :: Libraries :: Python Modules", @@ -108,22 +107,17 @@ def get_content(name, splitlines=False): "maps", "plots", ], - "namespace_packages": [ - "mpl_toolkits.basemap_data", - ], "package_dir": {"": "src"}, "packages": - find_packages(where="src"), + find_namespace_packages(where="src"), "package_data": { "mpl_toolkits.basemap_data": data_files, }, "python_requires": ", ".join([ - ">=2.6", - "!=3.0.*", - "!=3.1.*", + ">=3.9", "<4", ]), "project_urls": { diff --git a/packages/basemap_data/src/__init__.py b/packages/basemap_data/src/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/basemap_data/src/mpl_toolkits/__init__.py b/packages/basemap_data/src/mpl_toolkits/__init__.py deleted file mode 100644 index 02de4115d..000000000 --- a/packages/basemap_data/src/mpl_toolkits/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -try: - __import__('pkg_resources').declare_namespace(__name__) -except ImportError: - pass # must not have setuptools diff --git a/packages/basemap_data/src/mpl_toolkits/basemap_data/__init__.py b/packages/basemap_data/src/mpl_toolkits/basemap_data/__init__.py deleted file mode 100644 index 02de4115d..000000000 --- a/packages/basemap_data/src/mpl_toolkits/basemap_data/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -try: - __import__('pkg_resources').declare_namespace(__name__) -except ImportError: - pass # must not have setuptools diff --git a/packages/basemap_data_hires/setup.cfg b/packages/basemap_data_hires/setup.cfg index e408a4da9..e43de0337 100644 --- a/packages/basemap_data_hires/setup.cfg +++ b/packages/basemap_data_hires/setup.cfg @@ -5,6 +5,3 @@ license_files = [sdist] formats = zip - -[bdist_wheel] -universal = 1 diff --git a/packages/basemap_data_hires/setup.py b/packages/basemap_data_hires/setup.py index 7dbe83cf6..7421194d1 100644 --- a/packages/basemap_data_hires/setup.py +++ b/packages/basemap_data_hires/setup.py @@ -7,7 +7,7 @@ import os import itertools from setuptools import setup -from setuptools import find_packages +from setuptools import find_namespace_packages def get_content(name, splitlines=False): @@ -51,7 +51,7 @@ def get_content(name, splitlines=False): "name": "basemap_data_hires", "version": - "1.3.2", + "2.0.0-dev", "license": "GNU Lesser General Public License v3 or later (LGPLv3+)", "description": @@ -76,7 +76,6 @@ def get_content(name, splitlines=False): "Intended Audience :: Science/Research", "License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)", "Operating System :: OS Independent", - "Programming Language :: Python :: 2", "Programming Language :: Python :: 3", "Topic :: Scientific/Engineering :: Visualization", "Topic :: Software Development :: Libraries :: Python Modules", @@ -86,22 +85,17 @@ def get_content(name, splitlines=False): "maps", "plots", ], - "namespace_packages": [ - "mpl_toolkits.basemap_data", - ], "package_dir": {"": "src"}, "packages": - find_packages(where="src"), + find_namespace_packages(where="src"), "package_data": { "mpl_toolkits.basemap_data": data_files, }, "python_requires": ", ".join([ - ">=2.6", - "!=3.0.*", - "!=3.1.*", + ">=3.9", "<4", ]), "project_urls": { diff --git a/packages/basemap_data_hires/src/__init__.py b/packages/basemap_data_hires/src/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/basemap_data_hires/src/mpl_toolkits/__init__.py b/packages/basemap_data_hires/src/mpl_toolkits/__init__.py deleted file mode 100644 index 02de4115d..000000000 --- a/packages/basemap_data_hires/src/mpl_toolkits/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -try: - __import__('pkg_resources').declare_namespace(__name__) -except ImportError: - pass # must not have setuptools diff --git a/packages/basemap_data_hires/src/mpl_toolkits/basemap_data/__init__.py b/packages/basemap_data_hires/src/mpl_toolkits/basemap_data/__init__.py deleted file mode 100644 index 02de4115d..000000000 --- a/packages/basemap_data_hires/src/mpl_toolkits/basemap_data/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -try: - __import__('pkg_resources').declare_namespace(__name__) -except ImportError: - pass # must not have setuptools