def layer_from_source(source_uri, name): """Return QgsMapLayer from a given source uri. :param source_uri: A source URI :type source_uri: basestring :param name: Designated layer name :type name: basestring :return: QgsMapLayer :rtype: qgis.core.QgsMapLayer """ vector_extensions = ('shp', 'geojson') raster_extensions = ('asc', 'tiff', 'tif', 'geotiff', 'geotif') qlr_extensions = ('qlr', ) qgis_layer = None if is_file_path(source_uri): # sanitize source_uri sanitized_uri = urllib.unquote(source_uri).decode('utf-8') sanitized_uri.replace('file://', '') if source_uri.endswith(vector_extensions): qgis_layer = QgsVectorLayer(sanitized_uri, name, 'ogr') elif source_uri.endswith(raster_extensions): qgis_layer = QgsRasterLayer(sanitized_uri, name) elif source_uri.endswith(qlr_extensions): qgis_layer = QgsMapLayer.fromLayerDefinitionFile(sanitized_uri) if qgis_layer: qgis_layer = qgis_layer[0] qgis_layer.setName(name) elif is_tile_path(source_uri): # sanitize source_uri sanitized_uri = urllib.unquote(source_uri).decode('utf-8') # Check if it is only a url if sanitized_uri.startswith(('http://', 'https://')): # Then it is probably a tile xyz url sanitized_uri = 'type=xyz&url={0}'.format(sanitized_uri) # It might be in the form of query string query_params = urlparse.parse_qs(sanitized_uri) driver = query_params.get('driver', 'wms') qgis_layer = QgsRasterLayer(sanitized_uri, name, driver) return qgis_layer
def testLayerChangeDirtiesProject(self): """ Test that making changes to certain layer properties results in dirty projects """ p = QgsProject() l = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "points.shp"), "points", "ogr") self.assertTrue(l.isValid()) self.assertTrue(p.addMapLayers([l])) p.setDirty(False) l.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) self.assertTrue(p.isDirty()) p.setDirty(False) l.setName('test') self.assertTrue(p.isDirty()) p.setDirty(False) self.assertTrue(l.setSubsetString('class=\'a\'')) self.assertTrue(p.isDirty())
def load_vector(self, csv_file, qml_file=None): # uri = "file:///{}?encoding=UTF-8&delimiter=,&xField=LON&yField=LAT&crs=EPSG:4326".format(regnie_csv_file) # -> was working, simpler variant: # uri = "{}{}?delimiter=,&xField=LON&yField=LAT".format('file:///', regnie_csv_file) # but not on Windows - needs crs specified: uri = "{}{}?delimiter=,&xField=LON&yField=LAT&crs=EPSG:4326".format( "file:///", csv_file) self.out("uri: {}".format(uri)) # Make a vector layer: csv_layer = QgsVectorLayer(uri, csv_file.name, "delimitedtext") if not csv_layer.isValid(): self._show_message(Qgis.Critical, csv_file.name) return layer_name = Path(csv_file).stem self._layer_name = layer_name csv_layer.setName(layer_name) self._remove_layer_with_same_name(layer_name) self._insert_layer(csv_layer, qml_file, 5)
def _create_named_layer(self, json_src, layer_name, zoom_level, merge_features, geo_type): """ * Creates a QgsVectorLayer and adds it to the group specified by layer_target_group * Invalid geometries will be removed during the process of merging features over tile boundaries """ # layer_with_zoom = "{}{}{}".format(layer_name, VtReader._zoom_level_delimiter, zoom_level) layer = QgsVectorLayer(json_src, layer_name, "ogr") layer.setCustomProperty("vector_tile_source", self.source.source()) layer.setCustomProperty("zoom_level", zoom_level) layer.setShortName(layer_name) layer.setDataUrl(self.source.source()) if self.source.name() and "openmaptiles" in self.source.name().lower(): layer.setDataUrl(remove_key(self.source.source())) layer.setAttribution(u"Vector Tiles © Klokan Technologies GmbH (CC-BY), Data © OpenStreetMap contributors (ODbL)") layer.setAttributionUrl("https://openmaptiles.com/hosting/") if merge_features and geo_type in [GeoTypes.LINE_STRING, GeoTypes.POLYGON]: layer = FeatureMerger().merge_features(layer) layer.setName(layer_name) return layer
def startDraw(self): # Create and add the new layer layer = QgsVectorLayer('Polygon?crs=epsg:4326', providerLib='memory') layer.renderer().symbol().setColor(QColor.fromRgb(160, 82, 45)) layer.setName(f'search aoi') QgsProject.instance().addMapLayer(layer) # Use the add feature tool self.iface.setActiveLayer(layer) # Function called when the feature is added to the layer def featureAdded(): # Disconnect from the signal layer.featureAdded.disconnect() # Save changes and end edit mode layer.commitChanges() # Select the feature then fill the input feature = layer.selectAll() self.fillPolygonInput() # Connect the layer to the signal featureAdded layer.featureAdded.connect(featureAdded) layer.startEditing() self.iface.actionAddFeature().trigger()
def testSaveLoadProject(self): schema_uri = self.encode_uri(self.ds_uri, self.schema) project_uri = self.encode_uri(self.ds_uri, self.schema, 'abc') self.dropProjectsTable() # make sure we have a clean start prj = QgsProject() uri = self.vl.source() vl1 = QgsVectorLayer(uri, 'test', self.provider) self.assertEqual(vl1.isValid(), True) prj.addMapLayer(vl1) prj_storage = QgsApplication.projectStorageRegistry( ).projectStorageFromType(self.project_storage_type) self.assertTrue(prj_storage) lst0 = prj_storage.listProjects(schema_uri) self.assertEqual(lst0, []) # try to save project in the database prj.setFileName(project_uri) res = prj.write() self.assertTrue(res) lst1 = prj_storage.listProjects(schema_uri) self.assertEqual(lst1, ["abc"]) # now try to load the project back prj2 = QgsProject() prj2.setFileName(project_uri) res = prj2.read() self.assertTrue(res) self.assertEqual(len(prj2.mapLayers()), 1) self.assertEqual(prj2.baseName(), "abc") self.assertEqual(prj2.absoluteFilePath(), "") # path not supported for project storages self.assertTrue( abs(prj2.lastModified().secsTo(QDateTime.currentDateTime())) < 10) lastModified = prj2.lastModified() # try to see project's metadata res, metadata = prj_storage.readProjectStorageMetadata(project_uri) self.assertTrue(res) self.assertEqual(metadata.name, "abc") time_project = metadata.lastModified time_now = QDateTime.currentDateTime() time_diff = time_now.secsTo(time_project) self.assertTrue(abs(time_diff) < 10) # try to update the project vl1.setName("testNew") prj.write() prj3 = QgsProject() prj3.setFileName(project_uri) res = prj3.read() self.assertTrue(res) prj4 = QgsProject() prj4.setFileName(project_uri) res = prj4.read() self.assertTrue(res) self.assertEqual(len(prj4.mapLayers()), 1) self.assertEqual(list(prj4.mapLayers().values())[0].name(), "testNew") self.assertEqual(prj4.baseName(), "abc") self.assertEqual(prj4.absoluteFilePath(), "") # path not supported for project storages self.assertTrue(prj4.lastModified() > lastModified) # try to remove the project res = prj_storage.removeProject(project_uri) self.assertTrue(res) lst2 = prj_storage.listProjects(schema_uri) self.assertEqual(lst2, []) self.dropProjectsTable( ) # make sure we have a clean finish... "leave no trace"
class Layer: ''' wrapper of a vector layer in the QGIS layer tree with some convenient functions. Can be grouped and addressed by its name. ''' def __init__(self, layername: str, data_path: str, groupname: str = '', prepend: bool = True): ''' Parameters ---------- layername : str name of the layer in the data source data_path : str path to the data source of the layer groupname : str, optional name of the parent group, will be created if not existing, can be nested by joining groups with '/' e.g. 'Projekt/Hintergrundkarten', defaults to add layer to the root of the layer tree prepend : bool prepend the group of the layer if True (prepends each group if nested), append if False, defaults to prepending the group ''' self.layername = layername self.data_path = data_path self.layer = None self._l = None self.groupname = groupname self.prepend = prepend @property def parent(self) -> QgsLayerTreeGroup: ''' the parent group of the layer ''' parent = QgsProject.instance().layerTreeRoot() if self.groupname: parent = Layer.add_group(self.groupname, prepend=self.prepend) return parent @property def _tree_layer(self) -> QgsLayerTreeLayer: ''' tree representation of the layer ''' if not self.layer: return None return self.parent.findLayer(self.layer) @property def layer(self) -> QgsVectorLayer: ''' the wrapped vector layer ''' try: layer = self._layer if layer is not None: # call function on layer to check if it still exists layer.id() except RuntimeError: return None return layer @layer.setter def layer(self, layer: QgsVectorLayer): self._layer = layer @classmethod def add_group(cls, groupname: str, prepend: bool = True) -> QgsLayerTreeGroup: ''' add a group to the layer tree Parameters ---------- groupname : str name of the parent group, will be created if not existing, can be nested by joining groups with '/' e.g. 'Projekt/Hintergrundkarten' prepend : bool, optional prepend the group if True (prepends each group if nested), append if False, defaults to prepending the group Returns ---------- QgsLayerTreeGroup the created group (the deepest one in hierarchy if nested) ''' groupnames = groupname.split('/') parent = QgsProject.instance().layerTreeRoot() group = cls._nest_groups(parent, groupnames, prepend=prepend) return group @classmethod def _nest_groups(cls, parent: QgsLayerTreeGroup, groupnames: List[str], prepend: bool = True) -> QgsLayerTreeGroup: '''recursively nests groups in order of groupnames''' if len(groupnames) == 0: return parent next_parent = parent.findGroup(groupnames[0]) if not next_parent: next_parent = (parent.insertGroup(0, groupnames[0]) if prepend else parent.addGroup(groupnames[0])) return cls._nest_groups(next_parent, groupnames[1:], prepend=prepend) @classmethod def find(cls, label: str, groupname: str = '') -> List[QgsLayerTreeLayer]: ''' deep find tree layer by name in a group recursively Parameters ---------- label : str label of the tree layer groupname : str, optional name of the group to search in, can be nested by joining groups with '/' e.g. 'Projekt/Hintergrundkarten', defaults to searching in layer tree root Returns ---------- list list of tree layers matching the name, empty list if none found ''' parent = QgsProject.instance().layerTreeRoot() if groupname: groupnames = groupname.split('/') while groupnames: g = groupnames.pop(0) parent = parent.findGroup(g) if not parent: return [] def deep_find(node, label): found = [] if node: for child in node.children(): if child.name() == label: found.append(child) found.extend(deep_find(child, label)) return found found = deep_find(parent, label) return found def draw(self, style_path: str = None, label: str = '', redraw: str = True, checked: bool = True, filter: str = None, expanded: bool = True, prepend: bool = False) -> QgsVectorLayer: ''' load the data into a vector layer, draw it and add it to the layer tree Parameters ---------- label : str, optional label of the layer, defaults to layer name this is initialized with style_path : str, optional a QGIS style (.qml) can be applied to the layer, defaults to no style redraw : bool, optional replace old layer with same name in same group if True, only create if not existing if set to False, else it is refreshed, defaults to redrawing the layer checked: bool, optional set check state of layer in layer tree, defaults to being checked filter: str, optional QGIS filter expression to filter the layer, defaults to no filtering expanded: str, optional sets the legend to expanded or not, defaults to an expanded legend prepend: bool, optional prepend the layer to the other layers in its group if True, append it if False, defaults to appending the layer Returns ---------- QgsVectorLayer the created, replaced or refreshed vector layer ''' if not self.layer: layers = Layer.find(label, groupname=self.groupname) if layers: self.layer = layers[0].layer() if redraw: self.remove() else: iface.mapCanvas().refreshAllLayers() if not self.layer: self.layer = QgsVectorLayer(self.data_path, self.layername, "ogr") if label: self.layer.setName(label) QgsProject.instance().addMapLayer(self.layer, False) self.layer.loadNamedStyle(style_path) tree_layer = self._tree_layer if not tree_layer: tree_layer = self.parent.insertLayer(0, self.layer) if prepend else\ self.parent.addLayer(self.layer) tree_layer.setItemVisibilityChecked(checked) tree_layer.setExpanded(expanded) if filter is not None: self.layer.setSubsetString(filter) return self.layer def set_visibility(self, state: bool): ''' change check state of layer, layer is not visible if unchecked Parameters ---------- state: bool set check state of layer in layer tree ''' tree_layer = self._tree_layer if tree_layer: tree_layer.setItemVisibilityChecked(state) def zoom_to(self): ''' zooms map canvas to the extent of this layer ''' if not self.layer: return canvas = iface.mapCanvas() self.layer.updateExtents() transform = QgsCoordinateTransform( self.layer.crs(), canvas.mapSettings().destinationCrs(), QgsProject.instance()) canvas.setExtent(transform.transform(self.layer.extent())) def remove(self): ''' remove the layer from map and layer tree ''' if not self.layer: return QgsProject.instance().removeMapLayer(self.layer.id()) self.layer = None
def open_file( dialog=None, osm_file=None, output_geom_types=None, white_list_column=None, layer_name="OsmFile", config_outputs=None, output_dir=None, final_query=None, prefix_file=None): """ Open an osm file. Memory layer if no output directory is set, or Geojson in the output directory. :param final_query: The query where the file comes from. Might be empty if it's a local OSM file. :type final_query: basestring """ outputs = {} if output_dir: for layer in ['points', 'lines', 'multilinestrings', 'multipolygons']: if not prefix_file: prefix_file = layer_name outputs[layer] = join( output_dir, prefix_file + "_" + layer + ".geojson") if isfile(outputs[layer]): raise FileOutPutException(suffix='(' + outputs[layer] + ')') # Legacy, waiting to remove the OsmParser for QGIS >= 3.6 # Change in osm_file_dialog.py L131 too output_geom_legacy = [l.value.lower() for l in output_geom_types] if not white_list_column: white_list_column = {} white_list_legacy = ( {l.value.lower(): csv for l, csv in white_list_column.items()} ) LOGGER.info('The OSM file is: {}'.format(osm_file)) # Parsing the file osm_parser = OsmParser( osm_file=osm_file, layers=output_geom_legacy, white_list_column=white_list_legacy) osm_parser.signalText.connect(dialog.set_progress_text) osm_parser.signalPercentage.connect(dialog.set_progress_percentage) start_time = time.time() layers = osm_parser.parse() elapsed_time = time.time() - start_time parser_time = time.strftime("%Hh %Mm %Ss", time.gmtime(elapsed_time)) LOGGER.info('The OSM parser took: {}'.format(parser_time)) # Finishing the process with geojson or memory layer num_layers = 0 for i, (layer, item) in enumerate(layers.items()): dialog.set_progress_percentage(i / len(layers) * 100) QApplication.processEvents() if item['featureCount'] and LayerType(layer.capitalize()) in output_geom_types: final_layer_name = layer_name # If configOutputs is not None (from My Queries) if config_outputs: if config_outputs[layer]['namelayer']: final_layer_name = config_outputs[layer]['namelayer'] if output_dir: dialog.set_progress_text(tr('From memory to GeoJSON: ' + layer)) # Transforming the vector file osm_geometries = { 'points': QgsWkbTypes.Point, 'lines': QgsWkbTypes.LineString, 'multilinestrings': QgsWkbTypes.MultiLineString, 'multipolygons': QgsWkbTypes.MultiPolygon} memory_layer = item['vector_layer'] encoding = get_default_encoding() writer = QgsVectorFileWriter( outputs[layer], encoding, memory_layer.fields(), osm_geometries[layer], memory_layer.crs(), "GeoJSON") for f in memory_layer.getFeatures(): writer.addFeature(f) del writer # Loading the final vector file new_layer = QgsVectorLayer(outputs[layer], final_layer_name, "ogr") else: new_layer = item['vector_layer'] new_layer.setName(final_layer_name) # Try to set styling if defined if config_outputs and config_outputs[layer]['style']: new_layer.loadNamedStyle(config_outputs[layer]['style']) else: # Loading default styles if layer == "multilinestrings" or layer == "lines": if "colour" in item['tags']: new_layer.loadNamedStyle( join(dirname(dirname(abspath(__file__))), "styles", layer + "_colour.qml")) # Add action about OpenStreetMap add_actions(new_layer, item['tags']) if final_query: QgsExpressionContextUtils.setLayerVariable( new_layer, 'quickosm_query', final_query) QgsProject.instance().addMapLayer(new_layer) num_layers += 1 return num_layers
def get_layer_description_from_browser(self, category): """Obtain the description of the browser layer selected by user. :param category: The category of the layer to get the description. :type category: string :returns: Tuple of boolean and string. Boolean is true if layer is validated as compatible for current role (impact function and category) and false otherwise. String contains a description of the selected layer or an error message. :rtype: tuple """ if category == 'hazard': browser = self.tvBrowserHazard elif category == 'exposure': browser = self.tvBrowserExposure elif category == 'aggregation': browser = self.tvBrowserAggregation else: raise InaSAFEError index = browser.selectionModel().currentIndex() if not index: return False, '' # Map the proxy model index to the source model index index = browser.model().mapToSource(index) item = browser.model().sourceModel().dataItem(index) if not item: return False, '' item_class_name = item.metaObject().className() # if not itemClassName.endswith('LayerItem'): if not item.type() == QgsDataItem.Layer: if item_class_name == 'QgsPGRootItem' and not item.children(): return False, create_postGIS_connection_first else: return False, '' if item_class_name not in [ 'QgsOgrLayerItem', 'QgsGdalLayerItem', 'QgsPGLayerItem', 'QgsLayerItem', ]: return False, '' path = item.path() if item_class_name in ['QgsOgrLayerItem', 'QgsGdalLayerItem', 'QgsLayerItem'] and not os.path.exists(path): return False, '' # try to create the layer if item_class_name == 'QgsOgrLayerItem': layer = QgsVectorLayer(path, '', 'ogr') elif item_class_name == 'QgsPGLayerItem': uri = self.postgis_path_to_uri(path) if uri: layer = QgsVectorLayer(uri.uri(), uri.table(), 'postgres') else: layer = None else: layer = QgsRasterLayer(path, '', 'gdal') if not layer or not layer.isValid(): return False, self.tr('Not a valid layer.') try: keywords = self.keyword_io.read_keywords(layer) if ('layer_purpose' not in keywords and 'impact_summary' not in keywords): keywords = None except (HashNotFoundError, OperationalError, NoKeywordsFoundError, KeywordNotFoundError, InvalidParameterError, UnsupportedProviderError, MissingMetadata): keywords = None # set the layer name for further use in the step_fc_summary if keywords: if qgis_version() >= 21800: layer.setName(keywords.get('title')) else: layer.setLayerName(keywords.get('title')) if not self.parent.is_layer_compatible(layer, category, keywords): label_text = '%s<br/>%s' % ( self.tr( 'This layer\'s keywords or type are not suitable:'), self.unsuitable_layer_description_html( layer, category, keywords)) return False, label_text # set the current layer (e.g. for the keyword creation sub-thread # or for adding the layer to mapCanvas) self.parent.layer = layer if category == 'hazard': self.parent.hazard_layer = layer elif category == 'exposure': self.parent.exposure_layer = layer else: self.parent.aggregation_layer = layer # Check if the layer is keywordless if keywords and 'keyword_version' in keywords: kw_ver = str(keywords['keyword_version']) self.parent.is_selected_layer_keywordless = ( not is_keyword_version_supported(kw_ver)) else: self.parent.is_selected_layer_keywordless = True desc = layer_description_html(layer, keywords) return True, desc
def add_layer_from_geopackage(gpkgfile, layer_name, categories_field=None): gpkgfile += f"|layername={layer_name}" l = QgsVectorLayer(gpkgfile) l.setName(layer_name) QgsProject.instance().addMapLayer(l) return l
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)
def open_file(dialog=None, osm_file=None, output_geom_types=None, white_list_column=None, layer_name="OsmFile", config_outputs=None, output_dir=None, prefix_file=None): """ Open an osm file. Memory layer if no output directory is set, or Geojson in the output directory. """ outputs = {} if output_dir: for layer in ['points', 'lines', 'multilinestrings', 'multipolygons']: if not prefix_file: prefix_file = layer_name outputs[layer] = join(output_dir, prefix_file + "_" + layer + ".geojson") if isfile(outputs[layer]): raise FileOutPutException(suffix='(' + outputs[layer] + ')') # Parsing the file osm_parser = OsmParser(osm_file=osm_file, layers=output_geom_types, white_list_column=white_list_column) osm_parser.signalText.connect(dialog.set_progress_text) osm_parser.signalPercentage.connect(dialog.set_progress_percentage) layers = osm_parser.parse() # Finishing the process with geojson or memory layer num_layers = 0 for i, (layer, item) in enumerate(layers.items()): dialog.set_progress_percentage(i / len(layers) * 100) QApplication.processEvents() if item['featureCount'] and layer in output_geom_types: final_layer_name = layer_name # If configOutputs is not None (from My Queries) if config_outputs: if config_outputs[layer]['namelayer']: final_layer_name = config_outputs[layer]['namelayer'] if output_dir: dialog.set_progress_text( tr("QuickOSM", u"From memory to GeoJSON: " + layer)) # Transforming the vector file osm_geometries = { 'points': QgsWkbTypes.Point, 'lines': QgsWkbTypes.LineString, 'multilinestrings': QgsWkbTypes.MultiLineString, 'multipolygons': QgsWkbTypes.MultiPolygon } memory_layer = item['vector_layer'] encoding = get_default_encoding() writer = QgsVectorFileWriter(outputs[layer], encoding, memory_layer.fields(), osm_geometries[layer], memory_layer.crs(), "GeoJSON") for f in memory_layer.getFeatures(): writer.addFeature(f) del writer # Loading the final vector file new_layer = QgsVectorLayer(outputs[layer], final_layer_name, "ogr") else: new_layer = item['vector_layer'] new_layer.setName(final_layer_name) # Try to set styling if defined if config_outputs and config_outputs[layer]['style']: new_layer.loadNamedStyle(config_outputs[layer]['style']) else: # Loading default styles if layer == "multilinestrings" or layer == "lines": if "colour" in item['tags']: new_layer.loadNamedStyle( join(dirname(dirname(abspath(__file__))), "styles", layer + "_colour.qml")) # Add action about OpenStreetMap actions = new_layer.actions() actions.addAction( QgsAction.OpenUrl, "OpenStreetMap Browser", 'http://www.openstreetmap.org/browse/' '[% "osm_type" %]/[% "osm_id" %]', False) actions.addAction( QgsAction.GenericPython, 'JOSM', 'from QuickOSM.CoreQuickOSM.Actions import Actions;' 'Actions.run("josm","[% "full_id" %]")', False) actions.addAction( QgsAction.OpenUrl, "User default editor", 'http://www.openstreetmap.org/edit?' '[% "osm_type" %]=[% "osm_id" %]', False) for link in ['url', 'website', 'wikipedia', 'ref:UAI']: if link in item['tags']: link = link.replace(":", "_") actions.addAction( QgsAction.GenericPython, link, 'from QuickOSM.core.actions import Actions;' 'Actions.run("' + link + '","[% "' + link + '" %]")', False) if 'network' in item['tags'] and 'ref' in item['tags']: actions.addAction( QgsAction.GenericPython, "Sketchline", 'from QuickOSM.core.actions import Actions;' 'Actions.run_sketch_line("[% "network" %]","[% "ref" %]")', False) QgsProject.instance().addMapLayer(new_layer) num_layers += 1 return num_layers
class MapBiomasAlertRequest(QObject): killProcess = pyqtSignal() currentProcess = pyqtSignal(str) finishedProcess = pyqtSignal() showExtentProcess = pyqtSignal() message = pyqtSignal(Qgis.MessageLevel, str) def __init__(self, canvas): super().__init__() self.nameCatalog = 'mapbiomas_alert_valid' self.apiMB = API_MapbiomasAlert() self.killProcess.connect(self.apiMB.kill) self.canvas = canvas self.project = QgsProject.instance() self.layerTreeRoot = self.project.layerTreeRoot() self.mapCanvasGeom = MapCanvasGeometry() self.pluginName = 'MapBiomas' self.crsCatalog = QgsCoordinateReferenceSystem('EPSG:4674') self.styleFile = 'mapbiomas_alert.qml' self.alert = None self.alert_id = None self.response = None self.isRunning = None def __del__(self): self.killProcess.disconnect(self.apiMB.kill) def _createCatalog(self): key_value = lambda k: "field={key}:{value}".format( key=k, value=self.apiMB.fields[k]['definition']) l_fields = [key_value(k) for k in self.apiMB.fields.keys()] l_fields.insert( 0, "Multipolygon?crs={}".format(self.crsCatalog.authid().lower())) l_fields.append('index=yes') uri = '&'.join(l_fields) self.alert = QgsVectorLayer(uri, self.nameCatalog, 'memory') self.alert.loadNamedStyle( os.path.join(os.path.dirname(__file__), self.styleFile)) self.alert_id = self.alert.id() def _responseFinished(self, response): self.response = response def actionsForm(self, nameAction, feature_id=None): """ Run action defined in layer, provide by style file :param nameAction: Name of action :params feature_id: Feature ID """ # Actions functions def flash(feature_id): geom = self.alert.getFeature(feature_id).geometry() self.mapCanvasGeom.flash([geom], self.alert) return {'isOk': True} def zoom(feature_id): geom = self.alert.getFeature(feature_id).geometry() self.mapCanvasGeom.zoom([geom], self.alert) return {'isOk': True} def report(feature_id): feat = self.alert.getFeature(feature_id) alerta_id = feat['alerta_id'] cars_ids = feat['cars'] if len(cars_ids) == 0: url = "{}/{}".format(API_MapbiomasAlert.urlReport, alerta_id) QDesktopServices.openUrl(QUrl(url)) else: for car_id in cars_ids.split('\n'): url = "{}/{}/car/{}".format(API_MapbiomasAlert.urlReport, alerta_id, car_id) QDesktopServices.openUrl(QUrl(url)) return {'isOk': True} actionsFunc = {'flash': flash, 'zoom': zoom, 'report': report} if not nameAction in actionsFunc.keys(): return { 'isOk': False, 'message': "Missing action '{}'".format(nameAction) } return actionsFunc[nameAction](feature_id) def requestPopulateCatalog(self): def getWktExtent(): crsCanvas = self.canvas.mapSettings().destinationCrs() ct = QgsCoordinateTransform(crsCanvas, self.crsCatalog, self.project) extent = self.canvas.extent( ) if crsCanvas == self.crsCatalog else ct.transform( self.canvas.extent()) return extent.asWktPolygon() def populate(features): provider = self.alert.dataProvider() for item in features: atts = [item[k] for k in self.apiMB.fields] feat = QgsFeature() feat.setAttributes(atts) geom = item['geometry'] if not geom is None: feat.setGeometry(geom) provider.addFeature(feat) del item def finished(response): self.response = response if not response['isOk']: self.message.emit(Qgis.Critical, response['message']) return if len(self.response['features']) == 0: self.message.emit(Qgis.Warning, "Inside this view don't have alerts") del response['features'] return populate(response['features']) del response['features'] self.message.emit(Qgis.Success, 'Finished OK') def closeTableAttribute(): layer_id = self.alert_id widgets = QApplication.instance().allWidgets() for tb in filter( lambda w: isinstance(w, QDialog) and layer_id in w. objectName(), widgets): tb.close() self.currentProcess.emit('Populate Catalog') existsCatalog = not self.alert is None and not self.project.mapLayer( self.alert_id) is None if not existsCatalog: self._createCatalog() else: name = "Receiving... - {}".format(self.nameCatalog) self.alert.setName(name) self.alert.dataProvider().truncate() # Delete all features closeTableAttribute() self.response = None self.calculateMetadata = True self.message.emit(Qgis.Info, 'Request features...') url = self.apiMB.getUrlAlerts(getWktExtent()) self.apiMB.getAlerts(url, finished) self.calculateMetadata = False if self.response['isOk']: if not existsCatalog: self.project.addMapLayer(self.alert, addToLegend=False) root = self.project.layerTreeRoot() root.insertLayer(0, self.alert).setCustomProperty( "showFeatureCount", True) else: self.alert.setName(self.nameCatalog) self.alert.triggerRepaint() else: root = self.project.layerTreeRoot() if not root.findLayer(self.alert) is None: root.removeLayer(self.alert) def searchAlert(self): self.currentProcess.emit('Check server') self.apiMB.isHostLive(self._responseFinished) if not self.response['isOk']: self.message.emit(Qgis.Critical, 'MapBioma server is out') self.finishedProcess.emit() return self.currentProcess.emit('Search alerts') if self.canvas.layerCount() == 0: msg = 'Need layer(s) in map' self.message.emit(Qgis.Warning, msg) else: self.apiMB.access.isKill = False self.showExtentProcess.emit() self.requestPopulateCatalog() self.finishedProcess.emit() @pyqtSlot() def onCancel(self): self.killProcess.emit()
def open_file( dialog=None, osm_file=None, output_geom_types=None, white_list_column=None, layer_name="OsmFile", config_outputs=None, output_dir=None, final_query=None, prefix_file=None): """ Open an osm file. Memory layer if no output directory is set, or Geojson in the output directory. :param final_query: The query where the file comes from. Might be empty if it's a local OSM file. :type final_query: basestring """ outputs = {} if output_dir: for layer in ['points', 'lines', 'multilinestrings', 'multipolygons']: if not prefix_file: prefix_file = layer_name outputs[layer] = join( output_dir, prefix_file + "_" + layer + ".geojson") if isfile(outputs[layer]): raise FileOutPutException(suffix='(' + outputs[layer] + ')') # Legacy, waiting to remove the OsmParser for QGIS >= 3.6 # Change in osm_file_dialog.py L131 too output_geom_legacy = [l.value.lower() for l in output_geom_types] if not white_list_column: white_list_column = {} white_list_legacy = ( {l.value.lower(): csv for l, csv in white_list_column.items()} ) LOGGER.info('The OSM file is: {}'.format(osm_file)) # Parsing the file osm_parser = OsmParser( osm_file=osm_file, layers=output_geom_legacy, white_list_column=white_list_legacy) osm_parser.signalText.connect(dialog.set_progress_text) osm_parser.signalPercentage.connect(dialog.set_progress_percentage) start_time = time.time() layers = osm_parser.parse() elapsed_time = time.time() - start_time parser_time = time.strftime("%Hh %Mm %Ss", time.gmtime(elapsed_time)) LOGGER.info('The OSM parser took: {}'.format(parser_time)) # Finishing the process with geojson or memory layer num_layers = 0 for i, (layer, item) in enumerate(layers.items()): dialog.set_progress_percentage(i / len(layers) * 100) QApplication.processEvents() if item['featureCount'] and ( LayerType(layer.capitalize()) in output_geom_types): final_layer_name = layer_name # If configOutputs is not None (from My Queries) if config_outputs: if config_outputs[layer]['namelayer']: final_layer_name = config_outputs[layer]['namelayer'] if output_dir: dialog.set_progress_text( tr('From memory layer to GeoJSON: ' + layer)) # Transforming the vector file osm_geometries = { 'points': QgsWkbTypes.Point, 'lines': QgsWkbTypes.LineString, 'multilinestrings': QgsWkbTypes.MultiLineString, 'multipolygons': QgsWkbTypes.MultiPolygon} memory_layer = item['vector_layer'] encoding = get_default_encoding() writer = QgsVectorFileWriter( outputs[layer], encoding, memory_layer.fields(), osm_geometries[layer], memory_layer.crs(), "GeoJSON") for f in memory_layer.getFeatures(): writer.addFeature(f) del writer # Loading the final vector file new_layer = QgsVectorLayer( outputs[layer], final_layer_name, "ogr") else: new_layer = item['vector_layer'] new_layer.setName(final_layer_name) # Try to set styling if defined if config_outputs and config_outputs[layer]['style']: new_layer.loadNamedStyle(config_outputs[layer]['style']) else: # Loading default styles if layer == "multilinestrings" or layer == "lines": if "colour" in item['tags']: new_layer.loadNamedStyle( join(dirname(dirname(abspath(__file__))), "styles", layer + "_colour.qml")) # Add action about OpenStreetMap add_actions(new_layer, item['tags']) if final_query: QgsExpressionContextUtils.setLayerVariable( new_layer, 'quickosm_query', final_query) QgsProject.instance().addMapLayer(new_layer) num_layers += 1 return num_layers
def get_layer_description_from_browser(self, category): """Obtain the description of the browser layer selected by user. :param category: The category of the layer to get the description. :type category: string :returns: Tuple of boolean and string. Boolean is true if layer is validated as compatible for current role (impact function and category) and false otherwise. String contains a description of the selected layer or an error message. :rtype: tuple """ if category == 'hazard': browser = self.tvBrowserHazard elif category == 'exposure': browser = self.tvBrowserExposure elif category == 'aggregation': browser = self.tvBrowserAggregation else: raise InaSAFEError index = browser.selectionModel().currentIndex() if not index: return False, '' # Map the proxy model index to the source model index index = browser.model().mapToSource(index) item = browser.model().sourceModel().dataItem(index) if not item: return False, '' item_class_name = item.metaObject().className() # if not itemClassName.endswith('LayerItem'): if not item.type() == QgsDataItem.Layer: if item_class_name == 'QgsPGRootItem' and not item.children(): return False, create_postGIS_connection_first else: return False, '' if item_class_name not in [ 'QgsOgrLayerItem', 'QgsGdalLayerItem', 'QgsPGLayerItem', 'QgsLayerItem', ]: return False, '' path = item.path() if item_class_name in [ 'QgsOgrLayerItem', 'QgsGdalLayerItem', 'QgsLayerItem' ] and not os.path.exists(path): return False, '' # try to create the layer if item_class_name == 'QgsOgrLayerItem': layer = QgsVectorLayer(path, '', 'ogr') elif item_class_name == 'QgsPGLayerItem': uri = self.postgis_path_to_uri(path) if uri: layer = QgsVectorLayer(uri.uri(), uri.table(), 'postgres') else: layer = None else: layer = QgsRasterLayer(path, '', 'gdal') if not layer or not layer.isValid(): return False, self.tr('Not a valid layer.') try: keywords = self.keyword_io.read_keywords(layer) if 'layer_purpose' not in keywords: keywords = None except (HashNotFoundError, OperationalError, NoKeywordsFoundError, KeywordNotFoundError, InvalidParameterError, UnsupportedProviderError, MissingMetadata): keywords = None # set the layer name for further use in the step_fc_summary if keywords: if qgis_version() >= 21800: layer.setName(keywords.get('title')) else: layer.setLayerName(keywords.get('title')) if not self.parent.is_layer_compatible(layer, category, keywords): label_text = '%s<br/>%s' % ( self.tr('This layer\'s keywords or type are not suitable:'), self.unsuitable_layer_description_html(layer, category, keywords)) return False, label_text # set the current layer (e.g. for the keyword creation sub-thread # or for adding the layer to mapCanvas) self.parent.layer = layer if category == 'hazard': self.parent.hazard_layer = layer elif category == 'exposure': self.parent.exposure_layer = layer else: self.parent.aggregation_layer = layer # Check if the layer is keywordless if keywords and 'keyword_version' in keywords: kw_ver = str(keywords['keyword_version']) self.parent.is_selected_layer_keywordless = ( not is_keyword_version_supported(kw_ver)) else: self.parent.is_selected_layer_keywordless = True desc = layer_description_html(layer, keywords) return True, desc
def add_design_to_map(qris_project, item, node): """adds designs to the map""" # Establish paths to layers design_id = item.data(item_code['feature_id']) subset_string = ("design_id = " + str(design_id)) design_name = item.text() geopackage_path = qris_project.project_designs.geopackage_path( qris_project.project_path) designs_layer = QgsVectorLayer(geopackage_path + "|layername=designs", "Designs", "ogr") structure_types_layer = QgsVectorLayer( geopackage_path + "|layername=structure_types", "Structure Types", "ogr") phases_layer = QgsVectorLayer(geopackage_path + "|layername=phases", "Implementation Phases", "ogr") zoi_layer = QgsVectorLayer(geopackage_path + "|layername=zoi", "ZOI", "ogr") zoi_types_layer = QgsVectorLayer(geopackage_path + "|layername=zoi_types", "ZOI", "ogr") complexes_layer = QgsVectorLayer(geopackage_path + "|layername=complexes", "Complexes", "ogr") structure_points_layer = QgsVectorLayer( geopackage_path + "|layername=structure_points", "Structures", "ogr") structure_lines_layer = QgsVectorLayer( geopackage_path + "|layername=structure_lines", "Structures", "ogr") # Get the structure geometry type # Could also do this with SQL design_iterator = designs_layer.getFeatures( QgsFeatureRequest().setFilterFid(design_id)) design_feature = next(design_iterator) structure_geometry = design_feature['structure_geometry'] def add_design_table(display_name, table_name, qml_name, read_only, group_node): """A handy way to add design layers and tables to the map""" if not any([c.name() == display_name for c in group_node.children()]): layer = QgsProject.instance().addMapLayer( QgsVectorLayer(geopackage_path + "|layername=" + table_name, display_name, "ogr"), False) if qml_name: layer_qml = os.path.join(symbology_path, 'symbology', qml_name) layer.loadNamedStyle(layer_qml) if read_only: layer.setReadOnly() group_node.addLayer(layer) # Summary tables (views) if any([c.name() == "Low-Tech Tables" for c in node.children()]): # if is there set it to the design node table_node = next(n for n in node.children() if n.name() == "Low-Tech Tables") else: # if not add the node as a group table_node = node.addGroup("Low-Tech Tables") table_node.setExpanded(False) # Summary tables (views) if any([c.name() == "Summary Tables" for c in table_node.children()]): # if is there set it to the design node summary_node = next(n for n in table_node.children() if n.name() == "Summary Tables") else: # if not add the node as a group summary_node = table_node.addGroup("Summary Tables") summary_node.setExpanded(False) add_design_table('Structure Totals - Points', 'qry_total_structures_points', None, True, summary_node) add_design_table('Structure Totals - Lines', 'qry_total_structures_lines', None, True, summary_node) add_design_table('Structure Summary - Points', 'qry_structure_summary_points', None, True, summary_node) add_design_table('Structure Summary - Lines', 'qry_structure_summary_lines', None, True, summary_node) add_design_table('Complexes Summary - Points', 'qry_complexes_by_type_points', None, True, summary_node) add_design_table('Complexes Summary - Lines', 'qry_complexes_by_type_lines', None, True, summary_node) add_design_table('ZOI Summary', 'qry_zoi_summary', None, True, summary_node) # Lookup Tables if any([c.name() == "Lookup Tables" for c in table_node.children()]): # if is there set it to the design node lookup_node = next(n for n in table_node.children() if n.name() == "Lookup Tables") else: # if not add the node as a group lookup_node = table_node.addGroup("Lookup Tables") lookup_node.setExpanded(False) add_design_table('Design Status', 'lkp_design_status', 'lkp_design_status.qml', True, lookup_node) add_design_table('Phase Action', 'lkp_phase_action', 'lkp_phase_action.qml', True, lookup_node) add_design_table('ZOI Influence', 'lkp_zoi_influence', 'lkp_zoi_influence.qml', True, lookup_node) add_design_table('ZOI Stage', 'lkp_zoi_stage', 'lkp_zoi_stage.qml', True, lookup_node) add_design_table('Structure Mimics', 'lkp_structure_mimics', 'lkp_structure_mimics.qml', True, lookup_node) # Add Design Tables if any([c.name() == "Design Tables" for c in table_node.children()]): # if is there set it to the design node design_tables_node = next(n for n in table_node.children() if n.name() == "Design Tables") else: # if not add the node as a group design_tables_node = table_node.addGroup("Design Tables") design_tables_node.setExpanded(False) # Check if the designs table has been added and if not add it. add_design_table('Designs', 'designs', 'designs.qml', False, design_tables_node) add_design_table('Structure Types', 'structure_types', 'structure_types.qml', False, design_tables_node) add_design_table('ZOI Types', 'zoi_types', 'zoi_types.qml', False, design_tables_node) add_design_table('Phases', 'phases', 'phases.qml', False, design_tables_node) # Check if the design node is already added design_group_name = str(design_id) + "-" + item.text() if any([c.name() == design_group_name for c in node.children()]): # if is there set it to the design node design_node = next(n for n in node.children() if n.name() == design_group_name) else: # if not add the node as a group design_node = node.addGroup(design_group_name) # Add structures structure_layer_name = str(design_id) + "-Structures" if structure_geometry == 'Point': # Start setting custom symbology # TODO Refactor into a functio unique_values = [] for feature in structure_types_layer.getFeatures(): values = (feature["fid"], feature["name"]) unique_values.append(values) categories = [] for value in unique_values: layer_style = {} layer_style["color"] = '%d, %d, %d' % (randrange( 0, 256), randrange(0, 256), randrange(0, 256)) layer_style['size'] = '3' layer_style['outline_color'] = 'black' symbol_layer = QgsMarkerSymbol.createSimple(layer_style) category = QgsRendererCategory(str(value[0]), symbol_layer, value[1]) categories.append(category) renderer = QgsCategorizedSymbolRenderer('structure_type_id', categories) if not any( [c.name() == structure_layer_name for c in design_node.children()]): # Adding the type suffix as I could see adding qml that symbolizes on other attributes structure_points_qml = os.path.join(symbology_path, 'symbology', 'structure_points.qml') structure_points_layer.loadNamedStyle(structure_points_qml) QgsExpressionContextUtils.setLayerVariable(structure_points_layer, 'parent_id', design_id) structure_points_layer.setSubsetString(subset_string) QgsProject.instance().addMapLayer(structure_points_layer, False) structure_points_layer.setName(structure_layer_name) design_node.addLayer(structure_points_layer) layer_node = design_node.findLayer(structure_points_layer.id()) layer_node.setExpanded(False) else: structure_points_layer = QgsProject.instance().mapLayersByName( structure_layer_name)[0] if renderer is not None: structure_points_layer.setRenderer(renderer) structure_points_layer.triggerRepaint() else: # Add line structures # Start setting custom symbology # TODO Refactor into a function unique_values = [] for feature in structure_types_layer.getFeatures(): values = (feature["fid"], feature["name"]) unique_values.append(values) categories = [] for value in unique_values: layer_style = {} layer_style["color"] = '%d, %d, %d' % (randrange( 0, 256), randrange(0, 256), randrange(0, 256)) layer_style['width'] = '1' layer_style['capstyle'] = 'round' symbol_layer = QgsLineSymbol.createSimple(layer_style) category = QgsRendererCategory(str(value[0]), symbol_layer, value[1]) categories.append(category) renderer = QgsCategorizedSymbolRenderer('structure_type_id', categories) # end custom symbology if not any( [c.name() == structure_layer_name for c in design_node.children()]): structures_lines_qml = os.path.join(symbology_path, 'symbology', 'structure_lines.qml') structure_lines_layer.loadNamedStyle(structures_lines_qml) QgsExpressionContextUtils.setLayerVariable(structure_lines_layer, 'parent_id', design_id) structure_lines_layer.setSubsetString(subset_string) QgsProject.instance().addMapLayer(structure_lines_layer, False) structure_lines_layer.setName(structure_layer_name) design_node.addLayer(structure_lines_layer) layer_node = design_node.findLayer(structure_lines_layer.id()) layer_node.setExpanded(False) else: structure_lines_layer = QgsProject.instance().mapLayersByName( structure_layer_name)[0] if renderer is not None: structure_lines_layer.setRenderer(renderer) structure_lines_layer.triggerRepaint() # Add zoi zoi_layer_name = str(design_id) + "-ZOI" # TODO Refactor into a function # TODO Refactor into sql query unique_values = [] for feature in zoi_types_layer.getFeatures(): values = (feature["fid"], feature["name"]) unique_values.append(values) categories = [] for value in unique_values: layer_style = {} alpha = 60 layer_style["color"] = "{}, {}, {}, {}".format(randrange(0, 256), randrange(0, 256), randrange(0, 256), alpha) layer_style["outline_width"] = '0.50' layer_style["outline_style"] = 'dash' symbol_layer = QgsFillSymbol.createSimple(layer_style) category = QgsRendererCategory(str(value[0]), symbol_layer, value[1]) categories.append(category) renderer = QgsCategorizedSymbolRenderer('influence_type_id', categories) # End custom symbology # check for the zoi layer, and if it is not there symbolize and add it if not any([c.name() == zoi_layer_name for c in design_node.children()]): zoi_qml = os.path.join(symbology_path, 'symbology', 'zoi.qml') zoi_layer.loadNamedStyle(zoi_qml) QgsExpressionContextUtils.setLayerVariable(zoi_layer, 'parent_id', design_id) zoi_layer.setSubsetString(subset_string) QgsProject.instance().addMapLayer(zoi_layer, False) zoi_layer.setName(zoi_layer_name) design_node.addLayer(zoi_layer) layer_node = design_node.findLayer(zoi_layer.id()) layer_node.setExpanded(False) else: zoi_layer = QgsProject.instance().mapLayersByName(zoi_layer_name)[0] if renderer is not None: zoi_layer.setRenderer(renderer) zoi_layer.triggerRepaint() # Add complexes complex_layer_name = str(design_id) + "-Complexes" if not any( [c.name() == complex_layer_name for c in design_node.children()]): complex_qml = os.path.join(symbology_path, 'symbology', 'complexes.qml') complexes_layer.loadNamedStyle(complex_qml) QgsExpressionContextUtils.setLayerVariable(complexes_layer, 'parent_id', design_id) complexes_layer.setSubsetString(subset_string) QgsProject.instance().addMapLayer(complexes_layer, False) complexes_layer.setName(complex_layer_name) design_node.addLayer(complexes_layer)