示例#1
0
    def testAttributeMap(self):
        # start with a feature with no fields
        f = QgsFeature()
        f.setAttributes([1, 'a', NULL])
        with self.assertRaises(ValueError):
            _ = f.attributeMap()

        # set fields
        fields = QgsFields()
        field1 = QgsField('my_field')
        fields.append(field1)
        field2 = QgsField('my_field2')
        fields.append(field2)
        field3 = QgsField('my_field3')
        fields.append(field3)
        f.setFields(fields)
        f.setAttributes([1, 'a', NULL])
        self.assertEqual(f.attributeMap(), {'my_field': 1, 'my_field2': 'a', 'my_field3': NULL})

        # unbalanced fields/attributes -- should be handled gracefully
        # less attributes than fields
        f.setAttributes([1, 'a'])
        with self.assertRaises(ValueError):
            _ = f.attributeMap()
        f.setAttributes([1, 'a', 2, 3])
        # more attributes than fields
        with self.assertRaises(ValueError):
            _ = f.attributeMap()
示例#2
0
 def test_AddAttribute(self):
     feat = QgsFeature()
     feat.addAttribute(1, "text")
     myCount = len(feat.attributeMap())
     myExpectedCount = 1
     myMessage = '\nExpected: %s\nGot: %s' % (myExpectedCount, myCount)
     assert myCount == myExpectedCount, myMessage        
示例#3
0
 def gotFeatureForIdentification(self, pos):
     """Show a dialog with road information """
     #pos is a rectangle
     self.mem_layer_obj.select()
     ftr = QgsFeature()
     ftr_ids = []
     while self.mem_layer_obj.nextFeature(ftr):
         if ftr.geometry().intersects(pos):
             ftr_ids.append(ftr.id())
     self.chosenFOIGeoms = []
     self.info = QgsMessageViewer()
     if ftr_ids != []:
         f = QgsFeature()
         foi_type = self.foi_type.lower()
         if foi_type == 'areaofinterestdefiner':
             ftrData = "You have selected the following feature(s) for use as an Area of Interest:\n\n"
         if foi_type == 'lineofinterestdefiner':
             ftrData = "You have selected the following feature(s) for use as a Line of Interest:\n\n"
         if foi_type == 'pointofinterestdefiner':
             ftrData = "You have selected the following feature(s) for use as a Point of Interest:\n\n"
         for fid in ftr_ids:
             self.mem_layer_obj.dataProvider().featureAtId(fid, f,  True)
             ftrData += f.attributeMap()[0].toString()
             ftrData += "\n_____________________________\n"
             self.chosenFOIGeoms.append(f.geometry())
             id_fid = self.addGeomToMemoryLayer(f.geometry())
         self.info.setMessageAsPlainText(ftrData)
     else:
         self.info.setMessageAsPlainText("no data to show")
     self.info.show()
     return
示例#4
0
def layer_multifields_stats(layer, fields):
    """ return value distribution for field in given vector layer """
    provider = layer.dataProvider()
    if provider is None:
        return False
    # retrieve index for all fields
    f_indices = []
    for field in fields:
        idx = layer_field_index(layer, field)
        if idx == -1:
            return False
        f_indices.append(idx)

    f = QgsFeature()
    stats = {}
    provider.select(f_indices, provider.extent())
    provider.rewind()
    for _idx in range(provider.featureCount()):
        provider.nextFeature(f)
        # create compound key
        _key = ''
        for idx in f_indices:
            if _key != '':
                _key = _key + '_'
            _key += str(f.attributeMap()[idx].toString()).upper()
        # update stats based on compound key
        if stats.has_key(_key):
            stats[_key] += 1
        else:
            stats[_key] = 1
    return stats
示例#5
0
 def test_AddAttribute(self):
     feat = QgsFeature()
     feat.addAttribute(1, "text")
     myCount = len(feat.attributeMap())
     myExpectedCount = 1
     myMessage = '\nExpected: %s\nGot: %s' % (myExpectedCount, myCount)
     assert myCount == myExpectedCount, myMessage
示例#6
0
def layer_multifields_stats(layer, fields):
    """ return value distribution for field in given vector layer """
    provider = layer.dataProvider()
    if provider is None:
        return False
    # retrieve index for all fields
    f_indices = []
    for field in fields:
        idx = layer_field_index(layer, field)
        if idx == -1:
            return False
        f_indices.append(idx)
        
    f = QgsFeature()
    stats = {}
    provider.select(f_indices, provider.extent())
    provider.rewind()
    for _idx in range(provider.featureCount()):
        provider.nextFeature(f)
        # create compound key
        _key = ''
        for idx in f_indices:
            if _key != '':
                _key = _key + '_'
            _key += str(f.attributeMap()[idx].toString()).upper()
        # update stats based on compound key
        if stats.has_key(_key):
            stats[_key]+=1
        else:
            stats[_key]=1
    return stats
    def testAddFeatures(self):
        layer = QgsVectorLayer("Point", "test", "memory")
        provider = layer.dataProvider()

        res = provider.addAttributes([
            QgsField(
                "name",
                QVariant.String,
            ),
            QgsField("age", QVariant.Int),
            QgsField("size", QVariant.Double)
        ])
        assert res, "Failed to add attributes"

        myMessage = ('Expected: %s\nGot: %s\n' % (3, provider.fieldCount()))

        assert provider.fieldCount() == 3, myMessage

        ft = QgsFeature()
        ft.setGeometry(QgsGeometry.fromPoint(QgsPoint(10, 10)))
        ft.setAttributeMap({
            0: QVariant("Johny"),
            1: QVariant(20),
            2: QVariant(0.3)
        })
        res, t = provider.addFeatures([ft])

        assert res, "Failed to add feature"

        myMessage = ('Expected: %s\nGot: %s\n' % (1, provider.featureCount()))
        assert provider.featureCount() == 1, myMessage

        f = QgsFeature()
        provider.select()
        while provider.nextFeature(f):
            attrMap = f.attributeMap()
            myMessage = ('Expected: %s\nGot: %s\n' %
                         ("Johny", str(attrMap[0].toString())))

            assert str(attrMap[0].toString()) == "Johny", myMessage

            myMessage = ('Expected: %s\nGot: %s\n' %
                         (20, attrMap[1].toInt()[0]))

            assert attrMap[1].toInt()[0] == 20, myMessage

            myMessage = ('Expected: %s\nGot: %s\n' %
                         (0.3, attrMap[2].toFloat()[0]))

            assert (attrMap[0].toFloat()[0] - 0.3) < 0.0000001, myMessage

            geom = f.geometry()

            myMessage = (
                'Expected: %s\nGot: %s\n' %
                ("POINT(10.000000 10.000000)", str(geom.exportToWkt())))

            assert str(
                geom.exportToWkt()) == "POINT(10.000000 10.000000)", myMessage
示例#8
0
 def test_ChangeAttribute(self):
     feat = QgsFeature()
     feat.addAttribute(1, "text")
     feat.changeAttribute(1, "changed")
     myChangedAttribute = feat.attributeMap()[1].toString()
     myExpectedAttribute = "changed"
     myMessage = '\nExpected: %s\nGot: %s' % (myExpectedAttribute, 
         myChangedAttribute)
     assert myChangedAttribute == myExpectedAttribute, myMessage        
示例#9
0
 def test_ChangeAttribute(self):
     feat = QgsFeature()
     feat.addAttribute(1, "text")
     feat.changeAttribute(1, "changed")
     myChangedAttribute = feat.attributeMap()[1].toString()
     myExpectedAttribute = "changed"
     myMessage = '\nExpected: %s\nGot: %s' % (myExpectedAttribute,
                                              myChangedAttribute)
     assert myChangedAttribute == myExpectedAttribute, myMessage
示例#10
0
    @pyqtSlot(QPoint, QObject)
    def showInfo(self, point, mouseButton):
        """
        event handler for toolInfo
        @see QGIS tutorial for detail
        point-polygon search on currently selected layer  
        """
        cur_layer_name = self.ui.cb_layer_selector.currentText()
        if cur_layer_name.isEmpty():
            return
        try:
            cur_layer_idx = self.LAYER_NAMES.index(cur_layer_name)
            cur_layer = self.map_layers[cur_layer_idx]
            
            # if layer is not in same projection as map canvas
            # need to project query point
            if cur_layer.crs() != self.canvas.mapRenderer().destinationCrs():
                transform = QgsCoordinateTransform(self.canvas.mapRenderer().destinationCrs(), cur_layer.crs())
                point = transform.transform(point)
            
            # do query
            provider = cur_layer.dataProvider() 
            provider.rewind()
            feature = QgsFeature()
            colonIndexes = provider.attributeIndexes()
        
            # search using point as center of rectangle polygon
            search_buffer_x = self.canvas.extent().width() * self.SEARCH_BUFFER / self.canvas.width()
            search_buffer_y = self.canvas.extent().height() * self.SEARCH_BUFFER / self.canvas.height()
            provider.select(colonIndexes,
                            QgsRectangle(point.x()-search_buffer_x,
                                         point.y()-search_buffer_y,
                                         point.x()+search_buffer_x,
                                         point.y()+search_buffer_y),
                            True)
            # get selected and display in result detail dialog box 
            selected = []        
            while provider.nextFeature(feature):            
                # for polygons, only show geometry containing query point            
                if cur_layer.geometryType() == QGis.Polygon:                
                    if feature.geometry() is not None and not feature.geometry().contains (point):
                        continue
                selected.append(feature.attributeMap())

            if len(selected)>0:
                # display result if exists
                if cur_layer_idx == self.EXPOSURE:
                    self.dlgResultDetail.showExposureData(provider.fields(), selected)                    
                else:
                    self.dlgResultDetail.showInfoData(provider.fields(), selected)
                self.dlgResultDetail.exec_()
            else:
                logUICall.log(get_ui_string("widget.result.info.notfound"), logUICall.WARNING)
        except Exception as err:
            # point-in-polygon search is not critical, continue on error 
