Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix support for pyproj-2 EPSG syntax #186

Merged
merged 19 commits into from
Apr 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion docs/source/geo_def.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,13 @@ where
* **upper_right_x**: projection x coordinate of upper right corner of upper right pixel
* **upper_right_y**: projection y coordinate of upper right corner of upper right pixel

Below is an example of creating an ``AreaDefinition``:
Below are three examples of creating an ``AreaDefinition``:

.. doctest::

>>> from pyresample.geometry import AreaDefinition

>>> # a) Using a projection dictionary
>>> area_id = 'ease_sh'
>>> description = 'Antarctic EASE grid'
>>> proj_id = 'ease_sh'
Expand All @@ -74,6 +76,37 @@ Below is an example of creating an ``AreaDefinition``:
Number of rows: 425
Area extent: (-5326849.0625, -5326849.0625, 5326849.0625, 5326849.0625)

>>> # b) Using an explicit proj4 string
>>> proj_string = '+proj=laea +lat_0=-90 +lon_0=0 +a=6371228.0 +units=m'
>>> area_def = AreaDefinition(area_id, description, proj_id, proj_string,
... width, height, area_extent)
>>> print(area_def)
Area ID: ease_sh
Description: Antarctic EASE grid
Projection ID: ease_sh
Projection: {'a': '6371228.0', 'lat_0': '-90.0', 'lon_0': '0.0', 'proj': 'laea', 'units': 'm'}
Number of columns: 425
Number of rows: 425
Area extent: (-5326849.0625, -5326849.0625, 5326849.0625, 5326849.0625)

>>> # c) Using an EPSG code in a proj4 string
>>> proj_string = '+init=EPSG:3409' # Use 'EPSG:3409' with pyproj 2.0+
>>> area_def = AreaDefinition(area_id, description, proj_id, proj_string,
... width, height, area_extent)
>>> print(area_def)
Area ID: ease_sh
Description: Antarctic EASE grid
Projection ID: ease_sh
Projection: {'init': 'EPSG:3409'}
Number of columns: 425
Number of rows: 425
Area extent: (-5326849.0625, -5326849.0625, 5326849.0625, 5326849.0625)

.. note::

When using pyproj 2.0+, please use the new ``'EPSG:XXXX'`` syntax
as the old ``'+init=EPSG:XXXX'`` is no longer supported.

Creating an ``AreaDefinition`` can be complex if you don't know everything
about the region being described. Pyresample provides multiple utilities
for creating areas as well as storing them on disk for repeated use. See
Expand Down
31 changes: 22 additions & 9 deletions docs/source/geometry_utils.rst
Original file line number Diff line number Diff line change
Expand Up @@ -212,10 +212,10 @@ from_ul_corner
Loading from disk
-----------------

The :func:`~pyresample.utils.load_area` function can be used to
The :func:`~pyresample.area_config.load_area` function can be used to
parse area definitions from a configuration file by giving it the
area file name and regions you wish to load. :func:`~pyresample.utils.load_area`
takes advantage of :func:`~pyresample.utils.create_area_def`
area file name and regions you wish to load. :func:`~pyresample.area_config.load_area`
takes advantage of :func:`~pyresample.area_config.create_area_def`
and hence allows for the same arguments in the on-disk file.
Pyresample uses the YAML file format to store on-disk area definitions.
Below is an example YAML configuration file showing the various ways
Expand Down Expand Up @@ -344,20 +344,33 @@ an area might be specified.
resolution: 0.22542974631297721
units: deg

epsg:
area_id: ease_sh
description: Example of making an area definition using EPSG codes
projection:
init: EPSG:3410
shape: [425, 425]
area_extent: [-5326849.0625, -5326849.0625, 5326849.0625, 5326849.0625]

.. note::

The `lower_left_xy` and `upper_right_xy` items give the coordinates of the
outer edges of the corner pixels on the x and y axis respectively. When the
projection coordinates are longitudes and latitudes, it is expected to
provide the extent in `longitude, latitude` order.

.. note::

When using pyproj 2.0+, please use the new ``'EPSG: XXXX'`` syntax
as the old ``'init: EPSG:XXXX'`` is no longer supported.

If we assume the YAML content is stored in an ``areas.yaml`` file, we can
read a single ``AreaDefinition`` named ``corner`` by doing:

.. doctest::

