def select(cls, dataset, selection_mask=None, **selection): if cls.geom_dims(dataset): data = cls.shape_mask(dataset, selection) else: data = dataset.data if selection_mask is None: selection_mask = cls.select_mask(dataset, selection) empty = not selection_mask.sum() dimensions = dataset.dimensions() if empty: return { d.name: np.array([], dtype=cls.dtype(dataset, d)) for d in dimensions } indexed = cls.indexed(dataset, selection) new_data = {} for k, v in data.items(): if k not in dimensions or isscalar(v): new_data[k] = v else: new_data[k] = v[selection_mask] if indexed and len(list(new_data.values())[0]) == 1 and len( dataset.vdims) == 1: value = new_data[dataset.vdims[0].name] return value if isscalar(value) else value[0] return new_data
def init(cls, eltype, data, kdims, vdims): odict_types = (OrderedDict, cyODict) if kdims is None: kdims = eltype.kdims if vdims is None: vdims = eltype.vdims dimensions = [dimension_name(d) for d in kdims + vdims] if isinstance(data, geom_types): data = {'geometry': data} if not cls.applies(data): raise ValueError( "GeomDictInterface only handles dictionary types " "containing a 'geometry' key and shapely geometry " "value.") unpacked = [] for d, vals in data.items(): if isinstance(d, tuple): vals = np.asarray(vals) if vals.shape == (0, ): for sd in d: unpacked.append((sd, np.array([], dtype=vals.dtype))) elif not vals.ndim == 2 and vals.shape[1] == len(d): raise ValueError("Values for %s dimensions did not have " "the expected shape.") else: for i, sd in enumerate(d): unpacked.append((sd, vals[:, i])) elif d not in dimensions: unpacked.append((d, vals)) else: if not isscalar(vals): vals = np.asarray(vals) if not vals.ndim == 1 and d in dimensions: raise ValueError( 'DictInterface expects data for each column to be flat.' ) unpacked.append((d, vals)) if not cls.expanded( [vs for d, vs in unpacked if d in dimensions and not isscalar(vs)]): raise ValueError( 'DictInterface expects data to be of uniform shape.') if isinstance(data, odict_types): data.update(unpacked) else: data = OrderedDict(unpacked) return data, {'kdims': kdims, 'vdims': vdims}, {}
def geom_from_dict(geom, xdim, ydim, single_type, multi_type): from shapely.geometry import (Point, LineString, Polygon, MultiPoint, MultiPolygon, MultiLineString) if (xdim, ydim) in geom: xs, ys = np.asarray(geom.pop((xdim, ydim))).T elif xdim in geom and ydim in geom: xs, ys = geom.pop(xdim), geom.pop(ydim) else: raise ValueError('Could not find geometry dimensions') xscalar, yscalar = isscalar(xs), isscalar(ys) if xscalar and yscalar: xs, ys = np.array([xs]), np.array([ys]) elif xscalar: xs = np.full_like(ys, xs) elif yscalar: ys = np.full_like(xs, ys) geom_array = np.column_stack([xs, ys]) splits = np.where(np.isnan( geom_array[:, :2].astype('float')).sum(axis=1))[0] if len(splits): split_geoms = [ g[:-1] if i == (len(splits) - 1) else g for i, g in enumerate(np.split(geom_array, splits + 1)) ] else: split_geoms = [geom_array] split_holes = geom.pop('holes', None) if split_holes is not None and len(split_holes) != len(split_geoms): raise DataError('Polygons with holes containing multi-geometries ' 'must declare a list of holes for each geometry.') if single_type is Point: if len(splits) > 1 or any(len(g) > 1 for g in split_geoms): geom = MultiPoint(np.concatenate(split_geoms)) else: geom = Point(*split_geoms[0]) elif len(splits): if multi_type is MultiPolygon: if split_holes is None: split_holes = [[]] * len(split_geoms) geom = MultiPolygon(list(zip(split_geoms, split_holes))) else: geom = MultiLineString(split_geoms) elif single_type is Polygon: if split_holes is None or not len(split_holes): split_holes = [None] geom = Polygon(split_geoms[0], split_holes[0]) else: geom = LineString(split_geoms[0]) return geom
def isscalar(cls, dataset, dim, per_geom=False): """ Tests if dimension is scalar in each subpath. """ dim = dataset.get_dimension(dim) geom_dims = cls.geom_dims(dataset) if dim in geom_dims: return False elif per_geom: return all(isscalar(v) or len(list(unique_array(v))) == 1 for v in dataset.data[dim.name]) dim = dataset.get_dimension(dim) return len(dataset.data[dim.name].unique()) == 1
def iloc(cls, dataset, index): from shapely.geometry import MultiPoint rows, cols = index data = dict(dataset.data) geom = data['geometry'] if isinstance(geom, MultiPoint): if isscalar(rows) or isinstance(rows, slice): geom = geom[rows] elif isinstance(rows, (set, list)): geom = MultiPoint([geom[r] for r in rows]) data['geometry'] = geom return data
def from_multi(eltype, data, kdims, vdims): """Converts list formats into geopandas.GeoDataFrame. Args: eltype: Element type to convert data: The original data kdims: The declared key dimensions vdims: The declared value dimensions Returns: A GeoDataFrame containing the data in the list based format. """ from geopandas import GeoDataFrame new_data = [] types = [] xname, yname = (kd.name for kd in kdims[:2]) for d in data: types.append(type(d)) if isinstance(d, dict): d = {k: v if isscalar(v) else np.asarray(v) for k, v in d.items()} new_data.append(d) continue new_el = eltype(d, kdims, vdims) if new_el.interface is GeoPandasInterface: types[-1] = GeoDataFrame new_data.append(new_el.data) continue new_dict = {} for d in new_el.dimensions(): if d in (xname, yname): scalar = False else: scalar = new_el.interface.isscalar(new_el, d) vals = new_el.dimension_values(d, not scalar) new_dict[d.name] = vals[0] if scalar else vals new_data.append(new_dict) if len(set(types)) > 1: raise DataError('Mixed types not supported') if new_data and types[0] is GeoDataFrame: data = pd.concat(new_data) else: columns = [d.name for d in kdims + vdims if d not in (xname, yname)] geom = GeoPandasInterface.geom_type(eltype) if not len(data): return GeoDataFrame([], columns=['geometry'] + columns) data = to_geopandas(new_data, xname, yname, columns, geom) return data
def iloc(cls, dataset, index): from geopandas import GeoSeries from shapely.geometry import MultiPoint rows, cols = index geom_dims = cls.geom_dims(dataset) geom_col = cls.geo_column(dataset.data) scalar = False columns = list(dataset.data.columns) if isinstance(cols, slice): cols = [d.name for d in dataset.dimensions()][cols] elif np.isscalar(cols): scalar = np.isscalar(rows) cols = [dataset.get_dimension(cols).name] else: cols = [dataset.get_dimension(d).name for d in index[1]] if not all(d in cols for d in geom_dims): raise DataError( "Cannot index a dimension which is part of the " "geometry column of a spatialpandas DataFrame.", cls) cols = list( unique_iterator([ columns.index(geom_col) if c in geom_dims else columns.index(c) for c in cols ])) geom_type = dataset.data[geom_col].geom_type.iloc[0] if geom_type != 'MultiPoint': if scalar: return dataset.data.iloc[rows[0], cols[0]] elif isscalar(rows): rows = [rows] return dataset.data.iloc[rows, cols] geoms = dataset.data[geom_col] count = 0 new_geoms, indexes = [], [] for i, geom in enumerate(geoms): length = len(geom) if np.isscalar(rows): if count <= rows < (count + length): new_geoms.append(geom[rows - count]) indexes.append(i) break elif isinstance(rows, slice): if rows.start is not None and rows.start > (count + length): continue elif rows.stop is not None and rows.stop < count: break start = None if rows.start is None else max( rows.start - count, 0) stop = None if rows.stop is None else min( rows.stop - count, length) if rows.step is not None: dataset.param.warning( ".iloc step slicing currently not supported for" "the multi-tabular data format.") indexes.append(i) new_geoms.append(geom[start:stop]) elif isinstance(rows, (list, set)): sub_rows = [(r - count) for r in rows if count <= r < (count + length)] if not sub_rows: continue indexes.append(i) new_geoms.append(MultiPoint([geom[r] for r in sub_rows])) count += length new = dataset.data.iloc[indexes].copy() new[geom_col] = GeoSeries(new_geoms) return new
def dimension_type(cls, dataset, dim): name = dataset.get_dimension(dim, strict=True).name if name in cls.geom_dims(dataset): return float values = dataset.data[name] return type(values) if isscalar(values) else values.dtype.type
def init(cls, eltype, data, kdims, vdims): odict_types = (OrderedDict, cyODict) if kdims is None: kdims = eltype.kdims if vdims is None: vdims = eltype.vdims dimensions = [dimension_name(d) for d in kdims + vdims] if isinstance(data, geom_types): data = {'geometry': data} elif not isinstance(data, dict) or 'geometry' not in data: xdim, ydim = kdims[:2] from shapely.geometry import (Point, LineString, Polygon, MultiPoint, MultiPolygon, MultiLineString, LinearRing) data = to_geom_dict(eltype, data, kdims, vdims, GeomDictInterface) geom = data.get('geom_type') or MultiInterface.geom_type(eltype) poly = 'holes' in data or geom == 'Polygon' if poly: single_type, multi_type = Polygon, MultiPolygon elif geom == 'Line': single_type, multi_type = LineString, MultiLineString elif geom == 'Ring': single_type, multi_type = LinearRing, MultiPolygon else: single_type, multi_type = Point, MultiPoint data['geometry'] = geom_from_dict(data, xdim.name, ydim.name, single_type, multi_type) if not cls.applies(data): raise ValueError( "GeomDictInterface only handles dictionary types " "containing a 'geometry' key and shapely geometry " "value.") unpacked = [] for d, vals in data.items(): if isinstance(d, tuple): vals = np.asarray(vals) if vals.shape == (0, ): for sd in d: unpacked.append((sd, np.array([], dtype=vals.dtype))) elif not vals.ndim == 2 and vals.shape[1] == len(d): raise ValueError("Values for %s dimensions did not have " "the expected shape.") else: for i, sd in enumerate(d): unpacked.append((sd, vals[:, i])) elif d not in dimensions: unpacked.append((d, vals)) else: if not isscalar(vals): vals = np.asarray(vals) if not vals.ndim == 1 and d in dimensions: raise ValueError( 'DictInterface expects data for each column to be flat.' ) unpacked.append((d, vals)) if not cls.expanded( [vs for d, vs in unpacked if d in dimensions and not isscalar(vs)]): raise ValueError( 'DictInterface expects data to be of uniform shape.') if isinstance(data, odict_types): data.update(unpacked) else: data = OrderedDict(unpacked) return data, {'kdims': kdims, 'vdims': vdims}, {}