示例#11
0
    def testAddFeatures(self):
        layer = QgsVectorLayer("Point", "test", "memory")
        provider = layer.dataProvider()

        res = provider.addAttributes([QgsField("name", QVariant.String,),
                                      QgsField("age",  QVariant.Int),
                                      QgsField("size", QVariant.Double)])
        assert res, "Failed to add attributes"

        myMessage = ('Expected: %s\nGot: %s\n' %
                      (3, provider.fieldCount()))

        assert provider.fieldCount() == 3, myMessage

        ft = QgsFeature()
        ft.setGeometry(QgsGeometry.fromPoint(QgsPoint(10,10)))
        ft.setAttributeMap({0 : QVariant("Johny"),
                            1 : QVariant(20),
                            2 : QVariant(0.3)})
        res, t = provider.addFeatures([ft])

        assert res, "Failed to add feature"

        myMessage = ('Expected: %s\nGot: %s\n' %
                      (1, provider.featureCount()))
        assert provider.featureCount() == 1, myMessage

        f = QgsFeature()
        provider.select()
        while provider.nextFeature(f):
            attrMap = f.attributeMap()
            myMessage = ('Expected: %s\nGot: %s\n' %
                        ("Johny", str(attrMap[0].toString())))

            assert str(attrMap[0].toString()) == "Johny", myMessage

            myMessage = ('Expected: %s\nGot: %s\n' %
                        (20, attrMap[1].toInt()[0]))

            assert attrMap[1].toInt()[0] == 20, myMessage

            myMessage = ('Expected: %s\nGot: %s\n' %
                        (0.3, attrMap[2].toFloat()[0]))

            assert (attrMap[0].toFloat()[0] - 0.3) < 0.0000001, myMessage

            geom = f.geometry()

            myMessage = ('Expected: %s\nGot: %s\n' %
                        ("POINT(10.0 10.0)", str(geom.exportToWkt())))

            assert str(geom.exportToWkt()) == "POINT(10.0 10.0)", myMessage
示例#12
0
    def testLocalCities(self):
        """Test that we can retrieve the cities local to the event"""
        myShakeId = '20120726022003'
        myShakeEvent = ShakeEvent(myShakeId)
        # Get teh mem layer
        myCitiesLayer = myShakeEvent.localCitiesMemoryLayer()
        myProvider = myCitiesLayer.dataProvider()

        myFeature = QgsFeature()
        myAttributes = myProvider.attributeIndexes()
        myProvider.select(myAttributes)
        myExpectedFeatureCount = 6
        self.assertEquals(myProvider.featureCount(), myExpectedFeatureCount)
        myStrings = []
        while myProvider.nextFeature(myFeature):
            # fetch map of attributes
            myAttributes = myFeature.attributeMap()
            for (myKey, myValue) in myAttributes.iteritems():
                myStrings.append("%d: %s\n" % (myKey, myValue.toString()))
            myStrings.append('------------------\n')
        LOGGER.debug('Mem table:\n %s' % myStrings)
        myFilePath = unique_filename(prefix='testLocalCities',
                                     suffix='.txt',
                                     dir=temp_dir('test'))
        myFile = file(myFilePath, 'wt')
        myFile.writelines(myStrings)
        myFile.close()

        myFixturePath = os.path.join(dataDir(), 'tests', 'testLocalCities.txt')
        myFile = file(myFixturePath, 'rt')
        myExpectedString = myFile.readlines()
        myFile.close()

        myDiff = difflib.unified_diff(myStrings, myExpectedString)
        myDiffList = list(myDiff)
        myDiffString = ''
        for _, myLine in enumerate(myDiffList):
            myDiffString += myLine

        myMessage = ('Diff is not zero length:\n'
                     'Control file: %s\n'
                     'Test file: %s\n'
                     'Diff:\n%s'
                     % (myFixturePath,
                        myFilePath,
                        myDiffString))
        self.assertEqual(myDiffString, '', myMessage)
示例#13
0
	def do_dbf_import(self):
		""" last step: create table and import data """
		
		QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))

		tablename = unicode(self.field("tablename").toString())
		pkey = unicode(self.field("pkey").toString())
		if pkey == "(none)": pkey = None
		
		try:
			# create the table
			self.db.create_table(tablename, self.dbf_fields, pkey)
			
			cursor = self.db.con.cursor()
				
			# now let's get the features and import them to database
			pr = self.vlayer.dataProvider()
			flds = pr.fields()
			pr.enableGeometrylessFeatures(True)
			pr.select(pr.attributeIndexes(), QgsRectangle(), False) # all attrs, no geometry
			f = QgsFeature()
			while pr.nextFeature(f):
				attrs = f.attributeMap()
				values = []
				for (i,val) in attrs.iteritems():
					vartype = flds[i].type()
					if val.isNull():
						values.append("NULL")
					elif vartype == QVariant.Int:
						values.append(str(val.toInt()[0]))
					elif vartype == QVariant.Double:
						values.append(str(val.toDouble()[0]))
					else: # string or something else
						values.append("'%s'" % str(val.toString().toUtf8()).replace("'","''").replace("\\", "\\\\"))
				self.db.insert_table_row(tablename, values, None, cursor)
				
			# commit changes to DB
			self.db.con.commit()

		except postgis_utils.DbError, e:
			QApplication.restoreOverrideCursor()
			
			DlgDbError.showError(e, self)
			return False
示例#14
0
    def _aggregate(self, myImpactLayer, myExpectedResults):
        myAggregationLayer = QgsVectorLayer(
            os.path.join(BOUNDDATA, 'kabupaten_jakarta.shp'),
            'test aggregation',
            'ogr')
        # create a copy of aggregation layer
        myGeoExtent = extent_to_geo_array(
            myAggregationLayer.extent(),
            myAggregationLayer.crs())

        myAggrAttribute = self.keywordIO.read_keywords(
            myAggregationLayer, self.defaults['AGGR_ATTR_KEY'])
        # noinspection PyArgumentEqualDefault
        myAggregationLayer = clip_layer(
            layer=myAggregationLayer,
            extent=myGeoExtent,
            explode_flag=True,
            explode_attribute=myAggrAttribute)

        myAggregator = Aggregator(None, myAggregationLayer)
        # setting up
        myAggregator.isValid = True
        myAggregator.layer = myAggregationLayer
        myAggregator.safeLayer = safe_read_layer(
            str(myAggregator.layer.source()))
        myAggregator.aoiMode = False
        myAggregator.aggregate(myImpactLayer)

        myProvider = myAggregator.layer.dataProvider()
        myProvider.select(myProvider.attributeIndexes())
        myFeature = QgsFeature()
        myResults = []

        while myProvider.nextFeature(myFeature):
            myFeatureResults = {}
            myAtMap = myFeature.attributeMap()
            for (k, attr) in myAtMap.iteritems():
                myFeatureResults[k] = str(attr.toString())
            myResults.append(myFeatureResults)

        self.assertEqual(myExpectedResults, myResults)
示例#15
0
 def test_AttributeMap(self):
     myPath = os.path.join(unitTestDataPath(), 'lines.shp')
     myLayer = QgsVectorLayer(myPath, 'Lines', 'ogr')
     provider = myLayer.dataProvider()
     allAttrs = provider.attributeIndexes()
     provider.select(allAttrs)
     feat = QgsFeature()
     provider.nextFeature(feat)
     
     myAttributeMap = feat.attributeMap()
     myExpectedAttributeMap = {0: QVariant("Highway"), 1: QVariant(1)}
     
     # Only for printing purposes 
     myAttributeDict = {
         0:str(myAttributeMap[0].toString()),
         1:int(myAttributeMap[1].toString())}
     myExpectedAttributeDict = {0: "Highway", 1: 1}
     myMessage = '\nExpected: %s\nGot: %s' % (myExpectedAttributeDict, 
         myAttributeDict)
         
     assert myAttributeMap == myExpectedAttributeMap, myMessage
