Create HammerAxes Class
We will create a custom class for the Aitoff-Hammer projection, an equal-area map projection called HammerAxes
.
class HammerAxes(GeoAxes):
"""
A custom class for the Aitoff-Hammer projection, an equal-area map
projection.
https://en.wikipedia.org/wiki/Hammer_projection
"""
## The projection must specify a name. This will be used by the
## user to select the projection,
## i.e. ``subplot(projection='custom_hammer')``.
name = 'custom_hammer'
class HammerTransform(Transform):
"""The base Hammer transform."""
input_dims = output_dims = 2
def __init__(self, resolution):
"""
Create a new Hammer transform. Resolution is the number of steps
to interpolate between each input line segment to approximate its
path in curved Hammer space.
"""
Transform.__init__(self)
self._resolution = resolution
def transform_non_affine(self, ll):
longitude, latitude = ll.T
## Pre-compute some values
half_long = longitude / 2
cos_latitude = np.cos(latitude)
sqrt2 = np.sqrt(2)
alpha = np.sqrt(1 + cos_latitude * np.cos(half_long))
x = (2 * sqrt2) * (cos_latitude * np.sin(half_long)) / alpha
y = (sqrt2 * np.sin(latitude)) / alpha
return np.column_stack([x, y])
def transform_path_non_affine(self, path):
## vertices = path.vertices
ipath = path.interpolated(self._resolution)
return Path(self.transform(ipath.vertices), ipath.codes)
def inverted(self):
return HammerAxes.InvertedHammerTransform(self._resolution)
class InvertedHammerTransform(Transform):
input_dims = output_dims = 2
def __init__(self, resolution):
Transform.__init__(self)
self._resolution = resolution
def transform_non_affine(self, xy):
x, y = xy.T
z = np.sqrt(1 - (x / 4) ** 2 - (y / 2) ** 2)
longitude = 2 * np.arctan((z * x) / (2 * (2 * z ** 2 - 1)))
latitude = np.arcsin(y*z)
return np.column_stack([longitude, latitude])
def inverted(self):
return HammerAxes.HammerTransform(self._resolution)
def __init__(self, *args, **kwargs):
self._longitude_cap = np.pi / 2.0
super().__init__(*args, **kwargs)
self.set_aspect(0.5, adjustable='box', anchor='C')
self.clear()
def _get_core_transform(self, resolution):
return self.HammerTransform(resolution)