Skip to content

Commit

Permalink
Merge pull request #69 from ioam/project_ops
Browse files Browse the repository at this point in the history
Added project_points and general project operation
  • Loading branch information
philippjfr authored Jun 29, 2017
2 parents 0861907 + e3ed96d commit d240a9b
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 15 deletions.
1 change: 1 addition & 0 deletions geoviews/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from .element import (_Element, Feature, Tiles, # noqa (API import)
WMTS, LineContours, FilledContours, Text, Image,
Points, Path, Polygons, Shape, Dataset)
from . import operation # noqa (API import)
from . import plotting # noqa (API import)
from . import feature # noqa (API import)

Expand Down
66 changes: 53 additions & 13 deletions geoviews/operation.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import param
import numpy as np
from cartopy import crs as ccrs
from cartopy.img_transform import regrid
from cartopy.img_transform import warp_array

from holoviews.operation import ElementOperation

from .element import Image, Shape, Polygons, Path
from .element import Image, Shape, Polygons, Path, Points
from .util import project_extents

class project_shape(ElementOperation):
Expand All @@ -19,13 +19,38 @@ class project_shape(ElementOperation):
instantiate=False, doc="""
Projection the shape type is projected to.""")

supported_types = [Shape, Polygons, Path]

def _process_element(self, element):
geom = self.p.projection.project_geometry(element.geom(),
element.crs)
return element.clone(geom, crs=self.p.projection)

def _process(self, element, key=None):
return element.map(self._process_element, [Shape, Polygons, Path])
return element.map(self._process_element, self.supported_types)


class project_points(ElementOperation):

projection = param.ClassSelector(default=ccrs.GOOGLE_MERCATOR,
class_=ccrs.Projection,
instantiate=False, doc="""
Projection the shape type is projected to.""")

supported_types = [Points]

def _process_element(self, element):
xdim, ydim = element.dimensions()[:2]
xs, ys = (element.dimension_values(i) for i in range(2))
coordinates = self.p.projection.transform_points(element.crs, xs, ys)
new_data = element.columns()
new_data[xdim.name] = coordinates[:, 0]
new_data[ydim.name] = coordinates[:, 1]
return element.clone(new_data, crs=self.p.projection,
datatype=[element.interface.datatype]+element.datatype)

def _process(self, element, key=None):
return element.map(self._process_element, self.supported_types)


class project_image(ElementOperation):
Expand All @@ -41,23 +66,38 @@ class project_image(ElementOperation):
instantiate=False, doc="""
Projection the image type is projected to.""")

supported_types = [Image]

def _process(self, img, key=None):
proj = self.p.projection
if proj == img.crs:
return img
arr = img.dimension_values(2, flat=False).T
xs = img.dimension_values(0)
ys = img.dimension_values(1)
arr = img.dimension_values(2, flat=False)
x0, x1 = img.range(0)
y0, y1 = img.range(1)
xn, yn = arr.shape
px0, py0, px1, py1 = project_extents((x0, y0, x1, y1),
img.crs, proj)
px = np.linspace(px0, px1, xn)
py = np.linspace(py0, py1, yn)
pxs, pys = np.meshgrid(px, py)
pxs = pxs.reshape((yn, xn))
pys = pys.reshape((yn, xn))
parray = regrid(arr, xs, ys, img.crs, proj, pxs, pys)
return Image((px, py, parray), kdims=img.kdims,
src_ext, trgt_ext = (x0, x1, y0, y1), (px0, px1, py0, py1)
projected, extents = warp_array(arr, proj, img.crs, (xn, yn),
src_ext, trgt_ext)
bounds = (extents[0], extents[2], extents[1], extents[3])
data = np.flipud(projected)
return Image(data, bounds=bounds, kdims=img.kdims,
vdims=img.vdims, crs=proj)


class project(ElementOperation):
"""
Projects GeoViews Element types to the specified projection.
"""

projection = param.ClassSelector(default=ccrs.GOOGLE_MERCATOR,
class_=ccrs.Projection,
instantiate=False, doc="""
Projection the image type is projected to.""")

def _process(self, element, key=None):
element = element.map(project_image, project_image.supported_types)
element = element.map(project_shape, project_shape.supported_types)
return element.map(project_points, project_points.supported_types)
4 changes: 2 additions & 2 deletions geoviews/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ def project_extents(extents, src_proj, dest_proj, tol=1e-6):
domain_in_src_proj = Polygon([[x1, y1], [x2, y1],
[x2, y2], [x1, y2],
[x1, y1]])
boundary_poly = Polygon(dest_proj.boundary)
boundary_poly = Polygon(src_proj.boundary)
if src_proj != dest_proj:
# Erode boundary by threshold to avoid transform issues.
# This is a workaround for numerical issues at the boundary.
eroded_boundary = boundary_poly.buffer(-dest_proj.threshold)
eroded_boundary = boundary_poly.buffer(-src_proj.threshold)
geom_in_src_proj = eroded_boundary.intersection(
domain_in_src_proj)
geom_in_crs = dest_proj.project_geometry(geom_in_src_proj, src_proj)
Expand Down

0 comments on commit d240a9b

Please sign in to comment.