示例#16
0
    def test_AttributeMap(self):
        myPath = os.path.join(unitTestDataPath(), 'lines.shp')
        myLayer = QgsVectorLayer(myPath, 'Lines', 'ogr')
        provider = myLayer.dataProvider()
        allAttrs = provider.attributeIndexes()
        provider.select(allAttrs)
        feat = QgsFeature()
        provider.nextFeature(feat)

        myAttributeMap = feat.attributeMap()
        myExpectedAttributeMap = {0: QVariant("Highway"), 1: QVariant(1)}

        # Only for printing purposes
        myAttributeDict = {
            0: str(myAttributeMap[0].toString()),
            1: int(myAttributeMap[1].toString())
        }
        myExpectedAttributeDict = {0: "Highway", 1: 1}
        myMessage = '\nExpected: %s\nGot: %s' % (myExpectedAttributeDict,
                                                 myAttributeDict)

        assert myAttributeMap == myExpectedAttributeMap, myMessage
    def addActivitiesFromLayer(self):
        """
        """

        def _createNewActivity(id=None, otherActivity=None):

            # Connect to the protocol signal
            self.connect(self.activityProtocol, SIGNAL("created( bool, int, QString )"), _createNewActivityFinished)

            # Create a new Uuid
            if id is not None:
                uid = QPlainUuid(id)
            else:
                uid = QPlainUuid(QUuid.createUuid())

            tagGroups = list(TagGroup() for i in range(len(groups)))

            # attrs is a dictionary: key = field index, value = QgsFeatureAttribute
            # show all attributes and their values
            self.log("Attribute list:")
            for (k, attr) in attrs.iteritems():
                if k is not identifierColumnIndex:
                    self.log("%s: %s" % (fieldIndexMap[k], attr.toString()))

                    # First search the correct taggroup to append
                    attributeName = provider.fields()[k].name()
                    currentTagGroup = 0
                    for g in groups:
                        if attributeName in g:
                            break
                        else:
                            currentTagGroup += 1

                    if attr is not None and attr.toString() != '':
                        tag = Tag(key=fieldIndexMap[k], value=attr.toString())
                        tagGroups[currentTagGroup].addTag(tag)
                        if tagGroups[currentTagGroup].mainTag() is None:
                            tagGroups[currentTagGroup].setMainTag(tag)

            a = Activity(id=uid)
            a.setGeometry(feature.geometry())
            for tg in tagGroups:
                if len(tg.tags) > 0:
                    a.addTagGroup(tg)

            wrapperObj = {}

            wrapperObj['activities'] = [a.createDiff(otherActivity)]

            self.activityProtocol.add(json.dumps(wrapperObj, sort_keys=True, indent=4 * ' '))


        def _createNewActivityFinished(success, statusCode, response):

            # Connect to the protocol signal
            self.disconnect(self.activityProtocol, SIGNAL("created( bool, int, QString )"), _createNewActivityFinished)

            # The newly returned activity should be parsed and the ID needs to
            # be written to the QgsFeature

            self.log("Server returned status code %i and response:\n%s" % (statusCode, response))

        def _checkActivityExists(uid):

            self.connect(self.activityProtocol, SIGNAL("readSignal( bool, int, QString )"), _checkActivityExistsFinished)

            self.activityProtocol.readById(uid.toString())
            self.log("Check if activity exists:")

        def _checkActivityExistsFinished(success, statusCode, response):

            self.disconnect(self.activityProtocol, SIGNAL("readSignal( bool, int, QString )"), _checkActivityExistsFinished)

            self.log("Server returned status code %i and response:\n%s" % (statusCode, response))

            activities = self.parseActivitiesResponse(response)
            if len(activities) == 0:
                self.log("Activity does not yet exist")
                _createNewActivity(uid)

            #else:
                #   _createNewActivity(uid, activities[0])


        # Get the dict that maps the attribute names from the landmatrix input Shapefile to the
        # fields defined in the global definition yaml
        identifierColumn, transformMap, groups = self.getTagGroupsConfiguration("landmatrix.activity.ini")

        # Get the active layer and its data provider
        layer = self.iface.activeLayer()
        provider = layer.dataProvider()

        # The current feature
        feature = QgsFeature()

        # List of attribute indexes to select
        attributeIndexes = []
        # Dict that maps the field index to the fields defined in the global YAML
        fieldIndexMap = {}

        # Find the index of the uuid column
        identifierColumnIndex = None

        for (i, field) in provider.fields().iteritems():
            if str(field.name()) in transformMap:
                attributeIndexes.append(i)
                fieldIndexMap[i] = transformMap[str(field.name())]
            elif field.name() == str(identifierColumn):
                identifierColumnIndex = i


        # Start data retreival: fetch geometry and necessary attributes for each feature
        provider.select(attributeIndexes + [identifierColumnIndex])

        # retreive every feature with its geometry and attributes
        while provider.nextFeature(feature):

            
            # fetch map of attributes
            attrs = feature.attributeMap()

            # Get the identifier value
            identifierValue = attrs[identifierColumnIndex].toString()

            # If the identifier is empty or None, create a new activity.
            # This should only be necessary at the initial imports
            if identifierValue is None or str(identifierValue) == str(''):
                _createNewActivity()

            #if str(idenitfierValue).contains(QRegExp('a0c78834-fd98-4d4d-b8b5-0754b50f2510'))
            else:
                uid = QPlainUuid(identifierValue)
                _checkActivityExists(uid)
示例#18
0
    def run(self):
        """Run any post processors requested by the impact function.

        Args:
            None

        Returns:
            None

        Raises:
            None
        """
        try:
            myRequestedPostProcessors = self.functionParams['postprocessors']
            myPostProcessors = get_postprocessors(myRequestedPostProcessors)
        except (TypeError, KeyError):
            # TypeError is for when functionParams is none
            # KeyError is for when ['postprocessors'] is unavailable
            myPostProcessors = {}
        LOGGER.debug('Running this postprocessors: ' + str(myPostProcessors))

        myFeatureNameAttribute = self.aggregator.attributes[
            self.aggregator.defaults['AGGR_ATTR_KEY']]
        if myFeatureNameAttribute is None:
            self.attributeTitle = self.tr('Aggregation unit')
        else:
            self.attributeTitle = myFeatureNameAttribute

        myNameFieldIndex = self.aggregator.layer.fieldNameIndex(
            self.attributeTitle)
        mySumFieldIndex = self.aggregator.layer.fieldNameIndex(
            self._sumFieldName())

        myFemaleRatioIsVariable = False
        myFemRatioFieldIndex = None
        myFemaleRatio = None

        if 'Gender' in myPostProcessors:
            #look if we need to look for a variable female ratio in a layer
            try:
                myFemRatioField = self.aggregator.attributes[
                    self.aggregator.defaults['FEM_RATIO_ATTR_KEY']]
                myFemRatioFieldIndex = self.aggregator.layer.fieldNameIndex(
                    myFemRatioField)
                myFemaleRatioIsVariable = True

            except KeyError:
                try:
                    myFemaleRatio = self.keywordIO.read_keywords(
                        self.aggregator.layer,
                        self.aggregator.defaults['FEM_RATIO_KEY'])
                except KeywordNotFoundError:
                    myFemaleRatio = self.aggregator.defaults['FEM_RATIO']

        #iterate zone features
        myProvider = self.aggregator.layer.dataProvider()
        myAttributes = myProvider.attributeIndexes()
        # start data retreival: fetch no geometry and all attributes for each
        # feature
        myProvider.select(myAttributes, QgsRectangle(), False)
        myFeature = QgsFeature()
        myPolygonIndex = 0
        while myProvider.nextFeature(myFeature):
            #get all attributes of a feature
            myAttributeMap = myFeature.attributeMap()

            #if a feature has no field called
            if myNameFieldIndex == -1:
                myZoneName = str(myFeature.id())
            else:
                myZoneName = myAttributeMap[myNameFieldIndex].toString()

            #create dictionary of attributes to pass to postprocessor
            myGeneralParams = {'target_field': self.aggregator.targetField}

            if self.aggregator.statisticsType == 'class_count':
                myGeneralParams['impact_classes'] = (
                    self.aggregator.statisticsClasses)
            elif self.aggregator.statisticsType == 'sum':
                myImpactTotal, _ = myAttributeMap[mySumFieldIndex].toDouble()
                myGeneralParams['impact_total'] = myImpactTotal

            try:
                myGeneralParams['impact_attrs'] = (
                    self.aggregator.impactLayerAttributes[myPolygonIndex])
            except IndexError:
                #rasters and attributeless vectors have no attributes
                myGeneralParams['impact_attrs'] = None

            for myKey, myValue in myPostProcessors.iteritems():
                myParameters = myGeneralParams
                try:
                    #look if params are available for this postprocessor
                    myParameters.update(
                        self.functionParams['postprocessors'][myKey]['params'])
                except KeyError:
                    pass

                if myKey == 'Gender':
                    if myFemaleRatioIsVariable:
                        myFemaleRatio, mySuccessFlag = myAttributeMap[
                            myFemRatioFieldIndex].toDouble()
                        if not mySuccessFlag:
                            myFemaleRatio = self.aggregator.defaults[
                                'FEM_RATIO']
                        LOGGER.debug(mySuccessFlag)
                    myParameters['female_ratio'] = myFemaleRatio

                myValue.setup(myParameters)
                myValue.process()
                myResults = myValue.results()
                myValue.clear()
                #                LOGGER.debug(myResults)
                try:
                    self.postProcessingOutput[myKey].append(
                        (myZoneName, myResults))
                except KeyError:
                    self.postProcessingOutput[myKey] = []
                    self.postProcessingOutput[myKey].append(
                        (myZoneName, myResults))
            #increment the index
            myPolygonIndex += 1
示例#19
0
    def run(self):
        """Run any post processors requested by the impact function.

        Args:
            None

        Returns:
            None

        Raises:
            None
        """
        try:
            myRequestedPostProcessors = self.functionParams['postprocessors']
            myPostProcessors = get_postprocessors(myRequestedPostProcessors)
        except (TypeError, KeyError):
            # TypeError is for when functionParams is none
            # KeyError is for when ['postprocessors'] is unavailable
            myPostProcessors = {}
        LOGGER.debug('Running this postprocessors: ' + str(myPostProcessors))

        myFeatureNameAttribute = self.aggregator.attributes[
            self.aggregator.defaults['AGGR_ATTR_KEY']]
        if myFeatureNameAttribute is None:
            self.attributeTitle = self.tr('Aggregation unit')
        else:
            self.attributeTitle = myFeatureNameAttribute

        myNameFieldIndex = self.aggregator.layer.fieldNameIndex(
            self.attributeTitle)
        mySumFieldIndex = self.aggregator.layer.fieldNameIndex(
            self._sumFieldName())

        myFemaleRatioIsVariable = False
        myFemRatioFieldIndex = None
        myFemaleRatio = None

        if 'Gender' in myPostProcessors:
            #look if we need to look for a variable female ratio in a layer
            try:
                myFemRatioField = self.aggregator.attributes[
                    self.aggregator.defaults['FEM_RATIO_ATTR_KEY']]
                myFemRatioFieldIndex = self.aggregator.layer.fieldNameIndex(
                    myFemRatioField)
                myFemaleRatioIsVariable = True

            except KeyError:
                try:
                    myFemaleRatio = self.keywordIO.read_keywords(
                        self.aggregator.layer,
                        self.aggregator.defaults['FEM_RATIO_KEY'])
                except KeywordNotFoundError:
                    myFemaleRatio = self.aggregator.defaults['FEM_RATIO']

        #iterate zone features
        myProvider = self.aggregator.layer.dataProvider()
        myAttributes = myProvider.attributeIndexes()
        # start data retreival: fetch no geometry and all attributes for each
        # feature
        myProvider.select(myAttributes, QgsRectangle(), False)
        myFeature = QgsFeature()
        myPolygonIndex = 0
        while myProvider.nextFeature(myFeature):
            #get all attributes of a feature
            myAttributeMap = myFeature.attributeMap()

            #if a feature has no field called
            if myNameFieldIndex == -1:
                myZoneName = str(myFeature.id())
            else:
                myZoneName = myAttributeMap[myNameFieldIndex].toString()

            #create dictionary of attributes to pass to postprocessor
            myGeneralParams = {'target_field': self.aggregator.targetField}

            if self.aggregator.statisticsType == 'class_count':
                myGeneralParams['impact_classes'] = (
                    self.aggregator.statisticsClasses)
            elif self.aggregator.statisticsType == 'sum':
                myImpactTotal, _ = myAttributeMap[mySumFieldIndex].toDouble()
                myGeneralParams['impact_total'] = myImpactTotal

            try:
                myGeneralParams['impact_attrs'] = (
                    self.aggregator.impactLayerAttributes[myPolygonIndex])
            except IndexError:
                #rasters and attributeless vectors have no attributes
                myGeneralParams['impact_attrs'] = None

            for myKey, myValue in myPostProcessors.iteritems():
                myParameters = myGeneralParams
                try:
                    #look if params are available for this postprocessor
                    myParameters.update(
                        self.functionParams['postprocessors'][myKey]['params'])
                except KeyError:
                    pass

                if myKey == 'Gender':
                    if myFemaleRatioIsVariable:
                        myFemaleRatio, mySuccessFlag = myAttributeMap[
                            myFemRatioFieldIndex].toDouble()
                        if not mySuccessFlag:
                            myFemaleRatio = self.aggregator.defaults[
                                'FEM_RATIO']
                        LOGGER.debug(mySuccessFlag)
                    myParameters['female_ratio'] = myFemaleRatio

                myValue.setup(myParameters)
                myValue.process()
                myResults = myValue.results()
                myValue.clear()
