AttributeError returned by caropy.crs.CRS with proj4_params
Closed this issue · 4 comments
Example:
Python 3.5.1 (default, Dec 7 2015, 21:59:10)
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.1.76)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import cartopy
>>> crs = cartopy.crs.Mercator()
>>> crs
<cartopy.crs.Mercator object at 0x1039d5a40>
>>> proj4 = crs.proj4_params
>>> proj4
{'ellps': 'WGS84', 'k': 1, 'proj': 'merc', 'lon_0': 0.0, 'units': 'm'}
>>> cartopy.crs.CRS(proj4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "cartopy/_crs.pyx", line 142, in cartopy._crs.CRS.__init__ (lib/cartopy/_crs.c:2771)
AttributeError: 'cartopy._crs.CRS' object has no attribute 'globe'
>>>
What am I missing? Or is this a bug?
That's a really interesting question - thank you!
The CRS
class wasn't really designed for direct use (the focus is more on Projection
), but if you're just doing low-level point/vector transformations then I suppose there's no reason why you couldn't use it... except for the problem you've found.
CRS
is a class defined in Cython code, so in reality it's a C extension type. This means it doesn't have an attribute dictionary - only explicitly declared attributes exist. Looking in _crs.pxd we can see the declared attributes are only: proj4
, proj4_init
, and proj4_params
. Hence the error that you're seeing - there really is no globe
attribute for the code to access.
So how come Mercator
and the other CRS subclasses actually work? A Python subclass of CRS
does have an attribute dictionary, so it's possible to add any attributes. In the general case:
>>> class Foo(object): pass
...
>>> foo = Foo()
>>> foo.bar = 'This works!'
So... where does that leave us? A simple workaround for now is just to create a trivial Python subclass:
>>> class Foo(cartopy.crs.CRS): pass
...
>>> Foo({'proj': 'lonlat'}).proj4_params
{'ellps': 'WGS84', 'proj': 'lonlat'}
But it seems reasonable that we should also make CRS
usable on its own! (i.e. possibly just as simple as adding globe
to the list of declared attributes, possibly we'll also need to define a property) @pelson - any idea why CRS
shouldn't be usable?
...
cartopy.crs.CRS(proj4)
...
NB. If you're trying to define a new map then you don't want to be doing this. A map needs to be a subclass of Projection
with a defined boundary, etc.
You guys should fix this issue. I suggest removing the raise
error:
@property def crs(self): """Return the coordinate reference system (CRS) as a CFProjection object.""" if 'crs' in self._data_array.coords: return self._data_array.coords['crs'].item() raise AttributeError('crs attribute is not available.')
This will allow coders to abstract the class.