>>> from pyresample import utils
>>> area_def = utils.load_area('areas.yaml', 'corner')
>>> from pyresample import load_area
>>> area_def = load_area('areas.yaml', 'corner')
>>> print(area_def)
Area ID: corner
Description: Example of making an area definition using shape, upper_left_extent, and resolution
Expand All @@ -371,7 +384,7 @@ series of arguments:

.. doctest::

>>> corner, boundary = utils.load_area('areas.yaml', 'corner', 'boundary')
>>> corner, boundary = load_area('areas.yaml', 'corner', 'boundary')
>>> print(boundary)
Area ID: ease_sh
Description: Example of making an area definition using shape and area_extent
Expand Down Expand Up @@ -410,8 +423,8 @@ An area definition dict can be read using

.. doctest::

>>> from pyresample import utils
>>> area = utils.load_area('areas.cfg', 'ease_nh')
>>> from pyresample import load_area
>>> area = load_area('areas.cfg', 'ease_nh')
>>> print(area)
Area ID: ease_nh
Description: Arctic EASE grid
Expand All @@ -427,7 +440,7 @@ Several area definitions can be read at once using the region names in an argume

.. doctest::

>>> nh_def, sh_def = utils.load_area('areas.cfg', 'ease_nh', 'ease_sh')
>>> nh_def, sh_def = load_area('areas.cfg', 'ease_nh', 'ease_sh')
>>> print(sh_def)
Area ID: ease_sh
Description: Antarctic EASE grid
Expand Down
5 changes: 5 additions & 0 deletions pyresample/_cartopy.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

from logging import getLogger
import numpy as np
import pyproj
import warnings

try:
from xarray import DataArray
Expand Down Expand Up @@ -59,6 +61,9 @@ def _globe_from_proj4(proj4_terms):
class _PROJ4Projection(ccrs.Projection):

def __init__(self, proj4_terms, globe=None, bounds=None):
if 'EPSG' in proj4_terms.upper():
warnings.warn('Converting EPSG projection to proj4 string, which is a potentially lossy transformation')
proj4_terms = pyproj.Proj(proj4_terms).definition_string().strip()
terms = proj4_str_to_dict(proj4_terms)
globe = _globe_from_proj4(terms) if globe is None else globe

Expand Down
18 changes: 15 additions & 3 deletions pyresample/_spatial_mp.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import multiprocessing as mp
import warnings

from pyresample.utils import proj4_str_to_dict
from pyresample.utils import proj4_str_to_dict, is_pyproj2


try:
Expand Down Expand Up @@ -112,8 +112,12 @@ def query(self, x, k=1, eps=0, p=2, distance_upper_bound=np.inf):
class BaseProj(pyproj.Proj):

def __init__(self, projparams=None, preserve_units=True, **kwargs):
# Copy dict-type arguments as they will be modified in-place
if isinstance(projparams, dict):
projparams = projparams.copy()

# Pyproj<2 uses __new__ to initiate data and does not define its own __init__ method.
if pyproj.__version__ >= '2':
if is_pyproj2():
# If init is found in any of the data, override any other area parameters.
if 'init' in kwargs:
warnings.warn('init="EPSG:XXXX" is no longer supported. Use "EPSG:XXXX" as a proj string instead')
Expand All @@ -127,10 +131,18 @@ def __init__(self, projparams=None, preserve_units=True, **kwargs):
projparams = proj4_str_to_dict(projparams)
warnings.warn(warn_msg)
projparams = projparams.pop('init')
# New syntax 'EPSG:XXXX'
if 'EPSG' in kwargs or (isinstance(projparams, dict) and 'EPSG' in projparams):
djhoese marked this conversation as resolved.
Show resolved Hide resolved
if 'EPSG' in kwargs:
epsg_code = kwargs.pop('EPSG')
else:
epsg_code = projparams.pop('EPSG')
projparams = 'EPSG:{}'.format(epsg_code)

super(BaseProj, self).__init__(projparams=projparams, preserve_units=preserve_units, **kwargs)

def is_latlong(self):
if pyproj.__version__ >= '2':
if is_pyproj2():
return self.crs.is_geographic
return super(BaseProj, self).is_latlong()

Expand Down
2 changes: 2 additions & 0 deletions pyresample/test/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
test_ewa_fornav,
test_bilinear,
test_data_reduce,
test_spatial_mp
)

import unittest
Expand All @@ -59,6 +60,7 @@ def suite():
mysuite.addTests(test_ewa_fornav.suite())
mysuite.addTests(test_bilinear.suite())
mysuite.addTests(test_data_reduce.suite())
mysuite.addTests(test_spatial_mp.suite())
return mysuite


Expand Down
Loading