#                LOGGER.debug(myResults)
                try:
                    self.postProcessingOutput[myKey].append(
                        (myZoneName, myResults))
                except KeyError:
                    self.postProcessingOutput[myKey] = []
                    self.postProcessingOutput[myKey].append(
                        (myZoneName, myResults))
            #increment the index
            myPolygonIndex += 1
示例#20
0
def _clip_vector_layer(
        layer,
        extent,
        extra_keywords=None,
        explode_flag=True,
        hard_clip_flag=False,
        explode_attribute=None):
    """Clip a Hazard or Exposure layer to the extents provided.

    The layer must be a vector layer or an exception will be thrown.

    The output layer will always be in WGS84/Geographic.

    :param layer: A valid QGIS vector or raster layer
    :type layer:

    :param extent: Either an array representing the exposure layer extents
        in the form [xmin, ymin, xmax, ymax]. It is assumed that the
        coordinates are in EPSG:4326 although currently no checks are made to
        enforce this.
        or:
        A QgsGeometry of type polygon.
        **Polygon clipping is currently only supported for vector datasets.**
    :type extent: list(float, float, float, float)

    :param extra_keywords: Optional keywords dictionary to be added to
        output layer.
    :type extra_keywords: dict

    :param explode_flag: A bool specifying whether multipart features
        should be 'exploded' into singleparts.
        **This parameter is ignored for raster layer clipping.**
    :type explode_flag: bool

    :param hard_clip_flag: A bool specifying whether line and polygon
        features that extend beyond the extents should be clipped such that
        they are reduced in size to the part of the geometry that intersects
        the extent only. Default is False.
        **This parameter is ignored for raster layer clipping.**
    :type hard_clip_flag: bool

    :param explode_attribute: A str specifying to which attribute #1,
        #2 and so on will be added in case of explode_flag being true. The
        attribute is modified only if there are at least 2 parts.
    :type explode_attribute: str

    :returns: Clipped layer (placed in the system temp dir). The output layer
        will be reprojected to EPSG:4326 if needed.
    :rtype: QgsVectorLayer

    """
    if not layer or not extent:
        myMessage = tr('Layer or Extent passed to clip is None.')
        raise InvalidParameterError(myMessage)

    if layer.type() != QgsMapLayer.VectorLayer:
        myMessage = tr('Expected a vector layer but received a %s.' %
                       str(layer.type()))
        raise InvalidParameterError(myMessage)

    #myHandle, myFilename = tempfile.mkstemp('.sqlite', 'clip_',
    #    temp_dir())
    myHandle, myFilename = tempfile.mkstemp('.shp', 'clip_',
                                            temp_dir())

    # Ensure the file is deleted before we try to write to it
    # fixes windows specific issue where you get a message like this
    # ERROR 1: c:\temp\inasafe\clip_jpxjnt.shp is not a directory.
    # This is because mkstemp creates the file handle and leaves
    # the file open.
    os.close(myHandle)
    os.remove(myFilename)

    # Get the clip extents in the layer's native CRS
    myGeoCrs = QgsCoordinateReferenceSystem()
    myGeoCrs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId)
    myXForm = QgsCoordinateTransform(myGeoCrs, layer.crs())
    myAllowedClipTypes = [QGis.WKBPolygon, QGis.WKBPolygon25D]
    if type(extent) is list:
        myRect = QgsRectangle(
            extent[0], extent[1],
            extent[2], extent[3])
        # noinspection PyCallByClass
        myClipPolygon = QgsGeometry.fromRect(myRect)
    elif (type(extent) is QgsGeometry and
          extent.wkbType in myAllowedClipTypes):
        myRect = extent.boundingBox().toRectF()
        myClipPolygon = extent
    else:
        raise InvalidClipGeometryError(
            tr(
                'Clip geometry must be an extent or a single part'
                'polygon based geometry.'))

    myProjectedExtent = myXForm.transformBoundingBox(myRect)

    # Get vector layer
    myProvider = layer.dataProvider()
    if myProvider is None:
        myMessage = tr('Could not obtain data provider from '
                       'layer "%s"' % layer.source())
        raise Exception(myMessage)

    # Get the layer field list, select by our extent then write to disk
    # .. todo:: FIXME - for different geometry types we should implement
    #    different clipping behaviour e.g. reject polygons that
    #    intersect the edge of the bbox. Tim
    myAttributes = myProvider.attributeIndexes()
    myFetchGeometryFlag = True
    myUseIntersectFlag = True
    myProvider.select(
        myAttributes,
        myProjectedExtent,
        myFetchGeometryFlag,
        myUseIntersectFlag)

    myFieldList = myProvider.fields()

    myWriter = QgsVectorFileWriter(
        myFilename,
        'UTF-8',
        myFieldList,
        layer.wkbType(),
        myGeoCrs,
        #'SQLite')  # FIXME (Ole): This works but is far too slow
        'ESRI Shapefile')
    if myWriter.hasError() != QgsVectorFileWriter.NoError:
        myMessage = tr('Error when creating shapefile: <br>Filename:'
                       '%s<br>Error: %s' %
                       (myFilename, myWriter.hasError()))
        raise Exception(myMessage)

    # Reverse the coordinate xform now so that we can convert
    # geometries from layer crs to geocrs.
    myXForm = QgsCoordinateTransform(layer.crs(), myGeoCrs)
    # Retrieve every feature with its geometry and attributes
    myFeature = QgsFeature()
    myCount = 0
    myHasMultipart = False

    if explode_attribute is not None:
        theExplodeAttributeIndex = myProvider.fieldNameIndex(
            explode_attribute)

    while myProvider.nextFeature(myFeature):
        myGeometry = myFeature.geometry()
        if explode_attribute is not None:
            myAttrs = myFeature.attributeMap()
        # Loop through the parts adding them to the output file
        # we write out single part features unless explode_flag is False
        if explode_flag:
            myGeometryList = explode_multipart_geometry(myGeometry)
        else:
            myGeometryList = [myGeometry]

        for myPartIndex, myPart in enumerate(myGeometryList):
            myPart.transform(myXForm)
            if hard_clip_flag:
                # Remove any dangling bits so only intersecting area is
                # kept.
                myPart = clip_geometry(myClipPolygon, myPart)
            if myPart is None:
                continue

            myFeature.setGeometry(myPart)
            # There are multiple parts and we want to show it in the
            # explode_attribute
            if myPartIndex > 0 and explode_attribute is not None:
                myHasMultipart = True
                myPartAttr = QVariant(
                    '%s #%s' % (myAttrs[theExplodeAttributeIndex].toString(),
                                myPartIndex))
                myFeature.changeAttribute(theExplodeAttributeIndex, myPartAttr)

            myWriter.addFeature(myFeature)
        myCount += 1
    del myWriter  # Flush to disk

    if myCount < 1:
        myMessage = tr(
            'No features fall within the clip extents. Try panning / zooming '
            'to an area containing data and then try to run your analysis '
            'again. If hazard and exposure data doesn\'t overlap at all, it '
            'is not possible to do an analysis. Another possibility is that '
            'the layers do overlap but because they may have different '
            'spatial references, they appear to be disjointed. If this is the '
            'case, try to turn on reproject on-the-fly in QGIS.')
        raise NoFeaturesInExtentError(myMessage)

    myKeywordIO = KeywordIO()
    if extra_keywords is None:
        extra_keywords = {}
    extra_keywords['HAD_MULTIPART_POLY'] = myHasMultipart
    myKeywordIO.copy_keywords(
        layer, myFilename, extra_keywords=extra_keywords)
    myBaseName = '%s clipped' % layer.name()
    myLayer = QgsVectorLayer(myFilename, myBaseName, 'ogr')

    return myLayer
    def addStakeholdersFromLayer(self):
        """
        Import all stakeholders from the active layer to the Land Observatory
        platform.
        It is not (yet) tested if a stakeholder already exists or not.
        """

        # Connect to the protocol to get noticed as soon as the stakeholder has
        # been created
        self.connect(self.stakeholderProtocol, SIGNAL("created( bool, int, QString"), self.addStakeholdersFinished)

        # Get the dict maps the attribute names from the landmatrix input Shapefile to the
        # fields defined in the global definition yaml
        identifierColumn, transformMap, groups = self.getTagGroupsConfiguration("landmatrix.stakeholder.ini")

        # Get the active layer and its data provider
        layer = self.iface.activeLayer()
        provider = layer.dataProvider()

        # The current feature
        feature = QgsFeature()

        # List of attribute indexes to select
        attributeIndexes = []
        # Dict that maps the field index to the fields defined in the global YAML
        fieldIndexMap = {}
        for (i, field) in provider.fields().iteritems():
            if str(field.name()) in transformMap:
                attributeIndexes.append(i)
                fieldIndexMap[i] = transformMap[str(field.name())]

        # Start data retreival: fetch geometry and necessary attributes for each feature
        provider.select(attributeIndexes)

        stakeholders = []

        # retreive every feature with its geometry and attributes
        while provider.nextFeature(feature):

            tagGroups = list(TagGroup() for i in range(len(groups)))

            # fetch map of attributes
            attrs = feature.attributeMap()

            # attrs is a dictionary: key = field index, value = QgsFeatureAttribute
            # show all attributes and their values
            for (k, attr) in attrs.iteritems():
                self.log("%s: %s" % (fieldIndexMap[k], attr.toString()))

                # First search the correct taggroup to append
                attributeName = provider.fields()[k].name()
                currentTagGroup = 0
                for g in groups:
                    if attributeName in g:
                        break
                    else:
                        currentTagGroup += 1

                if attr is not None and attr.toString() != '':
                    tag = Tag(key=fieldIndexMap[k], value=attr.toString())
                    tagGroups[currentTagGroup].addTag(tag)
                    if tagGroups[currentTagGroup].mainTag() is None:
                        tagGroups[currentTagGroup].setMainTag(tag)

            s = Stakeholder()
            for tg in tagGroups:
                if len(tg.tags) > 0:
                    s.addTagGroup(tg)

            stakeholders.append(s)

        msg, rawBody = self.stakeholderProtocol.add(stakeholders)
        self.log(msg)
        self.log(rawBody)

        # Disconnect the signal
        self.disconnect(self.stakeholderProtocol, SIGNAL("created( bool, int, QString"), self.addStakeholdersFinished)
    def processing(self):
        #check edit mode
        if not self.active_layer.isEditable():
            QMessageBox.warning(self, self.tr("FieldPyculator warning"),
                                 self.tr("Layer is not in edit mode! Please start editing the layer!"))
            return    
        
        start =  datetime.datetime.now()
        new_ns = {}
        
        #run global code
        if self.ui.grpGlobalExpression.isChecked():
            try:
                code = unicode(self.ui.txtGlobalExp.toPlainText())
                bytecode = compile(code, '<string>', 'exec')
                exec bytecode in new_ns
            except:
                QMessageBox.critical(self, self.tr("FieldPyculator code execute error"),
                            (self.tr("Global code block can't be executed!\n%1: %2"))
                            .arg(unicode(sys.exc_info()[0].__name__))
                            .arg(unicode(sys.exc_info()[1])))
                return
            
        
        code = unicode(self.ui.txtFieldExp.toPlainText())
        
        #TODO: check 'result' existing in text of code???!!!
            
        #replace all fields tags
        field_map = self.data_provider.fields()
        for num, field in field_map.iteritems():
            field_name = unicode(field.name())
            replval = '__attr[' + str(num) + ']'
            code = code.replace("<"+field_name+">", replval)

        #replace all special vars
        code = code.replace('$id', '__id')
        code = code.replace('$geom', '__geom')
        #is it need: $area, $length, $x, $y????

        #print code #debug

        #search needed vars (hmmm... comments?!)
        need_id = code.find("__id") != -1
        need_geom = code.find("__geom") != -1
        need_attrs = code.find("__attr") != -1


        #compile
        try:
            bytecode = compile(code, '<string>', 'exec')
        except:
            QMessageBox.critical(self, self.tr("FieldPyculator code execute error"),
                                 self.tr("Field code block can't be executed!\n%1: %2")
                                 .arg(unicode(sys.exc_info()[0].__name__))
                                 .arg(unicode(sys.exc_info()[1])))
            return
        
        
        #get num of updating field
        field_num = self.data_provider.fieldNameIndex(self.ui.cmbUpdateField.currentText())
        
        #setup progress bar       
        self.ui.prgTotal.setValue(0)
        
        #run
        if not self.ui.chkOnlySelected.isChecked():
            #select all features
            features_for_update = self.data_provider.featureCount()
            if  features_for_update > 0:
                self.ui.prgTotal.setMaximum(features_for_update)
            
            feat = QgsFeature()
            if need_attrs:
                attr_ind = self.data_provider.attributeIndexes()
            else:
                attr_ind = []
            self.data_provider.select(attr_ind, QgsRectangle(), need_geom)
            
            while self.data_provider.nextFeature( feat ):
                feat_id = feat.id()
                
                #add needed vars
                if need_id:
                    new_ns['__id'] = feat_id

                if need_geom:
                    geom = feat.geometry()
                    new_ns['__geom'] = geom

                if need_attrs:
                    attr_map = feat.attributeMap()
                    attr = []
                    for num, a in attr_map.iteritems():
                        attr.append(self.qvar2py(a))
                    new_ns['__attr'] = attr
                
                #clear old result
                if new_ns.has_key(self.RESULT_VAR_NAME):
                    del new_ns[self.RESULT_VAR_NAME]
                
                #exec
                try:
                    exec bytecode in new_ns
                except:
                    QMessageBox.critical(self, self.tr("FieldPyculator code execute error"),
                            self.tr("Field code block can't be executed for feature %3!\n%1: %2")
                            .arg(unicode(sys.exc_info()[0].__name__))
                            .arg(unicode(sys.exc_info()[1]))
                            .arg(unicode(feat_id)))
                    return
                
                #check result
                if not new_ns.has_key(self.RESULT_VAR_NAME):
                    QMessageBox.critical(self, self.tr("FieldPyculator code execute error"),
                            self.tr("Field code block does not return '%1' variable! Please declare this variable in your code!")
                            .arg(self.RESULT_VAR_NAME))
                    return
                
                #try assign
                try:
                    self.active_layer.changeAttributeValue(feat_id, field_num, new_ns[self.RESULT_VAR_NAME])
                except:
                    QMessageBox.critical(self, self.tr("FieldPyculator code execute error"),
                            self.tr("Result value can't be assigned to the feature %3!\n%1: %2")
                            .arg(unicode(sys.exc_info()[0].__name__))
                            .arg(unicode(sys.exc_info()[1]))
                            .arg(unicode(feat_id)))
                    return

                self.ui.prgTotal.setValue(self.ui.prgTotal.value()+1)

        else:
            #only selected (TODO: NEED REFACTORING - copy-past!!!)
            features_for_update = self.active_layer.selectedFeatureCount()
            if features_for_update > 0:
                self.ui.prgTotal.setMaximum(features_for_update)

            for feat in self.active_layer.selectedFeatures():
                feat_id = feat.id()

                #add needed vars
                if need_id:
                    new_ns['__id'] = feat_id

                if need_geom:
                    geom = feat.geometry()
                    new_ns['__geom'] = geom

                if need_attrs:
                    attr_map = feat.attributeMap()
                    attr = []
                    for num, a in attr_map.iteritems():
                        attr.append(self.qvar2py(a))
                    new_ns['__attr'] = attr

                #clear old result
                if new_ns.has_key(self.RESULT_VAR_NAME):
                    del new_ns[self.RESULT_VAR_NAME]

                #exec
                try:
                    exec bytecode in new_ns
                except:
                    QMessageBox.critical(self, self.tr("FieldPyculator code execute error"),
                            self.tr("Field code block can't be executed for feature %3!\n%1: %2")
                            .arg(unicode(sys.exc_info()[0].__name__))
                            .arg(unicode(sys.exc_info()[1]))
                            .arg(unicode(feat_id)))
                    return

                #check result
                if not new_ns.has_key(self.RESULT_VAR_NAME):
                    QMessageBox.critical(self, self.tr("FieldPyculator code execute error"),
                            self.tr("Field code block does not return '%1' variable! Please declare this variable in your code!")
                            .arg(self.RESULT_VAR_NAME))
                    return

                #try assign
                try:
                    self.active_layer.changeAttributeValue(feat_id, field_num, new_ns[self.RESULT_VAR_NAME])
                except:
                    QMessageBox.critical(self, self.tr("FieldPyculator code execute error"),
                            self.tr("Result value can't be assigned to the feature %3!\n%1: %2")
                            .arg(unicode(sys.exc_info()[0].__name__))
                            .arg(unicode(sys.exc_info()[1]))
                            .arg(unicode(feat_id)))
                    return

                self.ui.prgTotal.setValue(self.ui.prgTotal.value()+1)

        stop = datetime.datetime.now()

        #workaround for python < 2.7
        td = stop - start
        if sys.version_info[:2] < (2, 7):
            total_sec = (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
        else:
            total_sec = td.total_seconds()

        QMessageBox.information(self, self.tr("FieldPyculator code executed successfully"),
                         self.tr("Updated %1 features for %2 seconds")
                            .arg(unicode(features_for_update))
                            .arg(unicode(total_sec))
                         )
示例#23
0
    def showInfo(self, point, mouseButton):
        """
        event handler for toolInfo
        @see QGIS tutorial for detail
        point-polygon search on currently selected layer  
        """
        cur_layer_name = self.ui.cb_layer_selector.currentText()
        if cur_layer_name.isEmpty():
            return
        try:
            cur_layer_idx = self.LAYER_NAMES.index(cur_layer_name)
            cur_layer = self.map_layers[cur_layer_idx]

            # if layer is not in same projection as map canvas
            # need to project query point
            if cur_layer.crs() != self.canvas.mapRenderer().destinationCrs():
                transform = QgsCoordinateTransform(
                    self.canvas.mapRenderer().destinationCrs(),
                    cur_layer.crs())
                point = transform.transform(point)

            # do query
            provider = cur_layer.dataProvider()
            provider.rewind()
            feature = QgsFeature()
            colonIndexes = provider.attributeIndexes()

            # search using point as center of rectangle polygon
            search_buffer_x = self.canvas.extent().width(
            ) * self.SEARCH_BUFFER / self.canvas.width()
            search_buffer_y = self.canvas.extent().height(
            ) * self.SEARCH_BUFFER / self.canvas.height()
            provider.select(
                colonIndexes,
                QgsRectangle(point.x() - search_buffer_x,
                             point.y() - search_buffer_y,
                             point.x() + search_buffer_x,
                             point.y() + search_buffer_y), True)
            # get selected and display in result detail dialog box
            selected = []
            while provider.nextFeature(feature):
                # for polygons, only show geometry containing query point
                if cur_layer.geometryType() == QGis.Polygon:
                    if feature.geometry(
                    ) is not None and not feature.geometry().contains(point):
                        continue
                selected.append(feature.attributeMap())

            if len(selected) > 0:
                # display result if exists
                if cur_layer_idx == self.EXPOSURE:
                    self.dlgResultDetail.showExposureData(
                        provider.fields(), selected)
                else:
                    self.dlgResultDetail.showInfoData(provider.fields(),
                                                      selected)
                self.dlgResultDetail.exec_()
            else:
                logUICall.log(get_ui_string("widget.result.info.notfound"),
                              logUICall.WARNING)
        except Exception as err:
            # point-in-polygon search is not critical, continue on error
            logUICall.log(str(err), logUICall.WARNING)
示例#24
0
def _clip_vector_layer(
        layer,
        extent,
        extra_keywords=None,
        explode_flag=True,
        hard_clip_flag=False,
        explode_attribute=None):
    """Clip a Hazard or Exposure layer to the extents provided.

    The layer must be a vector layer or an exception will be thrown.

    The output layer will always be in WGS84/Geographic.

    :param layer: A valid QGIS vector or raster layer
    :type layer:

    :param extent: Either an array representing the exposure layer extents
        in the form [xmin, ymin, xmax, ymax]. It is assumed that the
        coordinates are in EPSG:4326 although currently no checks are made to
        enforce this.
        or:
        A QgsGeometry of type polygon.
        **Polygon clipping is currently only supported for vector datasets.**
    :type extent: list(float, float, float, float)

    :param extra_keywords: Optional keywords dictionary to be added to
        output layer.
    :type extra_keywords: dict

    :param explode_flag: A bool specifying whether multipart features
        should be 'exploded' into singleparts.
        **This parameter is ignored for raster layer clipping.**
    :type explode_flag: bool

    :param hard_clip_flag: A bool specifying whether line and polygon
        features that extend beyond the extents should be clipped such that
        they are reduced in size to the part of the geometry that intersects
        the extent only. Default is False.
        **This parameter is ignored for raster layer clipping.**
    :type hard_clip_flag: bool

    :param explode_attribute: A str specifying to which attribute #1,
        #2 and so on will be added in case of explode_flag being true. The
        attribute is modified only if there are at least 2 parts.
    :type explode_attribute: str

    :returns: Clipped layer (placed in the system temp dir). The output layer
        will be reprojected to EPSG:4326 if needed.
    :rtype: QgsVectorLayer

    """
    if not layer or not extent:
        myMessage = tr('Layer or Extent passed to clip is None.')
        raise InvalidParameterError(myMessage)

    if layer.type() != QgsMapLayer.VectorLayer:
        myMessage = tr('Expected a vector layer but received a %s.' %
                       str(layer.type()))
        raise InvalidParameterError(myMessage)

    #myHandle, myFilename = tempfile.mkstemp('.sqlite', 'clip_',
    #    temp_dir())
    myHandle, myFilename = tempfile.mkstemp('.shp', 'clip_',
                                            temp_dir())

    # Ensure the file is deleted before we try to write to it
    # fixes windows specific issue where you get a message like this
    # ERROR 1: c:\temp\inasafe\clip_jpxjnt.shp is not a directory.
    # This is because mkstemp creates the file handle and leaves
    # the file open.
    os.close(myHandle)
    os.remove(myFilename)

    # Get the clip extents in the layer's native CRS
    myGeoCrs = QgsCoordinateReferenceSystem()
    myGeoCrs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId)
    myXForm = QgsCoordinateTransform(myGeoCrs, layer.crs())
    myAllowedClipTypes = [QGis.WKBPolygon, QGis.WKBPolygon25D]
    if type(extent) is list:
        myRect = QgsRectangle(
            extent[0], extent[1],
            extent[2], extent[3])
        # noinspection PyCallByClass
        myClipPolygon = QgsGeometry.fromRect(myRect)
    elif (type(extent) is QgsGeometry and
          extent.wkbType in myAllowedClipTypes):
        myRect = extent.boundingBox().toRectF()
        myClipPolygon = extent
    else:
        raise InvalidClipGeometryError(
            tr(
                'Clip geometry must be an extent or a single part'
                'polygon based geometry.'))

    myProjectedExtent = myXForm.transformBoundingBox(myRect)

    # Get vector layer
    myProvider = layer.dataProvider()
    if myProvider is None:
        myMessage = tr('Could not obtain data provider from '
                       'layer "%s"' % layer.source())
        raise Exception(myMessage)

    # Get the layer field list, select by our extent then write to disk
    # .. todo:: FIXME - for different geometry types we should implement
    #    different clipping behaviour e.g. reject polygons that
    #    intersect the edge of the bbox. Tim
    myAttributes = myProvider.attributeIndexes()
    myFetchGeometryFlag = True
    myUseIntersectFlag = True
    myProvider.select(
        myAttributes,
        myProjectedExtent,
        myFetchGeometryFlag,
        myUseIntersectFlag)

    myFieldList = myProvider.fields()

    myWriter = QgsVectorFileWriter(
        myFilename,
        'UTF-8',
        myFieldList,
        layer.wkbType(),
        myGeoCrs,
        #'SQLite')  # FIXME (Ole): This works but is far too slow
        'ESRI Shapefile')
    if myWriter.hasError() != QgsVectorFileWriter.NoError:
        myMessage = tr('Error when creating shapefile: <br>Filename:'
                       '%s<br>Error: %s' %
                       (myFilename, myWriter.hasError()))
        raise Exception(myMessage)

    # Reverse the coordinate xform now so that we can convert
    # geometries from layer crs to geocrs.
    myXForm = QgsCoordinateTransform(layer.crs(), myGeoCrs)
    # Retrieve every feature with its geometry and attributes
    myFeature = QgsFeature()
    myCount = 0
    myHasMultipart = False

    if explode_attribute is not None:
        theExplodeAttributeIndex = myProvider.fieldNameIndex(
            explode_attribute)

    while myProvider.nextFeature(myFeature):
        myGeometry = myFeature.geometry()
        if explode_attribute is not None:
            myAttrs = myFeature.attributeMap()
        # Loop through the parts adding them to the output file
        # we write out single part features unless explode_flag is False
        if explode_flag:
            myGeometryList = explode_multipart_geometry(myGeometry)
        else:
            myGeometryList = [myGeometry]

        for myPartIndex, myPart in enumerate(myGeometryList):
            myPart.transform(myXForm)
            if hard_clip_flag:
                # Remove any dangling bits so only intersecting area is
                # kept.
                myPart = clip_geometry(myClipPolygon, myPart)
            if myPart is None:
                continue

            myFeature.setGeometry(myPart)
            # There are multiple parts and we want to show it in the
            # explode_attribute
            if myPartIndex > 0 and explode_attribute is not None:
                myHasMultipart = True
                myPartAttr = QVariant(
                    '%s #%s' % (myAttrs[theExplodeAttributeIndex].toString(),
                                myPartIndex))
                myFeature.changeAttribute(theExplodeAttributeIndex, myPartAttr)

            myWriter.addFeature(myFeature)
        myCount += 1
    del myWriter  # Flush to disk

    if myCount < 1:
        myMessage = tr(
            'No features fall within the clip extents. Try panning / zooming '
            'to an area containing data and then try to run your analysis '
            'again. If hazard and exposure data doesn\'t overlap at all, it '
            'is not possible to do an analysis. Another possibility is that '
            'the layers do overlap but because they may have different '
            'spatial references, they appear to be disjointed. If this is the '
            'case, try to turn on reproject on-the-fly in QGIS.')
        raise NoFeaturesInExtentError(myMessage)

    myKeywordIO = KeywordIO()
    if extra_keywords is None:
        extra_keywords = {}
    extra_keywords['HAD_MULTIPART_POLY'] = myHasMultipart
    myKeywordIO.copy_keywords(
        layer, myFilename, extra_keywords=extra_keywords)
    myBaseName = '%s clipped' % layer.name()
    myLayer = QgsVectorLayer(myFilename, myBaseName, 'ogr')

    return myLayer
