Source code for gridgeo.gridgeo

import os
from copy import copy
from itertools import zip_longest

import netCDF4
from shapely.geometry import MultiPolygon
from shapely.ops import unary_union

from gridgeo.cfvariable import CFVariable
from gridgeo.ugrid import ugrid

try:
    from matplotlib import tri
except ImportError:
    tri = False


[docs]def set_precision(coords, precision): result = [] try: return round(coords, int(precision)) except TypeError: for coord in coords: result.append(set_precision(coord, precision)) return result
[docs]class GridGeo(object): """ GridGeo class takes a nc-like object (netCDF4-python or a netCDF file/URL) and parse the grid information. """ def __init__(self, nc, **kwargs): """ Return a GridGeo class. nc: netCDF4-python object or a netCDF file/URL string """ if isinstance(nc, netCDF4.Dataset): pass else: nc = netCDF4.Dataset(nc) var = CFVariable(nc, **kwargs) self.x = var.x_axis()[:] self.y = var.y_axis()[:] self.mesh = var.topology() self.polygons = var.polygons() self._geo_interface = None self._outline = None self._geometry = None if self.mesh == "ugrid" and tri: grid = ugrid(nc) node_x = grid["nodes"]["x"] node_y = grid["nodes"]["y"] faces = grid["faces"] self.triang = tri.Triangulation(node_x, node_y, triangles=faces) @property def geometry(self): if self._geometry is None: self._geometry = MultiPolygon(list(zip_longest(self.polygons, []))) return self._geometry def __str__(self): return f"{self.mesh}" def __repr__(self): return f"<GridGeo: {self.mesh}>" @property def outline(self): if self._outline is None: self._outline = unary_union(self.geometry) return self._outline @property def __geo_interface__(self): if self._geo_interface is None: self._geo_interface = self.geometry.__geo_interface__ return self._geo_interface
[docs] def to_geojson(self, **kw): """ Return a GeoJSON representation of an grid object. The `kw` are based on the simplestyle-spec: https://github.com/mapbox/simplestyle-spec/tree/master/1.1.0 """ title = kw.pop("title", self.mesh) description = kw.pop("description", "") marker_size = kw.pop("marker-size", "medium") marker_symbol = kw.pop("marker-symbol", "") marker_color = kw.pop("marker-color", "7e7e7e") stroke = kw.pop("stroke", "555555") stroke_opacity = kw.pop("stroke-opacity", 1) stroke_width = kw.pop("stroke-width", 2) fill = kw.pop("fill", "555555") fill_opacity = kw.pop("fill-opacity", 0.6) float_precision = kw.pop("float_precision", 6) geometry = copy(self.geometry.__geo_interface__) geometry["coordinates"] = set_precision( geometry["coordinates"], float_precision ) geojson = { "type": "Feature", "properties": { "title": title, "description": description, "marker-size": marker_size, "marker-symbol": marker_symbol, "marker-color": marker_color, "stroke": stroke, "stroke-opacity": stroke_opacity, "stroke-width": stroke_width, "fill": fill, "fill-opacity": fill_opacity, }, "geometry": geometry, } return geojson
[docs] def save(self, filename, fmt=None, **kw): formats = ["shp", "geojson"] extension = os.path.splitext(filename)[1] if not fmt: fmt = extension.lstrip(".") if fmt not in formats: raise ValueError(f"Expected shp or geojson, got {fmt}") if extension.lstrip(".") != fmt: filename = ".".join([filename, fmt]) if fmt == "geojson": import json geojson = self.to_geojson(**kw) kw = {"sort_keys": True, "indent": 4, "separators": (",", ": ")} with open(filename, "w") as f: json.dump(geojson, f, **kw) if fmt == "shp": import fiona name = kw.pop("name", self.mesh) schema = { "geometry": "MultiPolygon", "properties": {"name": f"str:{len(name)}"}, } with fiona.open(filename, "w", "ESRI Shapefile", schema) as f: f.write( { "geometry": self.__geo_interface__, "properties": {"name": name}, } )