def testEditGeoJsonAddFieldAndThenAddFeatures(self): """ Test bugfix of https://issues.qgis.org/issues/18596 (adding a new field)""" datasource = os.path.join(self.basetestpath, 'testEditGeoJsonAddField.json') with open(datasource, 'wt') as f: f.write("""{ "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": { "x": 1 }, "geometry": { "type": "Point", "coordinates": [ 0, 0 ] } } ] }""") vl = QgsVectorLayer(datasource, 'test', 'ogr') self.assertTrue(vl.isValid()) self.assertTrue(vl.startEditing()) self.assertTrue(vl.addAttribute(QgsField('strfield', QVariant.String))) self.assertTrue(vl.commitChanges()) self.assertEqual(len(vl.dataProvider().fields()), 1 + 1) self.assertEqual([f.name() for f in vl.dataProvider().fields()], ['x', 'strfield']) f = QgsFeature() self.assertTrue(vl.getFeatures(QgsFeatureRequest()).nextFeature(f)) self.assertIsNone(f['strfield']) self.assertEqual([field.name() for field in f.fields()], ['x', 'strfield']) self.assertTrue(vl.startEditing()) vl.changeAttributeValue(f.id(), 1, 'x') self.assertTrue(vl.commitChanges()) f = QgsFeature() self.assertTrue(vl.getFeatures(QgsFeatureRequest()).nextFeature(f)) self.assertEqual(f['strfield'], 'x') self.assertEqual([field.name() for field in f.fields()], ['x', 'strfield']) # Completely reload file vl = QgsVectorLayer(datasource, 'test', 'ogr') self.assertEqual(len(vl.fields()), 2)
def create_layer_bk(download_path, tmp_layer, indicator, indicator_name, data, year): tmp_data_provider = tmp_layer.dataProvider() tmp_layer.startEditing() tmp_feature = QgsFeature() # get world bank data # data = get_world_bank_data(indicator, year) # getting layer_name layer_name = indicator_name + " (" + year + ")" clean_layer_name = re.sub('\W+', '_', indicator_name) + "_" + year # creating output path # output_base_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "output") # if not os.path.exists(output_base_path): # os.mkdir(output_base_path) # retrieving input shp # output_file = os.path.join(output_base_path, clean_layer_name + ".shp") output_file = os.path.join(download_path, clean_layer_name + ".shp") input_base_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "resources") # copy resource file to output # resource_files = glob.glob(os.path.join(input_base_path, "ne_110m_admin_0_*")) resource_files = glob.glob(os.path.join(input_base_path, "ne_110m_admin_0_*")) for resource_file in resource_files: base, extension = os.path.splitext(resource_file) copyfile(resource_file, os.path.join(download_path, clean_layer_name + extension)) # Editing output_file layer = QgsVectorLayer(output_file, layer_name, "ogr") layer.startEditing() # TODO: add data check instead of the addedValue boolean? addedValue = False for feat in layer.getFeatures(): if feat['iso_a2'] is not None: for d in data: code = d['country']['id'] value = d['value'] if code == feat['iso_a2']: if value: # TODO: automatize the index 5 of feat['iso_a2'] layer.changeAttributeValue(feat.id(), 5, float(value)) tmp_feature.setAttributes([float(value)]) # TODO add all togheter tmp_data_provider.addFeatures([tmp_feature]) addedValue = True break layer.commitChanges() return layer, addedValue
def testGeopackageLargeFID(self): tmpfile = os.path.join(self.basetestpath, 'testGeopackageLargeFID.gpkg') ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString)) ds = None vl = QgsVectorLayer(u'{}'.format(tmpfile) + "|layername=" + "test", 'test', u'ogr') f = QgsFeature() f.setAttributes([1234567890123, None]) self.assertTrue(vl.startEditing()) self.assertTrue(vl.dataProvider().addFeatures([f])) self.assertTrue(vl.commitChanges()) got = [feat for feat in vl.getFeatures()][0] self.assertEqual(got['fid'], 1234567890123) self.assertTrue(vl.startEditing()) self.assertTrue(vl.changeGeometry(1234567890123, QgsGeometry.fromWkt('Point (3 50)'))) self.assertTrue(vl.changeAttributeValue(1234567890123, 1, 'foo')) self.assertTrue(vl.commitChanges()) got = [feat for feat in vl.getFeatures()][0] self.assertEqual(got['str_field'], 'foo') got_geom = got.geometry() self.assertIsNotNone(got_geom) self.assertTrue(vl.startEditing()) self.assertTrue(vl.deleteFeature(1234567890123)) self.assertTrue(vl.commitChanges())
def testEditSubsetString(self): tmpfile = os.path.join(self.basetestpath, 'testEditSubsetString.gpkg') ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) lyr = ds.CreateLayer('test', geom_type=ogr.wkbMultiPolygon) lyr.CreateField(ogr.FieldDefn('foo', ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) f['foo'] = 'bar' lyr.CreateFeature(f) f = None f = ogr.Feature(lyr.GetLayerDefn()) f['foo'] = 'baz' lyr.CreateFeature(f) f = None ds = None vl = QgsVectorLayer('{}|layerid=0'.format(tmpfile), 'test', 'ogr') self.assertEqual(vl.dataProvider().featureCount(), 2) # Test adding features vl.setSubsetString("foo = 'baz'") self.assertTrue(vl.startEditing()) feature = QgsFeature(vl.fields()) feature['foo'] = 'abc' vl.addFeature(feature) vl.commitChanges() vl.setSubsetString(None) self.assertEqual(vl.dataProvider().featureCount(), 3) # Test deleting a feature vl.setSubsetString("foo = 'baz'") self.assertTrue(vl.startEditing()) vl.deleteFeature(1) vl.commitChanges() vl.setSubsetString(None) self.assertEqual(vl.dataProvider().featureCount(), 2) # Test editing a feature vl.setSubsetString("foo = 'baz'") self.assertTrue(vl.startEditing()) vl.changeAttributeValue(2, 1, 'xx') vl.commitChanges() vl.setSubsetString(None) self.assertEqual(set((feat['foo'] for feat in vl.getFeatures())), set(['xx', 'abc']))
def testDisablewalForSqlite3(self): ''' Test disabling walForSqlite3 setting ''' QgsSettings().setValue("/qgis/walForSqlite3", False) tmpfile = os.path.join(self.basetestpath, 'testDisablewalForSqlite3.gpkg') ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) lyr.CreateField(ogr.FieldDefn('attr0', ogr.OFTInteger)) lyr.CreateField(ogr.FieldDefn('attr1', ogr.OFTInteger)) f = ogr.Feature(lyr.GetLayerDefn()) f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)')) lyr.CreateFeature(f) f = None ds = None vl = QgsVectorLayer(u'{}'.format(tmpfile), u'test', u'ogr') # Test that we are using default delete mode and not WAL ds = ogr.Open(tmpfile) lyr = ds.ExecuteSQL('PRAGMA journal_mode') f = lyr.GetNextFeature() res = f.GetField(0) ds.ReleaseResultSet(lyr) ds = None self.assertEqual(res, 'delete') self.assertTrue(vl.startEditing()) feature = next(vl.getFeatures()) self.assertTrue(vl.changeAttributeValue(feature.id(), 1, 1001)) # Commit changes cbk = ErrorReceiver() vl.dataProvider().raiseError.connect(cbk.receiveError) self.assertTrue(vl.commitChanges()) self.assertIsNone(cbk.msg) vl = None QgsSettings().setValue("/qgis/walForSqlite3", None)
def testUpdateFeature(self): p = QgsProject() vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") self.assertTrue(vector_layer.isValid()) p.addMapLayer(vector_layer) l = QgsPrintLayout(p) atlas = l.atlas() atlas.setEnabled(True) atlas.setCoverageLayer(vector_layer) self.assertTrue(atlas.beginRender()) self.assertTrue(atlas.first()) self.assertEqual(atlas.currentFeatureNumber(), 0) self.assertEqual(l.reportContext().feature()[4], 'Basse-Normandie') self.assertEqual(l.reportContext().layer(), vector_layer) vector_layer.startEditing() self.assertTrue(vector_layer.changeAttributeValue(l.reportContext().feature().id(), 4, 'Nah, Canberra mate!')) self.assertEqual(l.reportContext().feature()[4], 'Basse-Normandie') l.atlas().refreshCurrentFeature() self.assertEqual(l.reportContext().feature()[4], 'Nah, Canberra mate!') vector_layer.rollBack()
class AutoFieldsTests( unittest.TestCase ): @classmethod def setUpClass( self ): self.msg = MessageManager( 'debug', None ) self.msg.show( "Info! SetUp started", 'info', True ) #Initialize QGIS app app = QgsApplication([], True) QgsApplication.setPrefixPath("/usr", True) QgsApplication.initQgis() #Configure QSettings (organization and application name) self.settings = QSettings("GeoTux", "QGIS-Plugin-Test") #Load layer, add field f1, and add layer to Registry baseDir = os.path.dirname( os.path.realpath( __file__ ) ) self.layerPath = os.path.join( baseDir, 'test_data', 'test_points.shp' ) self.layer = QgsVectorLayer( self.layerPath, 'puntos', 'ogr' ) self.layer.dataProvider().addAttributes([QgsField('f1', QVariant.Double)]) self.layer.updateFields() QgsMapLayerRegistry.instance().addMapLayer( self.layer ) #Instantiate AutoFieldManager self.autoFieldManager = AutoFieldManager( self.msg, None, '/AutoFieldsTest', 'GeoTux', 'QGIS-Plugin-Test' ) def readStoredSettings( self, layer, fieldName ): """ Helper function to get a dictionary of stored QSettings for an AutoField """ dictTmpProperties = {} autoFieldId = self.autoFieldManager.buildAutoFieldId( layer, fieldName ) self.settings.beginGroup('/AutoFieldsTest/data/' + autoFieldId) dictTmpProperties['layer'] = self.settings.value( "layer", "", type=str ) dictTmpProperties['field'] = self.settings.value( "field", u"", type=unicode ) dictTmpProperties['expression'] = self.settings.value( "expression", u"", type=unicode ) dictTmpProperties['layer2'] = self.settings.value( "layer2", "", type=str ) dictTmpProperties['field2'] = self.settings.value( "field2", "", type=str ) dictTmpProperties['enabled'] = self.settings.value( "enabled", False, type=bool ) self.settings.endGroup() return dictTmpProperties def test01CreateEnabledAutoField( self ): """ QSettings should be properly stored, AutoField should be enabled """ self.msg.show( "Info! Test 1 started", 'info', True ) self.autoFieldManager.createAutoField( layer=self.layer, fieldName=u'f1', expression=u'$x' ) dictTmpProperties = self.readStoredSettings( self.layer, u'f1' ) dictExpectedProperties = { 'layer':self.layerPath, 'field':u'f1', 'expression':u'$x', 'layer2':"", 'field2':"", 'enabled':True } self.assertEqual( dictTmpProperties, dictExpectedProperties ) def test02AvoidTwoAutoFieldsOnSameField( self ): """ AutoField should not be created if another one already exists on the same field.""" self.msg.show( "Info! Test 2 started", 'info', True ) res = self.autoFieldManager.createAutoField( layer=self.layer, fieldName=u'f1', expression=u'$y' ) self.assertFalse( res ) def test03EditAutoFieldLayer( self ): """ AutoField value should be updated if a feature is added. Note: It cannot handle the case when writing directly to the provider, as QGIS doesn't have a SIGNAL for that. self.layer.dataProvider().addFeatures( [ tmpFeature ] ) """ self.msg.show( "Info! Test 3 started", 'info', True ) tmpFeature = QgsFeature( self.layer.pendingFields() ) tmpFeature.setGeometry( QgsGeometry.fromPoint( QgsPoint(-74.4, 4.5) ) ) # Either 1: self.layer.startEditing() self.layer.addFeature( tmpFeature ) self.layer.commitChanges() # Or 2: #with edit( self.layer ): # self.layer.addFeature( tmpFeature ) addedFeature = self.layer.getFeatures().next() self.assertEquals( addedFeature['f1'], -74.4 ) def test04ChangeAttributeValue( self ): """ AutoField value should be updated if another AutoField value is changed """ self.msg.show( "Info! Test 4 started", 'info', True ) self.autoFieldManager.createAutoField( layer=self.layer, fieldName=u'modified', expression=u'\'now: \' + to_string("f1")' ) self.layer.startEditing() self.layer.changeAttributeValue( 0, self.layer.fieldNameIndex( u'id' ), 1 ) self.layer.commitChanges() feature = self.layer.getFeatures().next() self.assertEquals( feature['modified'], 'now: -74.4' ) def test05FieldRemovedThenDisableAutoField( self ): """ AutoField should be disabled if its base field is removed """ self.msg.show( "Info! Test 5 started", 'info', True ) fieldIndex = self.layer.fieldNameIndex( u'f1' ) self.layer.startEditing() self.layer.deleteAttribute( fieldIndex ) self.layer.commitChanges() dictTmpProperties = self.readStoredSettings( self.layer, u'f1' ) self.assertFalse( dictTmpProperties['enabled'] ) def test06MissingFieldAddedThenEnableAutoField( self ): """ AutoField should be enabled if missing field is added """ self.msg.show( "Info! Test 6 started", 'info', True ) self.layer.startEditing() self.layer.addAttribute( QgsField( 'f1', QVariant.Double, len=10, prec=2 ) ) self.layer.commitChanges() dictTmpProperties = self.readStoredSettings( self.layer, u'f1' ) self.assertTrue( dictTmpProperties['enabled'] ) def test07LayerRemovedThenDisableAutoField( self ): """ AutoField should be disabled if its base layer is removed """ self.msg.show( "Info! Test 7 started", 'info', True ) QgsMapLayerRegistry.instance().removeMapLayer( self.layer.id() ) # removeMapLayer deletes the underlying object, so create it again self.layer = QgsVectorLayer( self.layerPath, 'puntos', 'ogr' ) dictTmpProperties = self.readStoredSettings( self.layer, u'f1' ) self.assertFalse( dictTmpProperties['enabled'] ) def test08MissingLayerAddedThenEnableAutoField( self ): """ AutoField should be enabled if missing layer is added """ self.msg.show( "Info! Test 8 started", 'info', True ) # test07 deletes the layer object, so create it again self.layer = QgsVectorLayer( self.layerPath, 'puntos', 'ogr' ) QgsMapLayerRegistry.instance().addMapLayer( self.layer ) dictTmpProperties = self.readStoredSettings( self.layer, u'f1' ) self.assertTrue( dictTmpProperties['enabled'] ) def test09RemoveAutoField( self ): """ QSettings should be deleted for the removed AutoField """ self.msg.show( "Info! Test 9 started", 'info', True ) # test07 deletes the layer object, so create it again self.layer = QgsVectorLayer( self.layerPath, 'puntos', 'ogr' ) autoFieldId = self.autoFieldManager.buildAutoFieldId( self.layer, u'f1') self.autoFieldManager.removeAutoField( autoFieldId ) dictTmpProperties = self.readStoredSettings( self.layer, u'f1' ) self.assertEqual( dictTmpProperties, {'layer':"",'field':"",'expression':"",'layer2':"",'field2':"",'enabled':False} ) @classmethod def tearDownClass( self ): self.msg.show( "Info! TearDown started", 'info', True ) # test07 deletes the layer object, so create it again self.layer = QgsVectorLayer( self.layerPath, 'puntos', 'ogr' ) #Remove AutoField modified autoFieldId = self.autoFieldManager.buildAutoFieldId( self.layer, u'modified' ) self.autoFieldManager.removeAutoField( autoFieldId ) #Delete field f1 fieldIndex = self.layer.fieldNameIndex('f1') self.layer.dataProvider().deleteAttributes( [fieldIndex] ) self.layer.updateFields() #Delete features from test layer fIds = self.layer.allFeatureIds() self.layer.dataProvider().deleteFeatures( fIds ) #Remove layer from Registry QgsMapLayerRegistry.instance().removeMapLayer( self.layer.id() ) self.msg.show( "Info! TearDown finished", 'info', True ) QgsApplication.exitQgis()
def testProjectStorage(self): # New project without fileName p0 = QgsProject() self.assertTrue(p0.auxiliaryStorage().isValid()) # Create new layers with key otherwise auxiliary layers are not # automacially created when added in project vl0 = createLayer() vl0Shp = writeShape(vl0, 'vl0.shp') vl1 = createLayer() vl1Shp = writeShape(vl1, 'vl1.shp') vl0 = QgsVectorLayer(vl0Shp, 'points', 'ogr') self.assertTrue(vl0.isValid()) vl1 = QgsVectorLayer(vl1Shp, 'points', 'ogr') self.assertTrue(vl1.isValid()) # Add layers to project and check underlying auxiliary layers p0.addMapLayers([vl0, vl1]) self.assertTrue(vl0.loadAuxiliaryLayer(p0.auxiliaryStorage(), 'pk')) self.assertTrue( vl1.loadAuxiliaryLayer(p0.auxiliaryStorage(), 'num_char')) al0 = vl0.auxiliaryLayer() al1 = vl1.auxiliaryLayer() self.assertEqual(al0.joinInfo().targetFieldName(), 'pk') self.assertEqual(al1.joinInfo().targetFieldName(), 'num_char') # Add a field in auxiliary layers pdef0 = QgsPropertyDefinition('propname', QgsPropertyDefinition.DataTypeNumeric, '', '', 'ut') self.assertTrue(al0.addAuxiliaryField(pdef0)) pdef1 = QgsPropertyDefinition('propname1', QgsPropertyDefinition.DataTypeString, '', '', 'ut') self.assertTrue(al1.addAuxiliaryField(pdef1)) # Check auxiliary fields names af0Name = QgsAuxiliaryLayer.nameFromProperty(pdef0, False) self.assertEqual(af0Name, 'ut_propname') af1Name = QgsAuxiliaryLayer.nameFromProperty(pdef1, False) self.assertEqual(af1Name, 'ut_propname1') # Set value for auxiliary fields req = QgsFeatureRequest().setFilterExpression("name = 'Honey'") f = QgsFeature() vl0.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) af0Name = QgsAuxiliaryLayer.nameFromProperty(pdef0, True) index0 = vl0.fields().indexOf(af0Name) vl0.changeAttributeValue(f.id(), index0, 333) req = QgsFeatureRequest().setFilterExpression("name = 'Apple'") f = QgsFeature() vl1.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) af1Name = QgsAuxiliaryLayer.nameFromProperty(pdef1, True) index1 = vl1.fields().indexOf(af1Name) vl1.changeAttributeValue(f.id(), index0, 'myvalue') req = QgsFeatureRequest().setFilterExpression("name = 'Orange'") f = QgsFeature() vl1.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) vl1.changeAttributeValue(f.id(), index0, 'myvalue1') # Save the project in a zip file f = tmpPath() + '.qgz' p0.write(f) # Open the zip file with embedded auxiliary storage p1 = QgsProject() p1.read(f) # Check that auxiliary fields are well loaded in layers self.assertEqual(len(p1.mapLayers().values()), 2) for vl in p1.mapLayers().values(): al = vl.auxiliaryLayer() self.assertEqual(len(al.auxiliaryFields()), 1) af = al.auxiliaryFields()[0] afPropDef = QgsAuxiliaryLayer.propertyDefinitionFromField(af) self.assertEqual(afPropDef.origin(), 'ut') if vl.auxiliaryLayer().joinInfo().targetFieldName() == 'pk': self.assertEqual(afPropDef.name(), 'propname') self.assertEqual(al.featureCount(), 1) req = QgsFeatureRequest().setFilterExpression("name = 'Honey'") f = QgsFeature() vl.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) self.assertEqual(f.attributes()[index0], 333.0) else: # num_char self.assertEqual(al.featureCount(), 2) self.assertEqual(afPropDef.name(), 'propname1') req = QgsFeatureRequest().setFilterExpression("name = 'Apple'") f = QgsFeature() vl.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) self.assertEqual(f.attributes()[index1], 'myvalue') req = QgsFeatureRequest().setFilterExpression( "name = 'Orange'") f = QgsFeature() vl.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) self.assertEqual(f.attributes()[index1], 'myvalue1')
def testGeopackageTwoLayerEdition(self): ''' test https://issues.qgis.org/issues/17034 ''' tmpfile = os.path.join(self.basetestpath, 'testGeopackageTwoLayerEdition.gpkg') ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) lyr = ds.CreateLayer('layer1', geom_type=ogr.wkbPoint) lyr.CreateField(ogr.FieldDefn('attr', ogr.OFTInteger)) f = ogr.Feature(lyr.GetLayerDefn()) f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)')) lyr.CreateFeature(f) f = None lyr = ds.CreateLayer('layer2', geom_type=ogr.wkbPoint) lyr.CreateField(ogr.FieldDefn('attr', ogr.OFTInteger)) f = ogr.Feature(lyr.GetLayerDefn()) f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(1 1)')) lyr.CreateFeature(f) f = None ds = None vl1 = QgsVectorLayer(u'{}'.format(tmpfile) + "|layername=layer1", u'layer1', u'ogr') vl2 = QgsVectorLayer(u'{}'.format(tmpfile) + "|layername=layer2", u'layer2', u'ogr') # Edit vl1, vl2 multiple times self.assertTrue(vl1.startEditing()) self.assertTrue(vl2.startEditing()) self.assertTrue( vl1.changeGeometry(1, QgsGeometry.fromWkt('Point (2 2)'))) self.assertTrue( vl2.changeGeometry(1, QgsGeometry.fromWkt('Point (3 3)'))) self.assertTrue(vl1.commitChanges()) self.assertTrue(vl2.commitChanges()) self.assertTrue(vl1.startEditing()) self.assertTrue(vl2.startEditing()) self.assertTrue(vl1.changeAttributeValue(1, 1, 100)) self.assertTrue(vl2.changeAttributeValue(1, 1, 101)) self.assertTrue(vl1.commitChanges()) self.assertTrue(vl2.commitChanges()) self.assertTrue(vl1.startEditing()) self.assertTrue(vl2.startEditing()) self.assertTrue( vl1.changeGeometry(1, QgsGeometry.fromWkt('Point (4 4)'))) self.assertTrue( vl2.changeGeometry(1, QgsGeometry.fromWkt('Point (5 5)'))) self.assertTrue(vl1.commitChanges()) self.assertTrue(vl2.commitChanges()) vl1 = None vl2 = None # Check everything is as expected after re-opening vl1 = QgsVectorLayer(u'{}'.format(tmpfile) + "|layername=layer1", u'layer1', u'ogr') vl2 = QgsVectorLayer(u'{}'.format(tmpfile) + "|layername=layer2", u'layer2', u'ogr') got = [feat for feat in vl1.getFeatures()][0] got_geom = got.geometry() self.assertEqual(got['attr'], 100) reference = QgsGeometry.fromWkt('Point (4 4)') self.assertEqual( got_geom.asWkb(), reference.asWkb(), 'Expected {}, got {}'.format(reference.asWkt(), got_geom.asWkt())) got = [feat for feat in vl2.getFeatures()][0] got_geom = got.geometry() self.assertEqual(got['attr'], 101) reference = QgsGeometry.fromWkt('Point (5 5)') self.assertEqual( got_geom.asWkb(), reference.asWkb(), 'Expected {}, got {}'.format(reference.asWkt(), got_geom.asWkt()))
def on_click_Inici(self): global lbl_Cost global data global listFields global urlToLoad global TEMPORARY_PATH self.dlg.setEnabled(False) '''Tratamiento de errores''' llistaErrors = self.controlErrorsInput() if len(llistaErrors) > 0: llista = "Llista d'errors:\n\n" for i in range (0,len(llistaErrors)): llista += ("- "+llistaErrors[i] + '\n') QMessageBox.information(None, "Error", llista) self.dlg.setEnabled(True) return textBox = u'INICI DEL PROCÉS\n\n' self.dlg.text_info.setText(textBox) self.MouText() campNom = '' campGeometria = '' campCod = '' campSrc = '' campLat = '' campLng = '' '''Obtención de Nom y Geometria''' if self.dlg.radio_ws.isChecked(): campNom,campGeometria,campLat, campLng, campCod,campSrc=self.searchNomGeomCodSrcInFile() urlToLoad=self.dlg.combo_ws.currentText() #if(urlToLoad[-4:]=='.csv'): error = self.loadCSV(campNom, campGeometria, campCod,True) if (error=="Error"): self.dlg.setEnabled(True) return else: campNom = self.dlg.combo_nom.currentText() campCod=self.dlg.combo_cod.currentText() campSrc=self.dlg.combo_src.currentText() if self.dlg.radio_geom.isChecked(): campGeometria = self.dlg.combo_geom.currentText() elif self.dlg.radio_latlng.isChecked(): campLat=self.dlg.combo_lat.currentText() campLng=self.dlg.combo_lng.currentText() '''Creación vector layer''' self.dlg.progressBar.setValue(60) textBox += u'Generant capa vectorial...\n' self.dlg.text_info.setText(textBox) self.MouText() if campGeometria != '': file = 'file:///'+TEMPORARY_PATH+'/WS.csv?encoding=%s&delimiter=%s&wktField=%s&crs=%s' % (campCod,",", campGeometria,campSrc) elif campLat != '' and campLng != '': file = 'file:///'+TEMPORARY_PATH+'/WS.csv?encoding=%s&delimiter=%s&xField=%s&yField=%s&crs=%s' % (campCod,",", campLng, campLat,campSrc) else: file = 'file:///'+TEMPORARY_PATH+'/WS.csv?encoding=%s&delimiter=%s' % (campCod,",") vlayergeom = QgsVectorLayer(file, self.dlg.txt_nomTaula.text(),'delimitedtext') try: vlayergeom = self.comprobarValidez(vlayergeom) #Sirve tanto para comprobar la corrección del CSV como para pasar el layer a memoria except Exception as ex: missatge="La geometria seleccionada no és correcte" print (missatge) template = "An exception of type {0} occurred. Arguments:\n{1!r}" message = template.format(type(ex).__name__, ex.args) print (message) QMessageBox.information(None, "Error", missatge) self.dlg.text_info.setText('') self.dlg.progressBar.setValue(0) self.dlg.setEnabled(True) return "Error" vlayergeom.setName(self.dlg.txt_nomTaula.text()) self.dlg.progressBar.setValue(80) textBox += u'Adaptant camps...\n' self.dlg.text_info.setText(textBox) self.MouText() '''Se renombra el campo de nombre y se añade un id''' vlayergeom.startEditing() fields = vlayergeom.fields() for x in range(len(fields)): if(campNom in fields[x].displayName()): vlayergeom.renameAttribute(x,'Nom') break; vlayergeom.addAttribute(QgsField('id', QVariant.Int)) vlayergeom.commitChanges() '''Se autonumera el id''' features = vlayergeom.getFeatures() vlayergeom.startEditing() x=1 for feature in features: vlayergeom.changeAttributeValue(feature.id(),self.getIndexOfField(vlayergeom,"id"),x) x=x+1 vlayergeom.commitChanges() '''Se borran los campos no seleccionados''' if not self.dlg.radio_ws.isChecked(): llista_sel=[] if (len(self.dlg.ListaCamps.selectedItems())>0): for item in self.dlg.ListaCamps.selectedItems(): llista_sel.append(item.text()) vlayergeom.startEditing() for elem in listFields: if elem not in llista_sel: vlayergeom.deleteAttribute(self.getIndexOfField(vlayergeom,elem)) vlayergeom.commitChanges() '''Se representa en pantalla''' QgsProject.instance().addMapLayer(vlayergeom,False) root = QgsProject.instance().layerTreeRoot() myLayerNode=QgsLayerTreeLayer(vlayergeom) root.insertChildNode(0,myLayerNode) myLayerNode.setCustomProperty("showFeatureCount", True) if self.dlg.checkBox_save.isChecked(): this_folder = os.path.dirname(os.path.abspath(__file__)) '''UPDATE''' file = open(this_folder+'/default_ws.txt') cont=0 strToWrite = '' for line in file: if (line.split('=',1)[1].replace('\n','')==self.dlg.txt_url.text()): cont+=1 strToWrite+= line elif (cont==1): cont+=1 strToWrite+= 'nom='+campNom+'\n' elif (cont==2): cont+=1 if self.dlg.radio_geom.isChecked(): strToWrite+= 'geom='+campGeometria+'\n' else: strToWrite+='geom=\n' elif (cont==3): cont+=1 if self.dlg.radio_latlng.isChecked(): strToWrite+= 'lat='+campLat+'\n' else: strToWrite+='lat=\n' elif (cont==4): cont+=1 if self.dlg.radio_latlng.isChecked(): strToWrite+= 'lng='+campLng+'\n' else: strToWrite+='lng=\n' elif (cont==5): cont+=1 strToWrite+= 'cod='+campCod+'\n' elif (cont==6): cont+=1 strToWrite+= 'src='+campSrc+'\n' else: strToWrite+=line file.close() file = open(this_folder+'/default_ws.txt', "w") file.write(strToWrite) file.close() '''APEND''' if cont == 0: strToAppend = '\nurl='+self.dlg.txt_url.text() strToAppend += '\nnom='+campNom if self.dlg.radio_geom.isChecked(): strToAppend += '\ngeo='+campGeometria else: strToAppend += '\ngeo=' if self.dlg.radio_latlng.isChecked(): strToAppend += '\nlat='+campLat strToAppend += '\nlng='+campLng else: strToAppend += '\nlat=' strToAppend += '\nlng=' strToAppend += '\ncod='+campCod strToAppend += '\nsrc='+campSrc file = open(this_folder+'/default_ws.txt', "a") file.write(strToAppend) file.close() self.file2Combo("default_ws.txt", self.dlg.combo_ws, 'Selecciona una opció') self.dlg.progressBar.setValue(100) textBox += u'\nProcés finalitzat.\n' self.dlg.text_info.setText(textBox) self.MouText() self.dlg.setEnabled(True)
class CsvLayer(): """ Pretend we are a data provider """ dirty = False doing_attr_update = False def __init__(self, csv_path): """ Initialize the layer by reading the CSV file, creating a memory layer, and adding records to it """ # Save the path to the file soe we can update it in response to edits self.csv_path = csv_path self.csv_file = open(csv_path, 'rb') self.reader = csv.reader(self.csv_file) self.header = self.reader.next() logger(str(self.header)) # Get sample sample = self.reader.next() self.field_sample = dict(zip(self.header, sample)) logger("sample %s" % str(self.field_sample)) field_name_types = {} # create dict of fieldname:type for key in self.field_sample.keys(): if self.field_sample[key].isdigit(): field_type = 'integer' else: try: float(self.field_sample[key]) field_type = 'real' except ValueError: field_type = 'string' field_name_types[key] = field_type logger(str(field_name_types)) # Build up the URI needed to create memory layer self.uri = self.uri = "Point?crs=epsg:4326" for fld in self.header: self.uri += '&field={}:{}'.format(fld, field_name_types[fld]) logger(self.uri) # Create the layer self.lyr = QgsVectorLayer(self.uri, 'cities.csv', 'memory') self.add_records() # done with the csv file self.csv_file.close() # Make connections self.lyr.editingStarted.connect(self.editing_started) self.lyr.editingStopped.connect(self.editing_stopped) self.lyr.committedAttributeValuesChanges.connect(self.attributes_changed) self.lyr.committedFeaturesAdded.connect(self.features_added) self.lyr.committedFeaturesRemoved.connect(self.features_removed) self.lyr.geometryChanged.connect(self.geometry_changed) # Add the layer the map QgsMapLayerRegistry.instance().addMapLayer(self.lyr) def add_records(self): """ Add records to the memory layer by reading the CSV file """ # Return to beginning of csv file self.csv_file.seek(0) # Skip the header self.reader.next() self.lyr.startEditing() for row in self.reader: flds = dict(zip(self.header, row)) # logger("This row: %s" % flds) feature = QgsFeature() geometry = QgsGeometry.fromPoint( QgsPoint(float(flds['X']), float(flds['Y']))) feature.setGeometry(geometry) # for key in flds: # logger("setting attribute for |%s|" % key) # feature.setAttribute(feature.fieldNameIndex(key), flds[key]) feature.setAttributes(row) self.lyr.addFeature(feature, True) self.lyr.commitChanges() def editing_started(self): """ Connect to the edit buffer so we can capture geometry and attribute changes """ self.lyr.editBuffer().committedAttributeValuesChanges.connect( self.attributes_changed) def editing_stopped(self): """ Update the CSV file if changes were committed """ if self.dirty: logger("Updating the CSV") features = self.lyr.getFeatures() tempfile = NamedTemporaryFile(mode='w', delete=False) writer = csv.writer(tempfile, delimiter=',') # write the header writer.writerow(self.header) for feature in features: row = [] for fld in self.header: row.append(feature[feature.fieldNameIndex(fld)]) writer.writerow(row) tempfile.close() shutil.move(tempfile.name, self.csv_path) self.dirty = False def attributes_changed(self, layer, changes): """ Attribute values changed; set the dirty flag """ if not self.doing_attr_update: logger("attributes changed") self.dirty = True def features_added(self, layer, features): """ Features added; update the X and Y attributes for each and set the dirty flag """ logger("features added") for feature in features: self.geometry_changed(feature.id(), feature.geometry()) self.dirty = True def features_removed(self, layer, feature_ids): """ Features removed; set the dirty flag """ logger("features removed") self.dirty = True def geometry_changed(self, fid, geom): """ Geometry for a feature changed; update the X and Y attributes for each """ feature = self.lyr.getFeatures(QgsFeatureRequest(fid)).next() pt = geom.asPoint() logger("Updating feature {} ({}) X and Y attributes to: {}".format( fid, feature['NAME'], pt.toString())) self.lyr.changeAttributeValue(fid, feature.fieldNameIndex('X'), pt.x()) self.lyr.changeAttributeValue(fid, feature.fieldNameIndex('Y'), pt.y())
def _test(autoTransaction): """Test buffer methods within and without transactions - create a feature - save - retrieve the feature - change geom and attrs - test changes are seen in the buffer """ def _check_feature(wkt): f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), wkt) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.geometry().asWkt().upper(), wkt) ml = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer', 'test', 'memory') self.assertTrue(ml.isValid()) d = QTemporaryDir() options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'layer_a' err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(ml, os.path.join(d.path(), 'transaction_test.gpkg'), QgsCoordinateTransformContext(), options) self.assertEqual(err, QgsVectorFileWriter.NoError) self.assertTrue(os.path.isfile(os.path.join(d.path(), 'transaction_test.gpkg'))) options.layerName = 'layer_b' options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(ml, os.path.join(d.path(), 'transaction_test.gpkg'), QgsCoordinateTransformContext(), options) layer_a = QgsVectorLayer(os.path.join(d.path(), 'transaction_test.gpkg|layername=layer_a')) self.assertTrue(layer_a.isValid()) project = QgsProject() project.setAutoTransaction(autoTransaction) project.addMapLayers([layer_a]) ########################################### # Tests with a new feature self.assertTrue(layer_a.startEditing()) buffer = layer_a.editBuffer() f = QgsFeature(layer_a.fields()) f.setAttribute('int', 123) f.setGeometry(QgsGeometry.fromWkt('point(7 45)')) self.assertTrue(layer_a.addFeatures([f])) _check_feature('POINT (7 45)') # Need to fetch the feature because its ID is NULL (-9223372036854775808) f = next(layer_a.getFeatures()) self.assertEqual(len(buffer.addedFeatures()), 1) layer_a.undoStack().undo() self.assertEqual(len(buffer.addedFeatures()), 0) layer_a.undoStack().redo() self.assertEqual(len(buffer.addedFeatures()), 1) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 123) # Now change attribute self.assertEqual(buffer.changedAttributeValues(), {}) layer_a.changeAttributeValue(f.id(), 1, 321) self.assertEqual(len(buffer.addedFeatures()), 1) # This is surprising: because it was a new feature it has been changed directly self.assertEqual(buffer.changedAttributeValues(), {}) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 321) layer_a.undoStack().undo() self.assertEqual(buffer.changedAttributeValues(), {}) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 123) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute('int'), 123) # Change geometry f = next(layer_a.getFeatures()) self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) _check_feature('POINT (9 43)') self.assertEqual(buffer.changedGeometries(), {}) layer_a.undoStack().undo() _check_feature('POINT (7 45)') self.assertEqual(buffer.changedGeometries(), {}) self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) _check_feature('POINT (9 43)') self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(10 44)'))) _check_feature('POINT (10 44)') # This is anothr surprise: geometry edits get collapsed into a single # one because they have the same hardcoded id layer_a.undoStack().undo() _check_feature('POINT (7 45)') self.assertTrue(layer_a.commitChanges()) ########################################### # Tests with the existing feature # Get the feature f = next(layer_a.getFeatures()) self.assertTrue(f.isValid()) self.assertEqual(f.attribute('int'), 123) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)') self.assertTrue(layer_a.startEditing()) layer_a.changeAttributeValue(f.id(), 1, 321) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {1: {1: 321}}) layer_a.undoStack().undo() self.assertEqual(buffer.changedAttributeValues(), {}) # Change geometry self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (9 43)') self.assertEqual(buffer.changedGeometries()[1].asWkt().upper(), 'POINT (9 43)') layer_a.undoStack().undo() self.assertEqual(buffer.changedGeometries(), {}) f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)') self.assertEqual(buffer.changedGeometries(), {}) # Delete an existing feature self.assertTrue(layer_a.deleteFeature(f.id())) with self.assertRaises(StopIteration): next(layer_a.getFeatures()) self.assertEqual(buffer.deletedFeatureIds(), [f.id()]) layer_a.undoStack().undo() self.assertTrue(layer_a.getFeature(f.id()).isValid()) self.assertEqual(buffer.deletedFeatureIds(), []) ########################################### # Test delete # Delete a new feature f = QgsFeature(layer_a.fields()) f.setAttribute('int', 555) f.setGeometry(QgsGeometry.fromWkt('point(8 46)')) self.assertTrue(layer_a.addFeatures([f])) f = [f for f in layer_a.getFeatures() if f.attribute('int') == 555][0] self.assertTrue(f.id() in buffer.addedFeatures()) self.assertTrue(layer_a.deleteFeature(f.id())) self.assertFalse(f.id() in buffer.addedFeatures()) self.assertFalse(f.id() in buffer.deletedFeatureIds()) layer_a.undoStack().undo() self.assertTrue(f.id() in buffer.addedFeatures()) ########################################### # Add attribute field = QgsField('attr1', QVariant.String) self.assertTrue(layer_a.addAttribute(field)) self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), [field]) layer_a.undoStack().undo() self.assertEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), []) layer_a.undoStack().redo() self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), [field]) self.assertTrue(layer_a.commitChanges()) ########################################### # Remove attribute self.assertTrue(layer_a.startEditing()) buffer = layer_a.editBuffer() attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) self.assertTrue(layer_a.deleteAttribute(attr_idx)) self.assertEqual(buffer.deletedAttributeIds(), [2]) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) layer_a.undoStack().undo() self.assertEqual(buffer.deletedAttributeIds(), []) self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx) layer_a.undoStack().redo() self.assertEqual(buffer.deletedAttributeIds(), [2]) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) self.assertTrue(layer_a.rollBack()) ########################################### # Rename attribute self.assertTrue(layer_a.startEditing()) attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) self.assertEqual(layer_a.fields().lookupField('new_name'), -1) self.assertTrue(layer_a.renameAttribute(attr_idx, 'new_name')) self.assertEqual(layer_a.fields().lookupField('new_name'), attr_idx) layer_a.undoStack().undo() self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx) self.assertEqual(layer_a.fields().lookupField('new_name'), -1) layer_a.undoStack().redo() self.assertEqual(layer_a.fields().lookupField('new_name'), attr_idx) self.assertEqual(layer_a.fields().lookupField(field.name()), -1)
def set_contour_properties(self, input_file): """Set the X, Y, RGB, ROMAN attributes of the contour layer. :param input_file: (Required) Name of the contour layer. :type input_file: str :raise: InvalidLayerError if anything is amiss with the layer. """ LOGGER.debug('set_contour_properties requested for %s.' % input_file) layer = QgsVectorLayer(input_file, 'mmi-contours', "ogr") if not layer.isValid(): raise InvalidLayerError(input_file) layer.startEditing() # Now loop through the db adding selected features to mem layer request = QgsFeatureRequest() fields = layer.dataProvider().fields() for feature in layer.getFeatures(request): if not feature.isValid(): LOGGER.debug('Skipping feature') continue # Work out x and y line = feature.geometry().asPolyline() y = line[0].y() x_max = line[0].x() x_min = x_max for point in line: if point.y() < y: y = point.y() x = point.x() if x < x_min: x_min = x if x > x_max: x_max = x x = x_min + ((x_max - x_min) / 2) # Get length length = feature.geometry().length() mmi_value = float(feature['MMI']) # We only want labels on the whole number contours if mmi_value != round(mmi_value): roman = '' else: roman = romanise(mmi_value) # RGB from http://en.wikipedia.org/wiki/Mercalli_intensity_scale rgb = mmi_colour(mmi_value) # Now update the feature feature_id = feature.id() layer.changeAttributeValue( feature_id, fields.indexFromName('X'), x) layer.changeAttributeValue( feature_id, fields.indexFromName('Y'), y) layer.changeAttributeValue( feature_id, fields.indexFromName('RGB'), rgb) layer.changeAttributeValue( feature_id, fields.indexFromName('ROMAN'), roman) layer.changeAttributeValue( feature_id, fields.indexFromName('ALIGN'), 'Center') layer.changeAttributeValue( feature_id, fields.indexFromName('VALIGN'), 'HALF') layer.changeAttributeValue( feature_id, fields.indexFromName('LEN'), length) layer.commitChanges()
def testPktComposite(self): """ Check that tables with PKs composed of many fields of different types are correctly read and written to """ vl = QgsVectorLayer( '{} type=POINT estimatedmetadata=true key=\'"pk1","pk2"\' table="qgis_test"."tb_test_compound_pk" (geom)' .format(self.dbconn), "test_compound", "mssql") self.assertTrue(vl.isValid()) fields = vl.fields() f = next( vl.getFeatures(QgsFeatureRequest().setFilterExpression( 'pk1 = 1 AND pk2 = 2'))) # first of all: we must be able to fetch a valid feature self.assertTrue(f.isValid()) self.assertEqual(f['pk1'], 1) self.assertEqual(f['pk2'], 2) self.assertEqual(f['value'], 'test 2') # can we edit a field? vl.startEditing() vl.changeAttributeValue(f.id(), fields.indexOf('value'), 'Edited Test 2') self.assertTrue(vl.commitChanges()) # Did we get it right? Let's create a new QgsVectorLayer and try to read back our changes: vl2 = QgsVectorLayer( '{} type=POINT estimatedmetadata=true table="qgis_test"."tb_test_compound_pk" (geom) key=\'"pk1","pk2"\' ' .format(self.dbconn), "test_compound2", "mssql") self.assertTrue(vl2.isValid()) f2 = next( vl2.getFeatures(QgsFeatureRequest().setFilterExpression( 'pk1 = 1 AND pk2 = 2'))) self.assertTrue(f2.isValid()) # Then, making sure we really did change our value. self.assertEqual(f2['value'], 'Edited Test 2') # How about inserting a new field? f3 = QgsFeature(vl2.fields()) f3['pk1'] = 4 f3['pk2'] = -9223372036854775800 f3['value'] = 'other test' vl.startEditing() res, f3 = vl.dataProvider().addFeatures([f3]) self.assertTrue(res) self.assertTrue(vl.commitChanges()) # can we catch it on another layer? f4 = next( vl2.getFeatures(QgsFeatureRequest().setFilterExpression( 'pk2 = -9223372036854775800'))) self.assertTrue(f4.isValid()) expected_attrs = [4, -9223372036854775800, 'other test'] self.assertEqual(f4.attributes(), expected_attrs) # Finally, let's delete one of the features. f5 = next( vl2.getFeatures(QgsFeatureRequest().setFilterExpression( 'pk1 = 2 AND pk2 = 1'))) vl2.startEditing() vl2.deleteFeatures([f5.id()]) self.assertTrue(vl2.commitChanges()) # did we really delete? Let's try to get the deleted feature from the first layer. f_iterator = vl.getFeatures( QgsFeatureRequest().setFilterExpression('pk1 = 2 AND pk2 = 1')) got_feature = True try: f6 = next(f_iterator) got_feature = f6.isValid() except StopIteration: got_feature = False self.assertFalse(got_feature)
def testPktCompositeFloat(self): """ Check that tables with PKs composed of many fields of different types are correctly read and written to """ vl = QgsVectorLayer( '{} type=POINT key=\'"pk1","pk2","pk3"\' table="qgis_test"."tb_test_composite_float_pk" (geom)' .format(self.dbconn), "test_composite_float", "mssql") self.assertTrue(vl.isValid()) fields = vl.fields() f = next( vl.getFeatures( QgsFeatureRequest().setFilterExpression('pk3 = 3.14159274'))) # first of all: we must be able to fetch a valid feature self.assertTrue(f.isValid()) self.assertEqual(f['pk1'], 1) self.assertEqual(f['pk2'], 2) self.assertEqual(round(f['pk3'], 6), round(3.14159274, 6)) self.assertEqual(f['value'], 'test 2') # can we edit a field? vl.startEditing() vl.changeAttributeValue(f.id(), fields.indexOf('value'), 'Edited Test 2') self.assertTrue(vl.commitChanges()) # Did we get it right? Let's create a new QgsVectorLayer and try to read back our changes: vl2 = QgsVectorLayer( '{} sslmode=disable srid=4326 key=\'"pk1","pk2","pk3"\' table="qgis_test"."tb_test_composite_float_pk" (geom)' .format(self.dbconn), "test_composite_float2", "mssql") self.assertTrue(vl2.isValid()) f2 = next( vl.getFeatures( QgsFeatureRequest().setFilterExpression('pk3 = 3.14159274'))) self.assertTrue(f2.isValid()) # just making sure we have the correct feature # Only 6 decimals for PostgreSQL 11. self.assertEqual(round(f2['pk3'], 6), round(3.14159274, 6)) # Then, making sure we really did change our value. self.assertEqual(f2['value'], 'Edited Test 2') # How about inserting a new field? f3 = QgsFeature(vl2.fields()) f3['pk1'] = 4 f3['pk2'] = -9223372036854775800 f3['pk3'] = 7.29154 f3['value'] = 'other test' vl.startEditing() res, f3 = vl.dataProvider().addFeatures([f3]) self.assertTrue(res) self.assertTrue(vl.commitChanges()) # can we catch it on another layer? f4 = next( vl2.getFeatures(QgsFeatureRequest().setFilterExpression( 'pk2 = -9223372036854775800'))) self.assertTrue(f4.isValid()) expected_attrs = [4, -9223372036854775800, 7.29154, 'other test'] gotten_attrs = [f4['pk1'], f4['pk2'], round(f4['pk3'], 5), f4['value']] self.assertEqual(gotten_attrs, expected_attrs) # Finally, let's delete one of the features. f5 = next( vl2.getFeatures( QgsFeatureRequest().setFilterExpression('pk3 = 7.29154'))) vl2.startEditing() vl2.deleteFeatures([f5.id()]) self.assertTrue(vl2.commitChanges()) # did we really delete? f_iterator = vl.getFeatures( QgsFeatureRequest().setFilterExpression('pk3 = 7.29154')) got_feature = True try: f6 = next(f_iterator) got_feature = f6.isValid() except StopIteration: got_feature = False self.assertFalse(got_feature)
def set_contour_properties(contour_file_path): """Set the X, Y, RGB, ROMAN attributes of the contour layer. :param contour_file_path: Path of the contour layer. :type contour_file_path: str :raise: InvalidLayerError if anything is amiss with the layer. """ LOGGER.debug( 'Set_contour_properties requested for %s.' % contour_file_path) layer = QgsVectorLayer(contour_file_path, 'mmi-contours', "ogr") if not layer.isValid(): raise InvalidLayerError(contour_file_path) layer.startEditing() # Now loop through the db adding selected features to mem layer request = QgsFeatureRequest() for feature in layer.getFeatures(request): if not feature.isValid(): LOGGER.debug('Skipping feature') continue # Work out x and y line = feature.geometry().asPolyline() y = line[0].y() x_max = line[0].x() x_min = x_max for point in line: if point.y() < y: y = point.y() x = point.x() if x < x_min: x_min = x if x > x_max: x_max = x x = x_min + ((x_max - x_min) / 2) # Get length length = feature.geometry().length() mmi_value = float(feature[contour_mmi_field['field_name']]) # We only want labels on the whole number contours if mmi_value != round(mmi_value): roman = '' else: roman = romanise(mmi_value) # RGB from http://en.wikipedia.org/wiki/Mercalli_intensity_scale rgb = mmi_colour(mmi_value) # Now update the feature feature_id = feature.id() layer.changeAttributeValue( feature_id, field_index_from_definition(layer, contour_x_field), x) layer.changeAttributeValue( feature_id, field_index_from_definition(layer, contour_y_field), y) layer.changeAttributeValue( feature_id, field_index_from_definition(layer, contour_colour_field), rgb) layer.changeAttributeValue( feature_id, field_index_from_definition(layer, contour_roman_field), roman) layer.changeAttributeValue( feature_id, field_index_from_definition(layer, contour_halign_field), 'Center') layer.changeAttributeValue( feature_id, field_index_from_definition(layer, contour_valign_field), 'HALF') layer.changeAttributeValue( feature_id, field_index_from_definition(layer, contour_length_field), length) layer.commitChanges()
def testTypeValidation(self): """Test that incompatible types in attributes raise errors""" vl = QgsVectorLayer( 'Point?crs=epsg:4326&field=int:integer', 'test', 'memory') self.assertTrue(vl.isValid()) invalid = QgsFeature(vl.fields()) invalid.setAttribute('int', 'A string') invalid.setGeometry(QgsGeometry.fromWkt('point(9 45)')) self.assertTrue(vl.startEditing()) # Validation happens on commit self.assertTrue(vl.addFeatures([invalid])) self.assertFalse(vl.commitChanges()) self.assertTrue(vl.rollBack()) self.assertFalse(vl.hasFeatures()) # Add a valid feature valid = QgsFeature(vl.fields()) valid.setAttribute('int', 123) self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeatures([valid])) self.assertTrue(vl.commitChanges()) self.assertEqual(vl.featureCount(), 1) f = vl.getFeature(1) self.assertEqual(f.attribute('int'), 123) # Add both vl = QgsVectorLayer( 'Point?crs=epsg:4326&field=int:integer', 'test', 'memory') self.assertEqual(vl.featureCount(), 0) self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeatures([valid, invalid])) self.assertFalse(vl.commitChanges()) self.assertEqual(vl.featureCount(), 2) self.assertTrue(vl.rollBack()) self.assertEqual(vl.featureCount(), 0) # Add both swapped vl = QgsVectorLayer( 'Point?crs=epsg:4326&field=int:integer', 'test', 'memory') self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeatures([invalid, valid])) self.assertFalse(vl.commitChanges()) self.assertEqual(vl.featureCount(), 2) self.assertTrue(vl.rollBack()) self.assertEqual(vl.featureCount(), 0) # Change attribute value vl = QgsVectorLayer( 'Point?crs=epsg:4326&field=int:integer', 'test', 'memory') self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeatures([valid])) self.assertTrue(vl.commitChanges()) self.assertTrue(vl.startEditing()) self.assertTrue(vl.changeAttributeValue(1, 0, 'A string')) self.assertFalse(vl.commitChanges()) f = vl.getFeature(1) self.assertEqual(f.attribute('int'), 'A string') self.assertTrue(vl.rollBack()) f = vl.getFeature(1) self.assertEqual(f.attribute('int'), 123) # Change attribute values vl = QgsVectorLayer( 'Point?crs=epsg:4326&field=int:integer', 'test', 'memory') self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeatures([valid])) self.assertTrue(vl.commitChanges()) self.assertTrue(vl.startEditing()) self.assertTrue(vl.changeAttributeValues(1, {0: 'A string'})) self.assertFalse(vl.commitChanges()) f = vl.getFeature(1) self.assertEqual(f.attribute('int'), 'A string') self.assertTrue(vl.rollBack()) f = vl.getFeature(1) self.assertEqual(f.attribute('int'), 123) ############################################## # Test direct data provider calls # No rollback (old behavior) vl = QgsVectorLayer( 'Point?crs=epsg:4326&field=int:integer', 'test', 'memory') dp = vl.dataProvider() self.assertFalse(dp.addFeatures([valid, invalid])[0]) self.assertEqual([f.attributes() for f in dp.getFeatures()], [[123]]) f = vl.getFeature(1) self.assertEqual(f.attribute('int'), 123) # Roll back vl = QgsVectorLayer( 'Point?crs=epsg:4326&field=int:integer', 'test', 'memory') dp = vl.dataProvider() self.assertFalse(dp.addFeatures([valid, invalid], QgsFeatureSink.RollBackOnErrors)[0]) self.assertFalse(dp.hasFeatures()) # Expected behavior for changeAttributeValues is to always roll back self.assertTrue(dp.addFeatures([valid])[0]) self.assertFalse(dp.changeAttributeValues({1: {0: 'A string'}})) f = vl.getFeature(1) self.assertEqual(f.attribute('int'), 123)
def link_irrig_swat(self): APEXMOD_path_dict = self.dirs_and_paths() # self.layer = QgsProject.instance().mapLayersByName("mf_grid (MODFLOW)")[0] # input1 = QgsProject.instance().mapLayersByName("mf_grid (MODFLOW)")[0] # provider = self.layer.dataProvider() # # Find *.wel file and read number of grid cells # for filename in glob.glob(str(APEXMOD_path_dict['MODFLOW'])+"/*.wel"): # with open(filename, "r") as f: # data = [] # for line in f.readlines(): # if not line.startswith("#"): # data.append(line.replace('\n', '').split()) # wel_row = [] # wel_col = [] # nWell = int(data[0][0]) # # Skip two lines in Riv package and get row and col # for i in range(2, nWell+2): # wel_row.append(int(data[i][1])) # wel_col.append(int(data[i][2])) # # Find grid cells according to the well package # feats = self.layer.getFeatures() # wel_matched = [] # for f in feats: # rowNo = f.attribute("row") # colNo = f.attribute("col") # for i in range(len(wel_row)): # if ((rowNo == wel_row[i]) and (colNo == wel_col[i])): # wel_matched.append(f.id()) # self.layer.selectByIds(wel_matched) output_dir = APEXMOD_path_dict['Scenarios'] name_ext = "irrig_swat_grid.shp" irrig_swat_grid = os.path.join(output_dir, name_ext) # Create layer field layer_swat_col = QgsVectorLayer(irrig_swat_grid, '{0}'.format("irrig_swat_grid"), 'ogr') lyrProvider = layer_swat_col.dataProvider() if lyrProvider.fields().indexFromName('layer') == -1: lyr_field = QgsField('layer', QVariant.Int) lyrProvider.addAttributes([lyr_field]) layer_swat_col.updateFields() # Get the index numbers of the fields lyrIdx = lyrProvider.fields().indexFromName('layer') # Get features (Find out a way to change attribute values using another field) feats = layer_swat_col.getFeatures() layer_swat_col.startEditing() # add layer number for f in feats: layer_swat_col.changeAttributeValue(f.id(), lyrIdx, 1) layer_swat_col.commitChanges() # Join sub and hru id n3_ext = "irrig_swat_grid_s.shp" irrig_swat_grid_s = os.path.join(output_dir, n3_ext) # QgsVectorFileWriter.deleteShapeFile(irrig_mf_s) sub_shp = QgsProject.instance().mapLayersByName("sub (SWAT)")[0] processing.run("qgis:joinattributesbylocation", irrig_swat_grid, sub_shp, ['intersects'], 0, 0, "sum,mean,min,max,median", 0, irrig_swat_grid_s) # Join sub id n4_ext = "irrig_swat_grid_f.shp" irrig_swat_grid_f = os.path.join(output_dir, n4_ext) # QgsVectorFileWriter.deleteShapeFile(irrig_mf_f) hru_shp = QgsProject.instance().mapLayersByName("hru (SWAT)")[0] processing.run("qgis:joinattributesbylocation", irrig_swat_grid_s, hru_shp, ['intersects'], 0, 0, "sum,mean,min,max,median", 0, irrig_swat_grid_f) layer_swat = QgsVectorLayer(irrig_swat_grid_f, '{0}'.format("irrig_swat"), 'ogr') QgsProject.instance().addMapLayer(layer_swat, False) root = QgsProject.instance().layerTreeRoot() p_swat_tree = root.findGroup("Pumping from SWAT") p_swat_tree.insertChildNode(0, QgsLayerTreeLayer(layer_swat)) self.dlg.lineEdit_irrig_swat_grids.setText(irrig_swat_grid_f) # delete unnecessary fields input2 = QgsProject.instance().mapLayersByName("irrig_swat")[0] fields = input2.dataProvider() fdname = [ fields.indexFromName(field.name()) for field in fields.fields() if not ( field.name() == 'Subbasin' or field.name() == 'row' or field.name( ) == 'col' or field.name() == 'HRU_ID' or field.name() == 'layer') ] fields.deleteAttributes(fdname) input2.updateFields() msgBox.setWindowTitle("Created!") msgBox.setText( "'irrig_swat.shp' file has been created!\n" + "If you have multiple HRUs for a well, open its Attribute table and modify it." ) msgBox.exec_()
def download_data(self): # Get user selection group_code = self.cbGroups.itemData(self.cbGroups.currentIndex()) domain_code = self.cbDomains.itemData(self.cbDomains.currentIndex()) element_code = self.cbElements.itemData(self.cbElements.currentIndex()) item_code = self.cbItems.itemData(self.cbItems.currentIndex()) download_folder = self.download_folder.text() # Check selection if group_code is None: self.bar.pushMessage(None, self.tr('Please select a group'), level=QgsMessageBar.CRITICAL) elif domain_code is None: self.bar.pushMessage(None, self.tr('Please select a domain'), level=QgsMessageBar.CRITICAL) elif element_code is None: self.bar.pushMessage(None, self.tr('Please select an element'), level=QgsMessageBar.CRITICAL) elif item_code is None: self.bar.pushMessage(None, self.tr('Please select an item'), level=QgsMessageBar.CRITICAL) elif download_folder is None or len(download_folder) == 0: self.bar.pushMessage(None, self.tr('Please select a download folder'), level=QgsMessageBar.CRITICAL) else: # Get data data = get_data(domain_code, element_code, item_code) # Notify the user self.bar.pushMessage(None, self.tr('Downloaded rows: ') + str(len(data)), level=QgsMessageBar.INFO) # Layer name layer_name = self.cbItems.currentText().replace(' ', '_') + '_' + self.cbElements.currentText().replace(' ', '_') folder_name = os.path.join(download_folder, group_code, domain_code) if not os.path.exists(folder_name): os.makedirs(folder_name) # Copy template layer output_file = copy_layer(folder_name, layer_name) layer = QgsVectorLayer(output_file, 'layer_name', 'ogr') # Add all the years to the layer feature_idx = 64 year_to_be_shown = 2014 number_of_nulls = 0 for year in range(2014, 1960, -1): progress = (1 + (feature_idx - 64)) * 1.86 self.progress.setValue(progress) self.progress_label.setText('<b>' + self.tr('Progress') + ': ' + '</b> ' + self.tr('Adding Year ') + str(year)) year_data = self.get_year_data(data, year) layer.dataProvider().addAttributes([QgsField(str(year), QVariant.Double)]) if len(year_data) > 0: layer.startEditing() for feature in layer.getFeatures(): if feature['FAOSTAT'] is not None: feature_code = str(feature['FAOSTAT']) for d in year_data: data_code = str(d['code']) if data_code == feature_code: value = d['value'] layer.changeAttributeValue(feature.id(), (feature_idx), float(value)) tmp_feature = QgsFeature() tmp_feature.setAttributes([float(value)]) layer.dataProvider().addFeatures([tmp_feature]) if value is None: number_of_nulls += 1 layer.commitChanges() else: year_to_be_shown -= 1 feature_idx += 1 # Add layer to canvas if self.add_to_canvas.isChecked(): renderer = self.create_join_renderer(layer, str(year_to_be_shown), 11, QgsGraduatedSymbolRendererV2.Pretty) l = QgsVectorLayer(output_file, layer_name + '(' + str(year_to_be_shown) + ')', 'ogr') r = renderer.clone() r.setClassAttribute(str(year_to_be_shown)) l.setRendererV2(r) QgsMapLayerRegistry.instance().addMapLayer(l) self.iface.legendInterface().setLayerVisible(l, True) # Close pop-up self.dlg.close()
def download_data(self): # Get user selection group_code = self.cbGroups.itemData(self.cbGroups.currentIndex()) domain_code = self.cbDomains.itemData(self.cbDomains.currentIndex()) element_code = self.cbElements.itemData(self.cbElements.currentIndex()) item_code = self.cbItems.itemData(self.cbItems.currentIndex()) download_folder = self.download_folder.text() # Check selection if group_code is None: self.bar.pushMessage(None, self.tr('Please select a group'), level=QgsMessageBar.CRITICAL) elif domain_code is None: self.bar.pushMessage(None, self.tr('Please select a domain'), level=QgsMessageBar.CRITICAL) elif element_code is None: self.bar.pushMessage(None, self.tr('Please select an element'), level=QgsMessageBar.CRITICAL) elif item_code is None: self.bar.pushMessage(None, self.tr('Please select an item'), level=QgsMessageBar.CRITICAL) elif download_folder is None or len(download_folder) == 0: self.bar.pushMessage(None, self.tr('Please select a download folder'), level=QgsMessageBar.CRITICAL) else: # Get data data = get_data(domain_code, element_code, item_code) # Notify the user self.bar.pushMessage(None, self.tr('Downloaded rows: ') + str(len(data)), level=QgsMessageBar.INFO) # Layer name layer_name = self.cbItems.currentText().replace( ' ', '_') + '_' + self.cbElements.currentText().replace( ' ', '_') folder_name = os.path.join(download_folder, group_code, domain_code) if not os.path.exists(folder_name): os.makedirs(folder_name) # Copy template layer output_file = copy_layer(folder_name, layer_name) layer = QgsVectorLayer(output_file, 'layer_name', 'ogr') # Add all the years to the layer feature_idx = 64 year_to_be_shown = 2014 number_of_nulls = 0 for year in range(2014, 1960, -1): progress = (1 + (feature_idx - 64)) * 1.86 self.progress.setValue(progress) self.progress_label.setText('<b>' + self.tr('Progress') + ': ' + '</b> ' + self.tr('Adding Year ') + str(year)) year_data = self.get_year_data(data, year) layer.dataProvider().addAttributes( [QgsField(str(year), QVariant.Double)]) if len(year_data) > 0: layer.startEditing() for feature in layer.getFeatures(): if feature['FAOSTAT'] is not None: feature_code = str(feature['FAOSTAT']) for d in year_data: data_code = str(d['code']) if data_code == feature_code: value = d['value'] layer.changeAttributeValue( feature.id(), (feature_idx), float(value)) tmp_feature = QgsFeature() tmp_feature.setAttributes([float(value)]) layer.dataProvider().addFeatures( [tmp_feature]) if value is None: number_of_nulls += 1 layer.commitChanges() else: year_to_be_shown -= 1 feature_idx += 1 # Add layer to canvas if self.add_to_canvas.isChecked(): renderer = self.create_join_renderer( layer, str(year_to_be_shown), 11, QgsGraduatedSymbolRendererV2.Pretty) l = QgsVectorLayer( output_file, layer_name + '(' + str(year_to_be_shown) + ')', 'ogr') r = renderer.clone() r.setClassAttribute(str(year_to_be_shown)) l.setRendererV2(r) QgsMapLayerRegistry.instance().addMapLayer(l) self.iface.legendInterface().setLayerVisible(l, True) # Close pop-up self.dlg.close()
def processing(options, f, progressBar, progressMessage): ''' Select trees which are on the contour of the forest and isolated trees. ''' # Export Grid contour and isolated to crowns values forestSelectedPath = options['dst'] + 'tif/' + f + \ '_forest_selected.tif' crownsPath = options['dst'] + 'shp/' + f + '_crowns.shp' # crownsStatsPath = options['dst'] + 'shp/' + f + '_crowns_stats.shp' outputDir = options["dst"] fileTxt = open(outputDir + "/log.txt", "a") fileTxt.write("gridstatisticsforpolygons started\n") fileTxt.close() crowns = QgsVectorLayer(crownsPath, "crowns", "ogr") inputStatRaster = QgsRasterLayer(forestSelectedPath, "forestSelected") z_stat = QgsZonalStatistics(crowns, inputStatRaster, '_', 1, QgsZonalStatistics.Max) result_z_stat = z_stat.calculateStatistics(QgsFeedback()) outputDir = options["dst"] fileTxt = open(outputDir + "/log.txt", "a") fileTxt.write("gridstatisticsforpolygons passed\n") fileTxt.close() # crowns = QgsVectorLayer(crownsStatsPath, 'Crowns stats', 'ogr') crowns.selectByExpression('"_max"=1.0') selected_array = crowns.getValues("N", True) crowns.invertSelection() unselected_array = crowns.getValues("N", True) unselected_crowns_ids = crowns.getValues("$id", True) unselected_top_ids = crowns.getValues('"N" - 1', True) crowns.dataProvider().deleteFeatures(unselected_crowns_ids[0]) treetopsPath = options['dst'] + 'shp/' + f + '_treetops.shp' treetops = QgsVectorLayer(treetopsPath, 'Tree tops', 'ogr') treetops.dataProvider().deleteFeatures(unselected_top_ids[0]) treetopsSelectedPath = options['dst'] + 'shp/' + f + \ '_treetops_selected.shp' crownsSelectedPath = options['dst'] + 'shp/' + f + '_crowns_selected.shp' treetopsTrianglesPath = options['dst'] + 'shp/' + f + \ '_treetops_triangles.shp' outputDir = options["dst"] fileTxt = open(outputDir + "/log.txt", "a") fileTxt.write("advancedpythonfieldcalculator started\n") fileTxt.close() treetops.dataProvider().addAttributes([QgsField('N', QVariant.Int)]) treetops.updateFields() treetops.startEditing() for treetop in treetops.getFeatures(): treetops.changeAttributeValue(treetop.id(), treetop.fieldNameIndex('N'), treetop.id()) treetops.commitChanges() outputDir = options["dst"] fileTxt = open(outputDir + "/log.txt", "a") fileTxt.write("joinattributesbylocation started\n") fileTxt.close() # Adapted from https://github.com/qgis/QGIS-Processing # TODO: replace by native QGIS c++ algo when available... crowns.dataProvider().addAttributes([QgsField('tid', QVariant.Int)]) crowns.updateFields() crowns.startEditing() fcount = crowns.featureCount() counter = 0 for crown in crowns.getFeatures(): counter += 1 progressBar.setValue(100 + int(counter * (600 / fcount))) progressMessage.setText('Joining crown ' + str(counter) + '/' + str(fcount)) request = QgsFeatureRequest() request.setFilterRect(crown.geometry().boundingBox()) dp = treetops.dataProvider() for r in dp.getFeatures(request): if crown.geometry().intersects(r.geometry()): crowns.changeAttributeValue(crown.id(), crown.fieldNameIndex('tid'), r.id()) crowns.commitChanges() fileTxt = open(outputDir + "/log.txt", "a") fileTxt.write("delaunaytriangulation started\n") fileTxt.close() # delaunay triangulation Adapted from official Python plugin # TODO: replace by native QGIS c++ algo when available... fields = QgsFields() fields.append(QgsField('POINTA', QVariant.Double, '', 24, 15)) fields.append(QgsField('POINTB', QVariant.Double, '', 24, 15)) fields.append(QgsField('POINTC', QVariant.Double, '', 24, 15)) crs = QgsCoordinateReferenceSystem('EPSG:2056') triangleFile = QgsVectorFileWriter(treetopsTrianglesPath, 'utf-8', fields, QgsWkbTypes.Polygon, crs, 'ESRI Shapefile') pts = [] ptDict = {} ptNdx = -1 c = voronoi.Context() features = treetops.getFeatures() total = 100.0 / treetops.featureCount() if treetops.featureCount() else 0 progressMessage.setText('Starting triangulation...') for current, inFeat in enumerate(features): geom = QgsGeometry(inFeat.geometry()) if geom.isNull(): continue if geom.isMultipart(): points = geom.asMultiPoint() else: points = [geom.asPoint()] for n, point in enumerate(points): x = point.x() y = point.y() pts.append((x, y)) ptNdx += 1 ptDict[ptNdx] = (inFeat.id(), n) progressMessage.setText('Triangulation step 1 ok') if len(pts) < 3: raise QgsProcessingException( 'Input file should contain at least 3 points. Choose ' 'another file and try again.') uniqueSet = set(item for item in pts) ids = [pts.index(item) for item in uniqueSet] sl = voronoi.SiteList([voronoi.Site(*i) for i in uniqueSet]) c.triangulate = True voronoi.voronoi(sl, c) triangles = c.triangles feat = QgsFeature() total = 100.0 / len(triangles) if triangles else 1 for current, triangle in enumerate(triangles): indices = list(triangle) indices.append(indices[0]) polygon = [] attrs = [] step = 0 for index in indices: fid, n = ptDict[ids[index]] request = QgsFeatureRequest().setFilterFid(fid) inFeat = next(treetops.getFeatures(request)) geom = QgsGeometry(inFeat.geometry()) point = QgsPoint(geom.asPoint()) polygon.append(point) if step <= 3: attrs.append(ids[index]) step += 1 linestring = QgsLineString(polygon) poly = QgsPolygon() poly.setExteriorRing(linestring) feat.setAttributes(attrs) geometry = QgsGeometry().fromWkt(poly.asWkt()) feat.setGeometry(geometry) triangleFile.addFeature(feat) progressMessage.setText('Triangulation terminated') # Remove triangles with perimeter higher than threshold triangles = QgsVectorLayer(treetopsTrianglesPath, 'triangles', 'ogr') maxPeri = str(options['MaxTrianglePerimeter']) triangles.selectByExpression('$perimeter > ' + maxPeri) triangles_to_delete_ids = triangles.getValues("$id", True) triangles.dataProvider().deleteFeatures(triangles_to_delete_ids[0]) outputDir = options["dst"] fileTxt = open(outputDir + "/log.txt", "a") fileTxt.write("treeSelector passed\n") fileTxt.close() progressMessage.setText('Starting convexhull computing...')
def testShpZipSupport(self): ''' Test support for multi layer compressed shapefiles (.shp.zip) ''' if int(osgeo.gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION( 3, 1, 0): return tmpfile = os.path.join(self.basetestpath, 'testShpZipSupport.shp.zip') ds = osgeo.ogr.GetDriverByName('ESRI Shapefile').CreateDataSource( tmpfile) lyr = ds.CreateLayer('layer1', geom_type=osgeo.ogr.wkbPoint) lyr.CreateField(osgeo.ogr.FieldDefn('attr', osgeo.ogr.OFTInteger)) f = osgeo.ogr.Feature(lyr.GetLayerDefn()) f.SetField('attr', 1) f.SetGeometry(osgeo.ogr.CreateGeometryFromWkt('POINT(0 0)')) lyr.CreateFeature(f) f = None lyr = ds.CreateLayer('layer2', geom_type=osgeo.ogr.wkbMultiLineString) lyr.CreateField(osgeo.ogr.FieldDefn('attr', osgeo.ogr.OFTInteger)) f = osgeo.ogr.Feature(lyr.GetLayerDefn()) f.SetField('attr', 2) f.SetGeometry(osgeo.ogr.CreateGeometryFromWkt('LINESTRING(0 0,1 1)')) lyr.CreateFeature(f) f = None ds = None vl1 = QgsVectorLayer(tmpfile + '|layername=layer1', 'test', 'ogr') vl2 = QgsVectorLayer(tmpfile + '|layername=layer2', 'test', 'ogr') self.assertTrue(vl1.isValid()) self.assertTrue(vl2.isValid()) self.assertEqual(vl1.wkbType(), QgsWkbTypes.Point) self.assertEqual(vl2.wkbType(), QgsWkbTypes.MultiLineString) f1 = next(vl1.getFeatures()) f2 = next(vl2.getFeatures()) assert f1['attr'] == 1 self.assertEqual(f1.geometry().constGet().asWkt(), 'Point (0 0)') assert f2['attr'] == 2 self.assertEqual(f2.geometry().constGet().asWkt(), 'MultiLineString ((0 0, 1 1))') self.assertTrue(vl1.startEditing()) self.assertTrue(vl2.startEditing()) self.assertTrue(vl1.changeAttributeValue(f1.id(), 0, -1)) self.assertTrue(vl2.changeAttributeValue(f2.id(), 0, -2)) self.assertTrue(vl1.commitChanges()) self.assertTrue(vl2.commitChanges()) f = next(vl1.getFeatures()) assert f['attr'] == -1 f = next(vl2.getFeatures()) assert f['attr'] == -2 # Check DataItem registry = QgsApplication.dataItemProviderRegistry() ogrprovider = next(provider for provider in registry.providers() if provider.name() == 'OGR') item = ogrprovider.createDataItem(tmpfile, None) children = item.createChildren() self.assertEqual(len(children), 2) uris = sorted([children[i].uri() for i in range(2)]) self.assertIn('testShpZipSupport.shp.zip|layername=layer1', uris[0]) self.assertIn('testShpZipSupport.shp.zip|layername=layer2', uris[1]) gdalprovider = next(provider for provider in registry.providers() if provider.name() == 'GDAL') item = gdalprovider.createDataItem(tmpfile, None) assert not item
def _test(autoTransaction): """Test buffer methods within and without transactions - create a feature - save - retrieve the feature - change geom and attrs - test changes are seen in the buffer """ def _check_feature(wkt): f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), wkt) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.geometry().asWkt().upper(), wkt) ml = QgsVectorLayer( 'Point?crs=epsg:4326&field=int:integer&field=int2:integer', 'test', 'memory') self.assertTrue(ml.isValid()) d = QTemporaryDir() options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'layer_a' err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3( ml, os.path.join(d.path(), 'transaction_test.gpkg'), QgsCoordinateTransformContext(), options) self.assertEqual(err, QgsVectorFileWriter.NoError) self.assertTrue(os.path.isfile(newFileName)) layer_a = QgsVectorLayer(newFileName + '|layername=layer_a') self.assertTrue(layer_a.isValid()) project = QgsProject() project.setAutoTransaction(autoTransaction) project.addMapLayers([layer_a]) ########################################### # Tests with a new feature self.assertTrue(layer_a.startEditing()) buffer = layer_a.editBuffer() f = QgsFeature(layer_a.fields()) f.setAttribute('int', 123) f.setGeometry(QgsGeometry.fromWkt('point(7 45)')) self.assertTrue(layer_a.addFeatures([f])) _check_feature('POINT (7 45)') # Need to fetch the feature because its ID is NULL (-9223372036854775808) f = next(layer_a.getFeatures()) self.assertEqual(len(buffer.addedFeatures()), 1) layer_a.undoStack().undo() self.assertEqual(len(buffer.addedFeatures()), 0) layer_a.undoStack().redo() self.assertEqual(len(buffer.addedFeatures()), 1) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 123) # Now change attribute self.assertEqual(buffer.changedAttributeValues(), {}) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.changeAttributeValue(f.id(), 1, 321) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 321]) self.assertEqual(len(buffer.addedFeatures()), 1) # This is surprising: because it was a new feature it has been changed directly self.assertEqual(buffer.changedAttributeValues(), {}) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 321) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.undoStack().undo() self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 123]) self.assertEqual(buffer.changedAttributeValues(), {}) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 123) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute('int'), 123) # Change multiple attributes spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.changeAttributeValues(f.id(), {1: 321, 2: 456}) self.assertEqual(len(spy_attribute_changed), 2) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 321]) self.assertEqual(spy_attribute_changed[1], [f.id(), 2, 456]) buffer = layer_a.editBuffer() # This is surprising: because it was a new feature it has been changed directly self.assertEqual(buffer.changedAttributeValues(), {}) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.undoStack().undo() # This is because QgsVectorLayerUndoCommandChangeAttribute plural if not autoTransaction: layer_a.undoStack().undo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute('int'), 123) self.assertEqual(f.attribute('int2'), None) self.assertEqual(len(spy_attribute_changed), 2) self.assertEqual( spy_attribute_changed[1 if autoTransaction else 0], [f.id(), 2, None]) self.assertEqual( spy_attribute_changed[0 if autoTransaction else 1], [f.id(), 1, 123]) # Change geometry f = next(layer_a.getFeatures()) spy_geometry_changed = QSignalSpy(layer_a.geometryChanged) self.assertTrue( layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) self.assertTrue(len(spy_geometry_changed), 1) self.assertEqual(spy_geometry_changed[0][0], f.id()) self.assertEqual(spy_geometry_changed[0][1].asWkt(), QgsGeometry.fromWkt('point(9 43)').asWkt()) _check_feature('POINT (9 43)') self.assertEqual(buffer.changedGeometries(), {}) layer_a.undoStack().undo() _check_feature('POINT (7 45)') self.assertEqual(buffer.changedGeometries(), {}) self.assertTrue( layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) _check_feature('POINT (9 43)') self.assertTrue( layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(10 44)'))) _check_feature('POINT (10 44)') # This is another surprise: geometry edits get collapsed into a single # one because they have the same hardcoded id layer_a.undoStack().undo() _check_feature('POINT (7 45)') self.assertTrue(layer_a.commitChanges()) ########################################### # Tests with the existing feature # Get the feature f = next(layer_a.getFeatures()) self.assertTrue(f.isValid()) self.assertEqual(f.attribute('int'), 123) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)') # Change single attribute self.assertTrue(layer_a.startEditing()) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.changeAttributeValue(f.id(), 1, 321) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 321]) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {1: {1: 321}}) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(1), 321) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.undoStack().undo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(1), 123) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 123]) self.assertEqual(buffer.changedAttributeValues(), {}) # Change attributes spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.changeAttributeValues(f.id(), {1: 111, 2: 654}) self.assertEqual(len(spy_attribute_changed), 2) self.assertEqual(spy_attribute_changed[0], [1, 1, 111]) self.assertEqual(spy_attribute_changed[1], [1, 2, 654]) f = next(layer_a.getFeatures()) self.assertEqual(f.attributes(), [1, 111, 654]) self.assertEqual(buffer.changedAttributeValues(), {1: { 1: 111, 2: 654 }}) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.undoStack().undo() # This is because QgsVectorLayerUndoCommandChangeAttribute plural if not autoTransaction: layer_a.undoStack().undo() self.assertEqual(len(spy_attribute_changed), 2) self.assertEqual( spy_attribute_changed[0 if autoTransaction else 1], [1, 1, 123]) self.assertEqual( spy_attribute_changed[1 if autoTransaction else 0], [1, 2, None]) f = next(layer_a.getFeatures()) self.assertEqual(f.attributes(), [1, 123, None]) self.assertEqual(buffer.changedAttributeValues(), {}) # Change geometry spy_geometry_changed = QSignalSpy(layer_a.geometryChanged) self.assertTrue( layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) self.assertEqual(spy_geometry_changed[0][0], 1) self.assertEqual(spy_geometry_changed[0][1].asWkt(), QgsGeometry.fromWkt('point(9 43)').asWkt()) f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (9 43)') self.assertEqual(buffer.changedGeometries()[1].asWkt().upper(), 'POINT (9 43)') spy_geometry_changed = QSignalSpy(layer_a.geometryChanged) layer_a.undoStack().undo() self.assertEqual(spy_geometry_changed[0][0], 1) self.assertEqual(spy_geometry_changed[0][1].asWkt(), QgsGeometry.fromWkt('point(7 45)').asWkt()) self.assertEqual(buffer.changedGeometries(), {}) f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)') self.assertEqual(buffer.changedGeometries(), {}) # Delete an existing feature self.assertTrue(layer_a.deleteFeature(f.id())) with self.assertRaises(StopIteration): next(layer_a.getFeatures()) self.assertEqual(buffer.deletedFeatureIds(), [f.id()]) layer_a.undoStack().undo() self.assertTrue(layer_a.getFeature(f.id()).isValid()) self.assertEqual(buffer.deletedFeatureIds(), []) ########################################### # Test delete # Delete a new feature f = QgsFeature(layer_a.fields()) f.setAttribute('int', 555) f.setGeometry(QgsGeometry.fromWkt('point(8 46)')) self.assertTrue(layer_a.addFeatures([f])) f = [ f for f in layer_a.getFeatures() if f.attribute('int') == 555 ][0] self.assertTrue(f.id() in buffer.addedFeatures()) self.assertTrue(layer_a.deleteFeature(f.id())) self.assertFalse(f.id() in buffer.addedFeatures()) self.assertFalse(f.id() in buffer.deletedFeatureIds()) layer_a.undoStack().undo() self.assertTrue(f.id() in buffer.addedFeatures()) ########################################### # Add attribute field = QgsField('attr1', QVariant.String) self.assertTrue(layer_a.addAttribute(field)) self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), [field]) layer_a.undoStack().undo() self.assertEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), []) layer_a.undoStack().redo() self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), [field]) self.assertTrue(layer_a.commitChanges()) ########################################### # Remove attribute self.assertTrue(layer_a.startEditing()) buffer = layer_a.editBuffer() attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) self.assertTrue(layer_a.deleteAttribute(attr_idx)) self.assertEqual(buffer.deletedAttributeIds(), [attr_idx]) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) layer_a.undoStack().undo() self.assertEqual(buffer.deletedAttributeIds(), []) self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx) # This is totally broken at least on OGR/GPKG: the rollback # does not restore the original fields if False: layer_a.undoStack().redo() self.assertEqual(buffer.deletedAttributeIds(), [attr_idx]) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) # Rollback! self.assertTrue(layer_a.rollBack()) self.assertIn('attr1', layer_a.dataProvider().fields().names()) self.assertIn('attr1', layer_a.fields().names()) self.assertEqual(layer_a.fields().names(), layer_a.dataProvider().fields().names()) attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) self.assertTrue(layer_a.startEditing()) attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) ########################################### # Rename attribute attr_idx = layer_a.fields().lookupField(field.name()) self.assertEqual(layer_a.fields().lookupField('new_name'), -1) self.assertTrue(layer_a.renameAttribute(attr_idx, 'new_name')) self.assertEqual(layer_a.fields().lookupField('new_name'), attr_idx) layer_a.undoStack().undo() self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx) self.assertEqual(layer_a.fields().lookupField('new_name'), -1) layer_a.undoStack().redo() self.assertEqual(layer_a.fields().lookupField('new_name'), attr_idx) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) ############################################# # Try hard to make this fail for transactions if autoTransaction: self.assertTrue(layer_a.commitChanges()) self.assertTrue(layer_a.startEditing()) f = next(layer_a.getFeatures()) # Do for i in range(10): spy_attribute_changed = QSignalSpy( layer_a.attributeValueChanged) layer_a.changeAttributeValue(f.id(), 2, i) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 2, i]) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {f.id(): { 2: i }}) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), i) # Undo/redo for i in range(9): # Undo spy_attribute_changed = QSignalSpy( layer_a.attributeValueChanged) layer_a.undoStack().undo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), 8 - i) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 2, 8 - i]) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {f.id(): { 2: 8 - i }}) # Redo spy_attribute_changed = QSignalSpy( layer_a.attributeValueChanged) layer_a.undoStack().redo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), 9 - i) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 2, 9 - i]) # Undo again spy_attribute_changed = QSignalSpy( layer_a.attributeValueChanged) layer_a.undoStack().undo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), 8 - i) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 2, 8 - i]) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {f.id(): { 2: 8 - i }}) # Last check f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), 8 - i) self.assertEqual(buffer.changedAttributeValues(), {f.id(): { 2: 0 }}) layer_a.undoStack().undo() buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {}) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), None)
def create_path_with_scratch_layer(self, path_links): # Create TSP route crs = self.link_layer.dataProvider().crs().authid() vl = QgsVectorLayer(f"LineString?crs={crs}", 'TSP Solution', "memory") pr = vl.dataProvider() # add fields pr.addAttributes(self.link_layer.dataProvider().fields()) vl.updateFields( ) # tell the vector layer to fetch changes from the provider idx = self.link_layer.dataProvider().fieldNameIndex('link_id') self.link_features = {} for feat in self.link_layer.getFeatures(): link_id = feat.attributes()[idx] self.link_features[link_id] = feat # add a feature all_links = [] for k in path_links: fet = self.link_features[k] all_links.append(fet) # add all links to the temp layer pr.addFeatures(all_links) # add layer to the map QgsProject.instance().addMapLayer(vl) symbol = vl.renderer().symbol() symbol.setWidth(1.6) qgis.utils.iface.mapCanvas().refresh() # Create TSP stops crs = self.node_layer.dataProvider().crs().authid() nl = QgsVectorLayer(f"Point?crs={crs}", 'TSP Stops', "memory") pn = nl.dataProvider() # add fields pn.addAttributes(self.node_layer.dataProvider().fields()) nl.updateFields( ) # tell the vector layer to fetch changes from the provider idx = self.node_layer.dataProvider().fieldNameIndex('node_id') self.node_features = {} for feat in self.node_layer.getFeatures(): node_id = feat.attributes()[idx] self.node_features[node_id] = feat # add the feature stop_nodes = [] seq = {} for i, k in enumerate(self.worker_thread.node_sequence[:-1]): fet = self.node_features[k] stop_nodes.append(fet) seq[k] = i + 1 # add all links to the temp layer pn.addFeatures(stop_nodes) # Goes back and adds the order of visitation for each node pn.addAttributes([QgsField('sequence', QVariant.Int)]) nl.updateFields() sdx = nl.dataProvider().fieldNameIndex('sequence') nl.startEditing() for feat in nl.getFeatures(): node_id = feat.attributes()[idx] nl.changeAttributeValue(feat.id(), sdx, seq[node_id]) nl.commitChanges() # add layer to the map QgsProject.instance().addMapLayer(nl) symbol = QgsMarkerSymbol.createSimple({'name': 'star', 'color': 'red'}) symbol.setSize(6) nl.renderer().setSymbol(symbol) qgis.utils.iface.mapCanvas().refresh()
def testGeopackageTwoLayerEdition(self): ''' test https://issues.qgis.org/issues/17034 ''' tmpfile = os.path.join(self.basetestpath, 'testGeopackageTwoLayerEdition.gpkg') ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) lyr = ds.CreateLayer('layer1', geom_type=ogr.wkbPoint) lyr.CreateField(ogr.FieldDefn('attr', ogr.OFTInteger)) f = ogr.Feature(lyr.GetLayerDefn()) f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)')) lyr.CreateFeature(f) f = None lyr = ds.CreateLayer('layer2', geom_type=ogr.wkbPoint) lyr.CreateField(ogr.FieldDefn('attr', ogr.OFTInteger)) f = ogr.Feature(lyr.GetLayerDefn()) f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(1 1)')) lyr.CreateFeature(f) f = None ds = None vl1 = QgsVectorLayer(u'{}'.format(tmpfile) + "|layername=layer1", u'layer1', u'ogr') vl2 = QgsVectorLayer(u'{}'.format(tmpfile) + "|layername=layer2", u'layer2', u'ogr') # Edit vl1, vl2 multiple times self.assertTrue(vl1.startEditing()) self.assertTrue(vl2.startEditing()) self.assertTrue(vl1.changeGeometry(1, QgsGeometry.fromWkt('Point (2 2)'))) self.assertTrue(vl2.changeGeometry(1, QgsGeometry.fromWkt('Point (3 3)'))) self.assertTrue(vl1.commitChanges()) self.assertTrue(vl2.commitChanges()) self.assertTrue(vl1.startEditing()) self.assertTrue(vl2.startEditing()) self.assertTrue(vl1.changeAttributeValue(1, 1, 100)) self.assertTrue(vl2.changeAttributeValue(1, 1, 101)) self.assertTrue(vl1.commitChanges()) self.assertTrue(vl2.commitChanges()) self.assertTrue(vl1.startEditing()) self.assertTrue(vl2.startEditing()) self.assertTrue(vl1.changeGeometry(1, QgsGeometry.fromWkt('Point (4 4)'))) self.assertTrue(vl2.changeGeometry(1, QgsGeometry.fromWkt('Point (5 5)'))) self.assertTrue(vl1.commitChanges()) self.assertTrue(vl2.commitChanges()) vl1 = None vl2 = None # Check everything is as expected after re-opening vl1 = QgsVectorLayer(u'{}'.format(tmpfile) + "|layername=layer1", u'layer1', u'ogr') vl2 = QgsVectorLayer(u'{}'.format(tmpfile) + "|layername=layer2", u'layer2', u'ogr') got = [feat for feat in vl1.getFeatures()][0] got_geom = got.geometry() self.assertEqual(got['attr'], 100) reference = QgsGeometry.fromWkt('Point (4 4)') self.assertEqual(got_geom.asWkb(), reference.asWkb(), 'Expected {}, got {}'.format(reference.asWkt(), got_geom.asWkt())) got = [feat for feat in vl2.getFeatures()][0] got_geom = got.geometry() self.assertEqual(got['attr'], 101) reference = QgsGeometry.fromWkt('Point (5 5)') self.assertEqual(got_geom.asWkb(), reference.asWkb(), 'Expected {}, got {}'.format(reference.asWkt(), got_geom.asWkt()))
def generate_guide_file(self): """Generates the guide file, if CheckBPlanned.isChecked then add_to_db is called. Finalising with calling on the cleanup function.""" path = self.path[:self.path.index('tmp_files123')] file_name = path + 'guide_file_{f}_{g}.shp'.format( f=check_text(self.dlg.CBFieldList.currentText()), g=datetime.date(datetime.today()).isoformat()) if os.path.isfile(file_name): msgBox = QMessageBox() msgBox.setText( self. tr('You have already created a guide file for this field today, do you want to replace it?' )) msgBox.addButton(QPushButton(self.tr('Yes')), QMessageBox.YesRole) msgBox.addButton(QPushButton(self.tr('No')), QMessageBox.NoRole) res = msgBox.exec_() if res == 1: return try: for ending in ['dbf', 'prj', 'shp', 'shx']: os.remove(file_name[:-3] + ending) except PermissionError: QMessageBox.information( None, self.tr('Error'), self. tr('The file could not automatically be removed, please try to do it manually and create the guide file again' )) return params = { 'INPUT': self.path + "raster_output.tif", 'BAND': 1, 'OUTPUT': file_name, 'FIELD': 'indexValue' } alg_name = 'gdal:polygonize' try: processing.run(alg_name, params) vl = QgsVectorLayer(file_name, 'ferti_layert', 'ogr') vl.startEditing() ferti_field = QgsField('Fertilizin', QVariant.Int) vl.dataProvider().addAttributes([ferti_field]) vl.updateFields() idx = vl.dataProvider().fieldNameIndex('Fertilizin') for f in vl.getFeatures(): val = f.attributes()[0] if type(val) is not int: break ferti = int(np.interp(val, self.x_values, self.y_values)) vl.changeAttributeValue(f.id(), idx, ferti) vl.commitChanges() del vl self.file_name = file_name if self.dlg.CheckBPlanned.isChecked(): self.add_to_db() self.cleanup() except QgsProcessingException: QMessageBox.information( None, self.tr("Error:"), self. tr('Currently QGIS does not allow you to have any non English ' 'character in the directory path or filename')) return
def testProjectStorage(self): # New project without fileName p0 = QgsProject() self.assertTrue(p0.auxiliaryStorage().isValid()) # Create new layers with key otherwise auxiliary layers are not # automacially created when added in project vl0 = createLayer() vl0Shp = writeShape(vl0, 'vl0.shp') vl1 = createLayer() vl1Shp = writeShape(vl1, 'vl1.shp') vl0 = QgsVectorLayer(vl0Shp, 'points', 'ogr') self.assertTrue(vl0.isValid()) vl1 = QgsVectorLayer(vl1Shp, 'points', 'ogr') self.assertTrue(vl1.isValid()) # Add layers to project and check underlying auxiliary layers p0.addMapLayers([vl0, vl1]) self.assertTrue(vl0.loadAuxiliaryLayer(p0.auxiliaryStorage(), 'pk')) self.assertTrue(vl1.loadAuxiliaryLayer(p0.auxiliaryStorage(), 'num_char')) al0 = vl0.auxiliaryLayer() al1 = vl1.auxiliaryLayer() self.assertEqual(al0.joinInfo().targetFieldName(), 'pk') self.assertEqual(al1.joinInfo().targetFieldName(), 'num_char') # Add a field in auxiliary layers pdef0 = QgsPropertyDefinition('propname', QgsPropertyDefinition.DataTypeNumeric, '', '', 'ut') self.assertTrue(al0.addAuxiliaryField(pdef0)) pdef1 = QgsPropertyDefinition('propname1', QgsPropertyDefinition.DataTypeString, '', '', 'ut') self.assertTrue(al1.addAuxiliaryField(pdef1)) # Check auxiliary fields names af0Name = QgsAuxiliaryLayer.nameFromProperty(pdef0, False) self.assertEqual(af0Name, 'ut_propname') af1Name = QgsAuxiliaryLayer.nameFromProperty(pdef1, False) self.assertEqual(af1Name, 'ut_propname1') # Set value for auxiliary fields req = QgsFeatureRequest().setFilterExpression("name = 'Honey'") f = QgsFeature() vl0.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) af0Name = QgsAuxiliaryLayer.nameFromProperty(pdef0, True) index0 = vl0.fields().indexOf(af0Name) vl0.changeAttributeValue(f.id(), index0, 333) req = QgsFeatureRequest().setFilterExpression("name = 'Apple'") f = QgsFeature() vl1.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) af1Name = QgsAuxiliaryLayer.nameFromProperty(pdef1, True) index1 = vl1.fields().indexOf(af1Name) vl1.changeAttributeValue(f.id(), index0, 'myvalue') req = QgsFeatureRequest().setFilterExpression("name = 'Orange'") f = QgsFeature() vl1.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) vl1.changeAttributeValue(f.id(), index0, 'myvalue1') # Save the project in a zip file f = tmpPath() + '.qgz' p0.write(f) # Open the zip file with embedded auxiliary storage p1 = QgsProject() p1.read(f) # Check that auxiliary fields are well loaded in layers self.assertEqual(len(p1.mapLayers().values()), 2) for vl in p1.mapLayers().values(): al = vl.auxiliaryLayer() self.assertEqual(len(al.auxiliaryFields()), 1) af = al.auxiliaryFields()[0] afPropDef = QgsAuxiliaryLayer.propertyDefinitionFromField(af) self.assertEqual(afPropDef.origin(), 'ut') if vl.auxiliaryLayer().joinInfo().targetFieldName() == 'pk': self.assertEqual(afPropDef.name(), 'propname') self.assertEqual(al.featureCount(), 1) req = QgsFeatureRequest().setFilterExpression("name = 'Honey'") f = QgsFeature() vl.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) self.assertEqual(f.attributes()[index0], 333.0) else: # num_char self.assertEqual(al.featureCount(), 2) self.assertEqual(afPropDef.name(), 'propname1') req = QgsFeatureRequest().setFilterExpression("name = 'Apple'") f = QgsFeature() vl.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) self.assertEqual(f.attributes()[index1], 'myvalue') req = QgsFeatureRequest().setFilterExpression("name = 'Orange'") f = QgsFeature() vl.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) self.assertEqual(f.attributes()[index1], 'myvalue1')
def set_contour_properties(contour_file_path): """Set the X, Y, RGB, ROMAN attributes of the contour layer. :param contour_file_path: Path of the contour layer. :type contour_file_path: str :raise: InvalidLayerError if anything is amiss with the layer. """ LOGGER.debug('Set_contour_properties requested for %s.' % contour_file_path) layer = QgsVectorLayer(contour_file_path, 'mmi-contours', "ogr") if not layer.isValid(): raise InvalidLayerError(contour_file_path) layer.startEditing() # Now loop through the db adding selected features to mem layer request = QgsFeatureRequest() for feature in layer.getFeatures(request): if not feature.isValid(): LOGGER.debug('Skipping feature') continue # Work out x and y line = feature.geometry().asPolyline() y = line[0].y() x_max = line[0].x() x_min = x_max for point in line: if point.y() < y: y = point.y() x = point.x() if x < x_min: x_min = x if x > x_max: x_max = x x = x_min + ((x_max - x_min) / 2) # Get length length = feature.geometry().length() mmi_value = float(feature[contour_mmi_field['field_name']]) # We only want labels on the whole number contours if mmi_value != round(mmi_value): roman = '' else: roman = romanise(mmi_value) # RGB from http://en.wikipedia.org/wiki/Mercalli_intensity_scale rgb = mmi_colour(mmi_value) # Now update the feature feature_id = feature.id() layer.changeAttributeValue( feature_id, field_index_from_definition(layer, contour_x_field), x) layer.changeAttributeValue( feature_id, field_index_from_definition(layer, contour_y_field), y) layer.changeAttributeValue( feature_id, field_index_from_definition(layer, contour_colour_field), rgb) layer.changeAttributeValue( feature_id, field_index_from_definition(layer, contour_roman_field), roman) layer.changeAttributeValue( feature_id, field_index_from_definition(layer, contour_halign_field), 'Center') layer.changeAttributeValue( feature_id, field_index_from_definition(layer, contour_valign_field), 'HALF') layer.changeAttributeValue( feature_id, field_index_from_definition(layer, contour_length_field), length) layer.commitChanges()
def loadCSVLayer(gpsPath, logger, messageBar, dateFormat, mainWindow, messageBox): fields = ['date', 'time', 'x', 'y', 'altitude'] userfields = [] with open(gpsPath, 'rb') as csvfile: reader = csv.reader(csvfile, delimiter=',') i = 0 for row in reader: if i == 0: #header row #check for x for f in fields: Fre = re.search(f, str(row), re.I) if Fre: userfields.append(Fre.group()) else: # hang an error logger.error('CSV column names import error. Failed on: %s' % f) messageBox.critical(mainWindow, "Column Name Error", "Missing column: %s\n\nPlease reformat csv file. Column headers should include: 'date', 'time', 'x', 'y', 'altitude'" %(f)) else: pass i += 1 if i < 10: messageBox.warning(mainWindow, "Friendly Import Warning", "This track is pretty short, which if fine. However, some of the track smoothing and tour automation won't work great because it is geared for longer tracks. Give it a try anyway and let us know if you encounter an error or serious problem at https://github.com/EdFarrell/MilkMachine/issues" ) if len(userfields) == 5: logger.info('headers %s' % userfields) messageBar.pushMessage("Success", "User file column headers good: {0}".format(gpsPath), level=QgsMessageBar.INFO, duration=5) #http://qgis.org/api/classQgsVectorLayer.html layername = gpsPath.split(".")[0].split('/')[-1] #crs = QgsCoordinateReferenceSystem(4326).toProj4() crs = 'EPSG:4326' uri = "file:/" + gpsPath + "?delimiter=%s&xField=%s&yField=%s&crs=%s" % (",", "x", "y", crs) logger.info('uri: %s' % uri) Qlayer = QgsVectorLayer(uri, layername, "delimitedtext") # check the rest of the fields. required are date, time, and z fdict = field_indices(Qlayer) logger.info('fdict : %s' %(fdict)) # save the kml layer as shapepath = gpsPath.split(".")[0] + '.shp' shapepath_line = gpsPath.split(".")[0] + '_line.shp' #shapepath_dup = gpsPath.split(".")[0] + '_duplicate.shp' QgsVectorFileWriter.writeAsVectorFormat(Qlayer, shapepath, "utf-8", None, "ESRI Shapefile") # working copy #bring the shapefile back in, and render it on the map shaper = QgsVectorLayer(shapepath, layername, "ogr") shaper.dataProvider().addAttributes( [QgsField("datetime",QVariant.String), QgsField("camera",QVariant.String), QgsField("flyto",QVariant.String), QgsField("iconstyle", QVariant.String), QgsField("labelstyle", QVariant.String), QgsField("model", QVariant.String), QgsField("lookat", QVariant.String) , QgsField("symbtour", QVariant.String)]) shaper.updateFields() fields = field_indices(shaper) # calculate the datetime field # idx = fields['datetime'] #feature.attributes()[idx] fid_dt = [] # model_altitude = [] try: for f in shaper.getFeatures(): # currentatt = f.attributes()[fields['datetime']] # this should be fields['Name'] pointdate = f.attributes()[fields['date']] #2014/06/06 pointtime = f.attributes()[fields['time']] # format for microseconds sec_pieces = pointtime.split(':')[2].split('.') if len(sec_pieces) == 1: microsec = 0 elif len(sec_pieces) == 2: microsec = int(float('0.' + sec_pieces[1]) * 1000000) #['mm/dd/yyyy', 'dd/mm/yyyy', 'yyyy/mm/dd'] if dateFormat == 'mm/dd/yyyy': current_dt = datetime.datetime(int(pointdate.split('/')[2]), int(pointdate.split('/')[0]), int(pointdate.split('/')[1]), int(pointtime.split(':')[0]), int(pointtime.split(':')[1]), int(pointtime.split(':')[2]), microsec) elif dateFormat == 'dd/mm/yyyy': current_dt = datetime.datetime(int(pointdate.split('/')[2]), int(pointdate.split('/')[1]), int(pointdate.split('/')[0]), int(pointtime.split(':')[0]), int(pointtime.split(':')[1]), int(pointtime.split(':')[2]), microsec) elif dateFormat == 'yyyy/mm/dd': current_dt = datetime.datetime(int(pointdate.split('/')[0]), int(pointdate.split('/')[1]), int(pointdate.split('/')[2]), int(pointtime.split(':')[0]), int(pointtime.split(':')[1]), int(pointtime.split(':')[2]), microsec) fid_dt.append([f.id(), current_dt.strftime("%Y/%m/%d %H:%M:%S %f")]) shaper.startEditing() shaper.beginEditCommand('datetime') for i,v in enumerate(fid_dt): shaper.changeAttributeValue(v[0],fields['datetime'], v[1]) shaper.endEditCommand() shaper.commitChanges() return shaper except: logger.error('Error writing time to datetime column, user presented with messagebox') logger.exception(traceback.format_exc()) messageBox.critical(mainWindow,"Date & Time Import Error", "An error occured while converting the 'date' and 'time' fields into a Python datetime object. Please make sure that your specified the correct date format, and the time format is HH:MM:SS. If your seconds are fractional, then please express this as SS.xxxxxx")
class ReorderProcess(): """Along line point reordering according to given destination""" def __init__(self, exutoire, point_reseau): """Set all informations needed to order the network""" self.exutoire_layer = exutoire self.point_reseau_layer = point_reseau self.crs = QgsCoordinateReferenceSystem( self.point_reseau_layer.crs().authid()) # Create ouput self.output = QgsVectorLayer("Point", "point", "memory") self.output.setCrs(self.crs) # Add fields name_T_id = "T_id" name_L_id = "L_id" name_P_id = "P_id" name_nat = "nature" provider = self.output.dataProvider() caps = provider.capabilities() if caps & QgsVectorDataProvider.AddAttributes: res = provider.addAttributes([ QgsField(name_T_id, QVariant.String), QgsField(name_L_id, QVariant.String), QgsField(name_P_id, QVariant.String), QgsField(name_nat, QVariant.String) ]) self.output.updateFields() # Save field index self.index_nat = self.point_reseau_layer.fieldNameIndex('nature') self.index_pid = self.point_reseau_layer.fieldNameIndex('P_id') self.index_order = self.point_reseau_layer.fieldNameIndex('order') self.l_done = [] def reorder(self, pt, count_order): feat = QgsFeature(self.output.pendingFields()) pt_geom = pt.geometry() feat.setGeometry(pt_geom) tid = pt.attribute("T_id") lid = pt.attribute("L_id") ppid = pt.attribute("P_id") nat = pt.attribute("nature") if nat == 'start': self.output.startEditing() feat.setAttributes([tid, str(count_order), ppid, nat]) print 'reorder: %s' % ([tid, lid, ppid, nat, str(count_order)]) self.output.dataProvider().addFeatures([feat]) self.output.commitChanges() self.output.updateExtents() while nat != 'end': expr = QgsExpression('L_id = %s and P_id = %s' % (lid, str(int(ppid) + 1))) req = QgsFeatureRequest(expr) n_pt_it = self.point_reseau_layer.getFeatures(req) n_pt = n_pt_it.next() n_pt_it = None feat = QgsFeature(self.output.pendingFields()) n_pt_geom = n_pt.geometry() feat.setGeometry(n_pt_geom) tid = n_pt.attribute("T_id") lid = n_pt.attribute("L_id") ppid = n_pt.attribute("P_id") nat = n_pt.attribute("nature") self.output.startEditing() feat.setAttributes([tid, str(count_order), ppid, nat]) print[tid, lid, ppid, nat, str(count_order)] self.output.dataProvider().addFeatures([feat]) self.output.commitChanges() self.output.updateExtents() else: pid = 0 self.output.startEditing() feat.setAttributes([tid, str(count_order), str(pid), 'start']) print[tid, lid, str(pid), 'start', str(count_order)] self.output.dataProvider().addFeatures([feat]) self.output.commitChanges() self.output.updateExtents() nat = None feat = None while nat != 'start': ppid = str(int(ppid) - 1) expr = QgsExpression('L_id = %s and P_id = %s' % (lid, ppid)) req = QgsFeatureRequest(expr) n_pt_it = self.point_reseau_layer.getFeatures(req) n_pt = n_pt_it.next() n_pt_it = None feat = QgsFeature(self.output.pendingFields()) n_pt_geom = n_pt.geometry() feat.setGeometry(n_pt_geom) tid = n_pt.attribute("T_id") nat = n_pt.attribute("nature") if nat != 'start': pid += 1 self.output.startEditing() feat.setAttributes([tid, str(count_order), str(pid), nat]) print[tid, lid, str(pid), nat, str(count_order)] self.output.dataProvider().addFeatures([feat]) self.output.commitChanges() self.output.updateExtents() feat = None else: pid += 1 self.output.startEditing() feat.setAttributes( [tid, str(count_order), str(pid), 'end']) print[tid, lid, str(pid), 'end', str(count_order)] self.output.dataProvider().addFeatures([feat]) self.output.commitChanges() self.output.updateExtents() feat = None def executeReorder(self): count_order = 0 # loop over exutoire features to process several network for exutoire in self.exutoire_layer.getFeatures(): exutoire_geom = exutoire.geometry().buffer(1, 4).boundingBox() # Select the start point that intersects the outlet req = QgsFeatureRequest().setFilterRect(exutoire_geom) pts_reseau_sortie = self.point_reseau_layer.getFeatures(req) for pt_sortie in pts_reseau_sortie: count_order += 1 L_id = pt_sortie.attribute("L_id") # Reorder the points of the first line of the network self.reorder(pt_sortie, count_order) nat = 'end' string = "L_id = %s AND nature = '%s'" % (count_order, nat) print string expr = QgsExpression(string) reque = QgsFeatureRequest(expr) # Select the last point of the first line pt_end_it = self.output.getFeatures(reque) pt_end = pt_end_it.next() pt_end_it = None # Make a buffer around the point to define a boundingBox pt_end_geom = pt_end.geometry().buffer(1, 4).boundingBox() req = QgsFeatureRequest( QgsExpression("L_id != %s" % (str(L_id)))).setFilterRect(pt_end_geom) # Select the next points next_ls = self.point_reseau_layer.getFeatures(req) self.l_done.append(L_id) list_next = [] # Fill next_ls list with the next features for next_l in next_ls: list_next.append(next_l) # While there is features in list_next, reorder process continues while len(list_next) != 0: current_list = list_next list_next = [] # Loop over the next features for next_pt in current_list: # Get line id L_id = next_pt.attribute("L_id") print L_id # if the line has not been already reorder if L_id not in self.l_done: count_order += 1 #then reorder self.reorder(next_pt, count_order) string = "L_id = %s AND nature='%s'" % ( count_order, nat) print string expr = QgsExpression(string) req = QgsFeatureRequest(QgsExpression(expr)) pt_end_it = self.output.getFeatures(req) pt_end = pt_end_it.next() pt_end_it = None pt_end_geom = pt_end.geometry().buffer( 1, 4).boundingBox() # Find the next feature reque = QgsFeatureRequest( QgsExpression( "L_id != %s" % (L_id))).setFilterRect(pt_end_geom) next_ls = self.point_reseau_layer.getFeatures( reque) self.l_done.append(L_id) # Fill next_ls list again and loop for next_l in next_ls: list_next.append(next_l) print len(list_next) expr = QgsExpression("nature = 'end'") req = QgsFeatureRequest(expr) end_pts = self.output.getFeatures(req) change_dict = {} change_list = [] rm_ids = [] #clean lines that aren't a cross border anymore because a small part has been removed for end_pt in end_pts: end_pt_geom = end_pt.geometry().buffer(1, 4).boundingBox() end_pt_id = end_pt.id() end_lid = end_pt.attribute("L_id") end_pid = end_pt.attribute("P_id") expr = QgsExpression("L_id != '%s'" % (end_lid)) req = QgsFeatureRequest(expr).setFilterRect(end_pt_geom) int_pts = [] for int_pt in self.output.getFeatures(req): lid_int_pt = int_pt.attribute("L_id") int_pts.append(int_pt) if len(int_pts) == 1: rm_ids.append(end_pt_id) if int(end_lid) in change_dict: change_dict[int(lid_int_pt)] = change_dict[int(end_lid)] else: change_dict[int(lid_int_pt)] = int(end_lid) print change_dict change_dict = sorted(change_dict.items(), key=lambda t: t[0]) for ch_tuple in change_dict: print ch_tuple[0] end_lid = str(ch_tuple[1]) end_pid = None for end_pt in self.output.getFeatures( QgsFeatureRequest( QgsExpression("L_id = '%s' and nature = '%s'" % (end_lid, "end")))): if end_pid is None: end_pid = end_pt.attribute("P_id") elif int(end_pid) < int(end_pt.attribute("P_id")): end_pid = end_pt.attribute("P_id") expr = QgsExpression("L_id = '%s'" % (str(ch_tuple[0]))) req = QgsFeatureRequest(expr) for ch_pt in self.output.getFeatures(req): ch_pt_id = ch_pt.id() if ch_pt.attribute("nature") == "start": rm_ids.append(ch_pt_id) else: ch_tid = ch_pt.attribute("T_id") ch_nature = ch_pt.attribute("nature") self.output.startEditing() self.output.changeAttributeValue(ch_pt_id, 1, end_lid) self.output.changeAttributeValue(ch_pt_id, 2, end_pid) self.output.commitChanges() end_pid = int(end_pid) + 1 self.output.startEditing() self.output.deleteFeatures(rm_ids) self.output.commitChanges() return self.output, self.crs