示例#25
0
    def testClipping(self):
        """Test that we can clip geometries using other geometries."""
        myMemoryLayer = QgsVectorLayer(
            ('LineString?crs=epsg:4326&field=name:string(20)&index=yes'),
            'clip-in',
            'memory')

        assert myMemoryLayer is not None, 'Provider not initialised'
        myProvider = myMemoryLayer.dataProvider()
        assert myProvider is not None

        myFeature1 = QgsFeature()
        myFeature1.setGeometry(QgsGeometry.fromPolyline([
            QgsPoint(10,10),
            QgsPoint(20,10),
            QgsPoint(30,10),
            QgsPoint(40,10),
            ]
        ))
        myFeature1.setAttributeMap({0 : QVariant('Johny')})

        myFeature2 = QgsFeature()
        myFeature2.setGeometry(QgsGeometry.fromPolyline([
            QgsPoint(10,10),
            QgsPoint(20,20),
            QgsPoint(30,30),
            QgsPoint(40,40),
            ]
        ))
        myFeature2.setAttributeMap({0 : QVariant('Be')})

        myFeature3 = QgsFeature()
        myFeature3.setGeometry(QgsGeometry.fromPolyline([
            QgsPoint(10,10),
            QgsPoint(10,20),
            QgsPoint(10,30),
            QgsPoint(10,40),
            ]
        ))

        myFeature3.setAttributeMap({0 : QVariant('Good')})

        myResult, myFeatures = myProvider.addFeatures(
            [myFeature1, myFeature2, myFeature3])
        assert myResult == True
        assert len(myFeatures) == 3

        myClipPolygon = QgsGeometry.fromPolygon([[
            QgsPoint(20,20),
            QgsPoint(20,30),
            QgsPoint(30,30),
            QgsPoint(30,20),
            QgsPoint(20,20),
            ]]
        )
        print 'Clip: %s' % myClipPolygon.exportToWkt()
        writeShape(myMemoryLayer, 'clipGeometryBefore.shp')
        myProvider.rewind()
        myProvider.select(myProvider.attributeIndexes())
        myFeatures = []
        myFeature = QgsFeature()
        while myProvider.nextFeature(myFeature):
            myGeometry = myFeature.geometry()
            if myGeometry.intersects(myClipPolygon):
                # Adds nodes where the clip and the line intersec
                myCombinedGeometry = myGeometry.combine(myClipPolygon)
                # Gives you the areas inside the clip
                mySymmetricalGeometry = myGeometry.symDifference(
                    myCombinedGeometry)
                # Gives you areas outside the clip area
                # myDifferenceGeometry = myCombinedGeometry.difference(
                #    myClipPolygon)
                #print 'Original: %s' % myGeometry.exportToWkt()
                #print 'Combined: %s' % myCombinedGeometry.exportToWkt()
                #print 'Difference: %s' % myDifferenceGeometry.exportToWkt()
                print 'Symmetrical: %s' % mySymmetricalGeometry.exportToWkt()

                myExpectedWkt = 'LINESTRING(20.0 20.0, 30.0 30.0)'
                # There should only be one feature that intersects this clip
                # poly so this assertion should work.
                self.assertEqual(myExpectedWkt,
                                 mySymmetricalGeometry.exportToWkt())

                myNewFeature = QgsFeature()
                myNewFeature.setAttributeMap(myFeature.attributeMap())
                myNewFeature.setGeometry(mySymmetricalGeometry)
                myFeatures.append(myNewFeature)

        myNewMemoryLayer = QgsVectorLayer(
            ('LineString?crs=epsg:4326&field=name:string(20)&index=yes'),
            'clip-out',
            'memory')
        myNewProvider = myNewMemoryLayer.dataProvider()
        myResult, myFeatures = myNewProvider.addFeatures(myFeatures)
        self.assertTrue(myResult)
        self.assertEqual(len(myFeatures), 1)
        myNewMemoryLayer.commitChanges()

        writeShape(myNewMemoryLayer, 'clipGeometryAfter.shp')
