def update(self, feature, fields=None): """ Updates a :class:`Feature <geoscript.feature.Feature>` of the layer. *feature* is the feature to update. *fields* is an optional ``list`` of field names (as ``str`` objects) to update. >>> from geoscript import geom >>> l = Layer() >>> l.add([geom.Point(0,0)]) >>> f = l.first() >>> f.geom POINT (0 0) >>> f.geom = geom.Point(1,1) >>> l.update(f) >>> f = l.first() >>> f.geom POINT (1 1) """ if self.readonly: raise Exception('Layer is read-only') f = Filter("IN ('%s')" % feature.id) if not fields: fields = feature.schema.keys() vals = [feature._feature.getAttribute('%s' % fld) for fld in fields] self._source.modifyFeatures(fields, vals, f._filter)
def histogram(self, field, nbins=10, low=None, high=None, filter=None): if low is None or high is None: minmax = self.extrema(field) low = minmax[0] if low is None else low high = minmax[1] if high is None else high rnge = high - low dx = rnge / float(nbins) values = [0] * nbins # should optimize this, we don't need a filter if a low,high is not # specified fil = Filter('%s BETWEEN %s AND %s' % (field, low, high)) # concatenate with one specified fil += self._filter(filter) fit = self.layer._source.getFeatures(fil._filter).features() try: while fit.hasNext(): f = fit.next() val = f.getAttribute(field) values[min(nbins - 1, int( (val - low) / float(rnge) * nbins))] += 1 finally: fit.close() keys = [round(low + x * dx, 2) for x in range(0, nbins + 1)] return zip([(keys[i - 1], keys[i]) for i in range(1, len(keys))], values)
def extrema(self, field, low=None, high=None, filter=None): # build a filter based on specified min/max values fil = ['%s >= %s' % (field, low)] if low != None else [] fil += ['%s <= %s' % (field, high)] if high != None else [] fil = ' AND '.join(fil) fil = Filter(fil) if len(fil) > 0 else Filter.PASS # concatenate with one passed in fil += self._filter(filter) q = Query(self.layer.name) q.setFilter(fil._filter) min, max = None, None fit = self.layer._source.getFeatures(q).features() try: while fit.hasNext(): f = fit.next() val = f.getAttribute(field) min = val if min == None or val < min else min max = val if max == None or val > max else max finally: fit.close() return (min, max)
def count(self, filter=None): """ The number of features in the layer as an ``int``. *filter* is an optional :class:`Filter <geoscript.filter.Filter>` to constrains the counted set of features. >>> l = Layer() >>> l.count() 0 >>> from geoscript import geom >>> l.add([geom.Point(1,2)]) >>> l.add([geom.Point(3,4)]) >>> l.count() 2 >>> l.count('INTERSECTS(geom,POINT(3 4))') 1 """ f = Filter(filter) if filter else Filter.PASS count = self._source.getCount(DefaultQuery(self.name, f._filter)) if count == -1: count = 0 # calculate manually for f in self.features(filter): count += 1 return count
def testFilter(self): s = (Fill('red') + Stroke('blue') ).where("FOO = 'foo'") + Fill('green').where("BAR = 'bar'") st = s._style() rules = st.featureTypeStyles()[0].rules() assert 2 == len(rules) rule = rules[0] assert Filter("FOO = 'foo'") == Filter(rule.getFilter()) syms = rule.symbolizers() assert 2 == len(syms) assert isinstance(syms[0], PolygonSymbolizer) assert isinstance(syms[1], LineSymbolizer) rule = rules[1]
def cursor(self, filter=None, sort=None, hints=None): """ Returns a :class:`Cursor <geoscript.layer.cursor.Cursor>` over the features of the layer. *filter* is a optional :class:`Filter <geoscript.filter.Filter>` to constrain the features iterated over. *sort* is an optional tuple or ``list`` of tuples that defined the order in which features are iterated over. The first value of each tuple is the name of a field to sort on. The second value is one of the strings 'ASC' or 'DESC', representing ascending and decending sort order respectively. >>> l = Layer() >>> from geoscript import geom >>> l.add([geom.Point(1,2)]) >>> l.add([geom.Point(3,4)]) >>> l.add([geom.Point(5,6)]) >>> l.add([geom.Point(7,8)]) >>> l.add([geom.Point(9,10)]) >>> c = l.cursor() >>> f = c.next() >>> f.geom POINT (1 2) >>> f = c.next() >>> f.geom POINT (3 4) >>> features = c.read(2) >>> len(features) 2 >>> features[0].geom POINT (5 6) >>> features[1].geom POINT (7 8) >>> features = c.read(2) >>> len(features) 1 >>> features[0].geom POINT (9 10) >>> c.close() """ f = Filter(filter) if filter else Filter.PASS q = DefaultQuery(self.name, f._filter) if sort: sort = sort if isinstance(sort, list) else [sort] sortBy = [] ff = _filterFactory for s in sort: s = s if isinstance(s, tuple) else [s, 'ASC'] sortBy.append(ff.sort(s[0], SortOrder.valueOf(s[1]))) q.setSortBy(sortBy) if self.proj: q.coordinateSystem = self.proj._crs if hints is not None: q.setHints(Hints(hints)) fcol = self._source.getFeatures(q) #r = self._source.dataStore.getFeatureReader(q,Transaction.AUTO_COMMIT) return Cursor(fcol, self)
def _filter(self, filter): if filter is None: return self.filter if self.filter is None: return filter return self.filter + Filter(filter)
def filter(self, fil, name=None): """ Filters the layer. *fil* is the :class:`Filter <geoscript.filter.Filter>` to apply. *name* is the optional name to assign to the new filtered layer. This method returns a newly filtered layer. The new layer is create within the containing workspace of the original layer. >>> from geoscript.feature import Schema >>> l = Layer(schema=Schema('original', [('name', str)])) >>> l.add(['foo']) >>> l.add(['bar']) >>> l.add(['baz']) >>> >>> l2 = l.filter("name = 'foo'", "filtered") >>> l2.count() 1 >>> l3 = l.filter("name LIKE 'b%'", "filtered2") >>> l3.count() 2 """ f = Filter(fil) name = name or Layer._newname() fschema = feature.Schema(name, self.schema.fields) # create the filtered layer flayer = self.workspace.create(schema=fschema) q = DefaultQuery(self.name, f._filter) # loop through features and add to new filtered layer fit = self._source.getFeatures(q).features() try: while fit.hasNext(): f = feature.Feature(schema=fschema, f=fit.next()) flayer.add(f) finally: fit.close() return flayer
def bounds(self, filter=None): """ The :class:`Bounds <geoscript.geom.Bounds>` of the layer. *filter* is an optional :class:`Filter <geoscript.filter.Filter>` to constrains the returned bounds. >>> l = Layer() >>> from geoscript import geom >>> l.add([geom.Point(1.0, 2.0)]) >>> l.add([geom.Point(3.0, 4.0)]) >>> l.bounds() (1.0, 2.0, 3.0, 4.0, EPSG:4326) >>> l.bounds('INTERSECTS(geom,POINT(3 4))') (3.0, 4.0, 3.0, 4.0, EPSG:4326) """ f = Filter(filter) if filter else Filter.PASS q = DefaultQuery(self.name, f._filter) e = self._source.getBounds(q) if not e: # try through feature collection fc = self._source.getFeatures(q) e = fc.getBounds() if e: if e.crs(): return geom.Bounds(env=e) else: return geom.Bounds(env=e, prj=self.proj) else: # calculate manually fit = self._source.getFeatures(q).features() try: bounds = geom.Bounds(prj=self.proj) if fit.hasNext(): bounds.init(fit.next().getBounds()) while fit.hasNext(): bounds.expland(fit.next().getBounds()) return bounds finally: fit.close()
def delete(self, filter): """ Deletes features from the layer which match the specified constraint. *filter* is a :class:`Filter <geoscript.filter.Filter>` that specifies which features are to be deleted. >>> l = Layer() >>> from geoscript import geom >>> l.add([geom.Point(1,2)]) >>> l.add([geom.Point(3,4)]) >>> l.count() 2 >>> l.delete('INTERSECTS(geom, POINT(3 4))') >>> l.count() 1 """ f = Filter(filter) if filter else Filter.FAIL self._source.removeFeatures(f._filter)
def cursor(self, filter=None): """ Returns a :class:`Cursor <geoscript.layer.cursor.Cursor>` over the features of the layer. *filter* is a optional :class:`Filter <geoscript.filter.Filter>` to constrain the features iterated over. >>> l = Layer() >>> from geoscript import geom >>> l.add([geom.Point(1,2)]) >>> l.add([geom.Point(3,4)]) >>> l.add([geom.Point(5,6)]) >>> l.add([geom.Point(7,8)]) >>> l.add([geom.Point(9,10)]) >>> c = l.cursor() >>> f = c.next() >>> f.geom POINT (1 2) >>> f = c.next() >>> f.geom POINT (3 4) >>> features = c.read(2) >>> len(features) 2 >>> features[0].geom POINT (5 6) >>> features[1].geom POINT (7 8) >>> features = c.read(2) >>> len(features) 1 >>> features[0].geom POINT (9 10) >>> c.close() """ f = Filter(filter) if filter else Filter.PASS q = DefaultQuery(self.name, f._filter) if self.proj: q.coordinateSystem = self.proj._crs r = self._source.dataStore.getFeatureReader(q, Transaction.AUTO_COMMIT) return Cursor(r, self)
def bounds(self, filter=None): """ The :class:`Bounds <geoscript.geom.Bounds>` of the layer. *filter* is an optional :class:`Filter <geoscript.filter.Filter>` to constrains the returned bounds. >>> l = Layer() >>> from geoscript import geom >>> l.add([geom.Point(1.0, 2.0)]) >>> l.add([geom.Point(3.0, 4.0)]) >>> l.bounds() (1.0, 2.0, 3.0, 4.0) >>> l.bounds('INTERSECTS(geom,POINT(3 4))') (3.0, 4.0, 3.0, 4.0) """ f = Filter(filter) if filter else Filter.PASS e = self._source.getBounds(DefaultQuery(self.name, f._filter)) if e: return geom.Bounds(env=e)
def __init__(self, layer, filter=None): self.layer = layer self.filter = None if filter is None else Filter(filter)