示例#26
0
    def _preparePolygonLayer(self, theQgisLayer):
        """Create a new layer with no intersecting features to self.layer.

        A helper function to align the polygons to the postprocLayer
        polygons. If one input polygon is in two or more postprocLayer polygons
        then it is divided so that each part is within only one of the
        postprocLayer polygons. this allows to aggregate in postrocessing using
        centroid in polygon.

        The function assumes EPSG:4326 but no checks are enforced

        Args:
            theQgisLayer of the file to be processed
        Returns:
            QgisLayer of the processed file

        Raises:
            Any exceptions raised by the InaSAFE library will be propagated.
        """
#        import time
#        startTime = time.clock()

        myMessage = m.Message(
            m.Heading(self.tr('Preclipping input data...')),
            m.Paragraph(self.tr(
                'Modifying %1 to avoid intersections with the aggregation '
                'layer'
            ).arg(theQgisLayer.name())))
        self._sendMessage(myMessage)

        theLayerFilename = str(theQgisLayer.source())
        myPostprocPolygons = self.safeLayer.get_geometry()
        myPolygonsLayer = safe_read_layer(theLayerFilename)
        myRemainingPolygons = numpy.array(myPolygonsLayer.get_geometry())
#        myRemainingAttributes = numpy.array(myPolygonsLayer.get_data())
        myRemainingIndexes = numpy.array(range(len(myRemainingPolygons)))

        #used for unit tests only
        self.preprocessedFeatureCount = 0

        # FIXME (MB) the intersecting array is used only for debugging and
        # could be safely removed
        myIntersectingPolygons = []
        myInsidePolygons = []

        # FIXME (MB) maybe do raw geos without qgis
        #select all postproc polygons with no attributes
        aggregationProvider = self.layer.dataProvider()
        aggregationProvider.select([])

        # copy polygons to a memory layer
        myQgisMemoryLayer = create_memory_layer(theQgisLayer)

        polygonsProvider = myQgisMemoryLayer.dataProvider()
        allPolygonAttrs = polygonsProvider.attributeIndexes()
        polygonsProvider.select(allPolygonAttrs)
        myQgisPostprocPoly = QgsFeature()
        myQgisFeat = QgsFeature()
        myInsideFeat = QgsFeature()
        fields = polygonsProvider.fields()
        myTempdir = temp_dir(sub_dir='preprocess')
        myOutFilename = unique_filename(suffix='.shp',
                                        dir=myTempdir)

        self.keywordIO.copy_keywords(theQgisLayer, myOutFilename)
        mySHPWriter = QgsVectorFileWriter(myOutFilename,
                                          'UTF-8',
                                          fields,
                                          polygonsProvider.geometryType(),
                                          polygonsProvider.crs())
        if mySHPWriter.hasError():
            raise InvalidParameterError(mySHPWriter.errorMessage())
        # end FIXME

        for (myPostprocPolygonIndex,
             myPostprocPolygon) in enumerate(myPostprocPolygons):
            LOGGER.debug('PostprocPolygon %s' % myPostprocPolygonIndex)
            myPolygonsCount = len(myRemainingPolygons)
            aggregationProvider.featureAtId(
                myPostprocPolygonIndex, myQgisPostprocPoly, True, [])
            myQgisPostprocGeom = QgsGeometry(myQgisPostprocPoly.geometry())

            # myPostprocPolygon bounding box values
            A = numpy.array(myPostprocPolygon)
            minx = miny = sys.maxint
            maxx = maxy = -minx
            myPostprocPolygonMinx = min(minx, min(A[:, 0]))
            myPostprocPolygonMaxx = max(maxx, max(A[:, 0]))
            myPostprocPolygonMiny = min(miny, min(A[:, 1]))
            myPostprocPolygonMaxy = max(maxy, max(A[:, 1]))

            # create an array full of False to store if a BB vertex is inside
            # or outside the myPostprocPolygon
            myAreVerticesInside = numpy.zeros(myPolygonsCount * 4,
                                              dtype=numpy.bool)

            # Create Nx2 vector of vertices of bounding boxes
            myBBVertices = []
            # Compute bounding box for each geometry type
            for myPoly in myRemainingPolygons:
                minx = miny = sys.maxint
                maxx = maxy = -minx
                # Do outer ring only as the BB is outside anyway
                A = numpy.array(myPoly)
                minx = min(minx, numpy.min(A[:, 0]))
                maxx = max(maxx, numpy.max(A[:, 0]))
                miny = min(miny, numpy.min(A[:, 1]))
                maxy = max(maxy, numpy.max(A[:, 1]))
                myBBVertices.extend([(minx, miny),
                                    (minx, maxy),
                                    (maxx, maxy),
                                    (maxx, miny)])

            # see if BB vertices are in myPostprocPolygon
            myBBVertices = numpy.array(myBBVertices)
            inside, _ = points_in_and_outside_polygon(myBBVertices,
                                                      myPostprocPolygon)
            # make True if the vertice was in myPostprocPolygon
            myAreVerticesInside[inside] = True

            # myNextIterPolygons has the 0:count indexes
            # myOutsidePolygons has the mapped to original indexes
            # and is overwritten at every iteration because we care only of
            # the outside polygons remaining after the last iteration
            myNextIterPolygons = []
            myOutsidePolygons = []

            for i in range(myPolygonsCount):
                k = i * 4
                myMappedIndex = myRemainingIndexes[i]
                # memory layers counting starts at 1 instead of 0 as in our
                # indexes
                myFeatId = myMappedIndex + 1
                doIntersection = False
                # summ the isInside bool for each of the boundingbox vertices
                # of each poygon. for example True + True + False + True is 3
                myPolygonLocation = numpy.sum(myAreVerticesInside[k:k + 4])

                if myPolygonLocation == 4:
                    # all vertices are inside -> polygon is inside
                    #ignore this polygon from further analysis
                    myInsidePolygons.append(myMappedIndex)
                    polygonsProvider.featureAtId(myFeatId,
                                                 myQgisFeat,
                                                 True,
                                                 allPolygonAttrs)
                    mySHPWriter.addFeature(myQgisFeat)
                    self.preprocessedFeatureCount += 1
#                    LOGGER.debug('Polygon %s is fully inside' %myMappedIndex)
#                    tmpWriter.addFeature(myQgisFeat)

                elif myPolygonLocation == 0:
                    # all vertices are outside
                    # check if the polygon BB is completely outside of the
                    # myPostprocPolygon BB.
                    myPolyMinx = numpy.min(myBBVertices[k:k + 4, 0])
                    myPolyMaxx = numpy.max(myBBVertices[k:k + 4, 0])
                    myPolyMiny = numpy.min(myBBVertices[k:k + 4, 1])
                    myPolyMaxy = numpy.max(myBBVertices[k:k + 4, 1])

                    # check if myPoly is all E,W,N,S of myPostprocPolygon
                    if ((myPolyMinx > myPostprocPolygonMaxx) or
                            (myPolyMaxx < myPostprocPolygonMinx) or
                            (myPolyMiny > myPostprocPolygonMaxy) or
                            (myPolyMaxy < myPostprocPolygonMiny)):
                        #polygon is surely outside
                        myOutsidePolygons.append(myMappedIndex)
                        # we need this polygon in the next iteration
                        myNextIterPolygons.append(i)
                    else:
                        # polygon might be outside or intersecting. consider
                        # it intersecting so it goes into further analysis
                        doIntersection = True
                else:
                    # some vertices are outside some inside -> polygon is
                    # intersecting
                    doIntersection = True

                #intersect using qgis
                if doIntersection:
#                    LOGGER.debug('Intersecting polygon %s' % myMappedIndex)
                    myIntersectingPolygons.append(myMappedIndex)

                    ok = polygonsProvider.featureAtId(myFeatId,
                                                      myQgisFeat,
                                                      True,
                                                      allPolygonAttrs)
                    if not ok:
                        LOGGER.debug('Couldn\'t fetch feature: %s' % myFeatId)
                        LOGGER.debug([str(error) for error in
                                      polygonsProvider.errors()])

                    myQgisPolyGeom = QgsGeometry(myQgisFeat.geometry())
                    myAtMap = myQgisFeat.attributeMap()
#                    for (k, attr) in myAtMap.iteritems():
#                        LOGGER.debug( "%d: %s" % (k, attr.toString()))

                    # make intersection of the myQgisFeat and the postprocPoly
                    # write the inside part to a shp file and the outside part
                    # back to the original QGIS layer
                    try:
                        myIntersec = myQgisPostprocGeom.intersection(
                            myQgisPolyGeom)
#                        if myIntersec is not None:
                        myIntersecGeom = QgsGeometry(myIntersec)

                        #from ftools
                        myUnknownGeomType = 0
                        if myIntersecGeom.wkbType() == myUnknownGeomType:
                            int_com = myQgisPostprocGeom.combine(
                                myQgisPolyGeom)
                            int_sym = myQgisPostprocGeom.symDifference(
                                myQgisPolyGeom)
                            myIntersecGeom = QgsGeometry(
                                int_com.difference(int_sym))
#                        LOGGER.debug('wkbType type of intersection: %s' %
# myIntersecGeom.wkbType())
                        polygonTypesList = [QGis.WKBPolygon,
                                            QGis.WKBMultiPolygon]
                        if myIntersecGeom.wkbType() in polygonTypesList:
                            myInsideFeat.setGeometry(myIntersecGeom)
                            myInsideFeat.setAttributeMap(myAtMap)
                            mySHPWriter.addFeature(myInsideFeat)
                            self.preprocessedFeatureCount += 1
                        else:
                            pass
#                            LOGGER.debug('Intersection not a polygon so '
#                                         'the two polygons either touch '
#                                         'only or do not intersect. Not '
#                                         'adding this to the inside list')
                        #Part of the polygon that is outside the postprocpoly
                        myOutside = myQgisPolyGeom.difference(myIntersecGeom)
#                        if myOutside is not None:
                        myOutsideGeom = QgsGeometry(myOutside)

                        if myOutsideGeom.wkbType() in polygonTypesList:
                            # modifiy the original geometry to the part
                            # outside of the postproc polygon
                            polygonsProvider.changeGeometryValues(
                                {myFeatId: myOutsideGeom})
                            # we need this polygon in the next iteration
                            myOutsidePolygons.append(myMappedIndex)
                            myNextIterPolygons.append(i)

                    except TypeError:
                        LOGGER.debug('ERROR with FID %s', myMappedIndex)

#            LOGGER.debug('Inside %s' % myInsidePolygons)
#            LOGGER.debug('Outside %s' % myOutsidePolygons)
#            LOGGER.debug('Intersec %s' % myIntersectingPolygons)
            if len(myNextIterPolygons) > 0:
                #some polygons are still completely outside of the postprocPoly
                #so go on and reiterate using only these
                nextIterPolygonsIndex = numpy.array(myNextIterPolygons)

                myRemainingPolygons = myRemainingPolygons[
                    nextIterPolygonsIndex]
#                myRemainingAttributes = myRemainingAttributes[
#                                        nextIterPolygonsIndex]
                myRemainingIndexes = myRemainingIndexes[nextIterPolygonsIndex]
                LOGGER.debug('Remaining: %s' % len(myRemainingPolygons))
            else:
                print 'no more polygons to be checked'
                break
#            del tmpWriter

        # here the full polygon set is represented by:
        # myInsidePolygons + myIntersectingPolygons + myNextIterPolygons
        # the a polygon intersecting multiple postproc polygons appears
        # multiple times in the array
        # noinspection PyUnboundLocalVariable
        LOGGER.debug('Results:\nInside: %s\nIntersect: %s\nOutside: %s' % (
            myInsidePolygons, myIntersectingPolygons, myOutsidePolygons))

        #add in- and outside polygons

        for i in myOutsidePolygons:
            myFeatId = i + 1
            polygonsProvider.featureAtId(myFeatId, myQgisFeat, True,
                                         allPolygonAttrs)
            mySHPWriter.addFeature(myQgisFeat)
            self.preprocessedFeatureCount += 1

        del mySHPWriter
#        LOGGER.debug('Created: %s' % self.preprocessedFeatureCount)

        myName = '%s %s' % (theQgisLayer.name(), self.tr('preprocessed'))
        myOutLayer = QgsVectorLayer(myOutFilename, myName, 'ogr')
        if not myOutLayer.isValid():
            #TODO (MB) use a better exception
            raise Exception('Invalid qgis Layer')

        if self.showIntermediateLayers:
            self.keywordIO.update_keywords(myOutLayer, {'title': myName})
            QgsMapLayerRegistry.instance().addMapLayer(myOutLayer)

        return myOutLayer
示例#27
0
    def aggregate(self, theSafeImpactLayer):
        """Do any requested aggregation post processing.

        Performs Aggregation postprocessing step by

            * creating a copy of the dataset clipped by the impactlayer
              bounding box
            * stripping all attributes beside the aggregation attribute
            * delegating to the appropriate aggregator for raster and vectors

        :raises: ReadLayerError
        """

        if not self.isValid:
            raise InvalidAggregatorError

        myMessage = m.Message(
            m.Heading(self.tr('Aggregating results'), **PROGRESS_UPDATE_STYLE),
            m.Paragraph(self.tr(
                'This may take a little while - we are aggregating the impact'
                ' by %1').arg(self.layer.name())))
        self._sendMessage(myMessage)

        myQGISImpactLayer = safe_to_qgis_layer(theSafeImpactLayer)
        if not myQGISImpactLayer.isValid():
            myMessage = self.tr('Error when reading %1').arg(myQGISImpactLayer)
            # noinspection PyExceptionInherit
            raise ReadLayerError(myMessage)
        myLayerName = str(self.tr('%1 aggregated to %2').arg(
            myQGISImpactLayer.name()).arg(self.layer.name()))

        #delete unwanted fields
        myProvider = self.layer.dataProvider()
        myFields = myProvider.fields()

        #mark important attributes as needed
        self._setPersistantAttributes()
        myUnneededAttributes = []

        for i in myFields:
            if (myFields[i].name() not in
                    self.attributes.values()):
                myUnneededAttributes.append(i)
        LOGGER.debug('Removing this attributes: ' + str(myUnneededAttributes))
        # noinspection PyBroadException
        try:
            self.layer.startEditing()
            myProvider.deleteAttributes(myUnneededAttributes)
            self.layer.commitChanges()
        # FIXME (Ole): Disable pylint check for the moment
        # Need to work out what exceptions we will catch here, though.
        except:  # pylint: disable=W0702
            myMessage = self.tr('Could not remove the unneeded fields')
            LOGGER.debug(myMessage)

        del myUnneededAttributes, myProvider, myFields
        self.keywordIO.update_keywords(
            self.layer, {'title': myLayerName})

        self.statisticsType, self.statisticsClasses = (
            self.keywordIO.get_statistics(myQGISImpactLayer))

        #call the correct aggregator
        if myQGISImpactLayer.type() == QgsMapLayer.VectorLayer:
            self._aggregateVectorImpact(myQGISImpactLayer, theSafeImpactLayer)
        elif myQGISImpactLayer.type() == QgsMapLayer.RasterLayer:
            self._aggregateRasterImpact(myQGISImpactLayer)
        else:
            myMessage = self.tr('%1 is %2 but it should be either vector or '
                                'raster').\
                arg(myQGISImpactLayer.name()).arg(myQGISImpactLayer.type())
            # noinspection PyExceptionInherit
            raise ReadLayerError(myMessage)

        # show a styled aggregation layer
        if self.showIntermediateLayers:
            if self.statisticsType == 'sum':
                #style layer if we are summing
                myProvider = self.layer.dataProvider()
                myAttr = self._sumFieldName()
                myAttrIndex = myProvider.fieldNameIndex(myAttr)
                myProvider.select([myAttrIndex], QgsRectangle(), False)
                myFeature = QgsFeature()
                myHighestVal = 0

                while myProvider.nextFeature(myFeature):
                    myAttrMap = myFeature.attributeMap()
                    myVal, ok = myAttrMap[myAttrIndex].toInt()
                    if ok and myVal > myHighestVal:
                        myHighestVal = myVal

                myClasses = []
                myColors = ['#fecc5c', '#fd8d3c', '#f31a1c']
                myStep = int(myHighestVal / len(myColors))
                myCounter = 0
                for myColor in myColors:
                    myMin = myCounter
                    myCounter += myStep
                    myMax = myCounter

                    myClasses.append(
                        {'min': myMin,
                         'max': myMax,
                         'colour': myColor,
                         'transparency': 30,
                         'label': '%s - %s' % (myMin, myMax)})
                    myCounter += 1

                myStyle = {'target_field': myAttr,
                           'style_classes': myClasses}
                set_vector_graduated_style(self.layer, myStyle)
            else:
                #make style of layer pretty much invisible
                myProps = {'style': 'no',
                           'color_border': '0,0,0,127',
                           'width_border': '0.0'
                           }
                # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
                mySymbol = QgsFillSymbolV2.createSimple(myProps)
                myRenderer = QgsSingleSymbolRendererV2(mySymbol)
                self.layer.setRendererV2(myRenderer)
                self.layer.saveDefaultStyle()