def _time_query_string(self, epoch, col, symbol="="): if self.timeLayer.getDateType() == time_util.DateTypes.IntegerTimestamps: return "{} {} {}".format(QgsExpression.quotedColumnRef(col), symbol, epoch) else: timeStr = time_util.epoch_to_str(epoch, self.timeLayer.getTimeFormat()) return "{} {} {}".format(QgsExpression.quotedColumnRef(col), symbol, QgsExpression.quotedString(timeStr))
def newField(self, field=None): if field is None: return { 'input': '', 'aggregate': '', 'delimiter': '', 'name': '', 'type': QVariant.Invalid, 'length': 0, 'precision': 0, } default_aggregate = '' if field.type() in (QVariant.Int, QVariant.Double, QVariant.LongLong): default_aggregate = 'sum' if field.type() == QVariant.DateTime: default_aggregate = '' if field.type() == QVariant.String: default_aggregate = 'concatenate' return { 'input': QgsExpression.quotedColumnRef(field.name()), 'aggregate': default_aggregate, 'delimiter': ',', 'name': field.name(), 'type': field.type(), 'length': field.length(), 'precision': field.precision(), }
def _id_query_string(self, id): if self.timeLayer.hasIdAttribute(): idColumn = self.timeLayer.getIdAttribute() return " AND {}={}".format(QgsExpression.quotedColumnRef(idColumn), self._value_for_query(id, idColumn)) else: return ""
def setModelData(self, editor, model, index): if not editor: return (value, isExpression, isValid) = editor.currentField() if isExpression is True: model.setData(index, value) else: model.setData(index, QgsExpression.quotedColumnRef(value))
def processAlgorithm(self, parameters, context, feedback): layer = self.parameterAsVectorLayer(parameters, self.INPUT, context) fieldName = self.parameterAsString(parameters, self.FIELD, context) operator = self.OPERATORS[self.parameterAsEnum(parameters, self.OPERATOR, context)] value = self.parameterAsString(parameters, self.VALUE, context) fields = layer.fields() idx = layer.fields().lookupField(fieldName) if idx < 0: raise QgsProcessingException(self.tr("Field '{}' was not found in layer").format(fieldName)) fieldType = fields[idx].type() if fieldType != QVariant.String and operator in self.STRING_OPERATORS: op = ''.join(['"%s", ' % o for o in self.STRING_OPERATORS]) raise QgsProcessingException( self.tr('Operators {0} can be used only with string fields.').format(op)) field_ref = QgsExpression.quotedColumnRef(fieldName) quoted_val = QgsExpression.quotedValue(value) if operator == 'is null': expression_string = '{} IS NULL'.format(field_ref) elif operator == 'is not null': expression_string = '{} IS NOT NULL'.format(field_ref) elif operator == 'begins with': expression_string = "{} LIKE '{}%'".format(field_ref, value) elif operator == 'contains': expression_string = "{} LIKE '%{}%'".format(field_ref, value) elif operator == 'does not contain': expression_string = "{} NOT LIKE '%{}%'".format(field_ref, value) else: expression_string = '{} {} {}'.format(field_ref, operator, quoted_val) method = self.parameterAsEnum(parameters, self.METHOD, context) if method == 0: behavior = QgsVectorLayer.SetSelection elif method == 1: behavior = QgsVectorLayer.AddToSelection elif method == 2: behavior = QgsVectorLayer.RemoveFromSelection elif method == 3: behavior = QgsVectorLayer.IntersectSelection expression = QgsExpression(expression_string) if expression.hasParserError(): raise QgsProcessingException(expression.parserErrorString()) layer.selectByExpression(expression_string, behavior) return {self.OUTPUT: parameters[self.INPUT]}
def newField(self, field=None): if field is None: return {'name': '', 'type': QVariant.Invalid, 'length': 0, 'precision': 0, 'expression': ''} return {'name': field.name(), 'type': field.type(), 'length': field.length(), 'precision': field.precision(), 'expression': QgsExpression.quotedColumnRef(field.name())}
def newField(self, field=None): if field is None: return { 'name': '', 'type': QVariant.Invalid, 'length': 0, 'precision': 0, 'expression': '' } return { 'name': field.name(), 'type': field.type(), 'length': field.length(), 'precision': field.precision(), 'expression': QgsExpression.quotedColumnRef(field.name()) }
def processAlgorithm(self, feedback): layer = dataobjects.getObjectFromUri(self.getParameterValue( self.INPUT)) fieldName = self.getParameterValue(self.FIELD) operator = self.OPERATORS[self.getParameterValue(self.OPERATOR)] value = self.getParameterValue(self.VALUE) fields = layer.fields() writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, layer.wkbType(), layer.crs()) idx = layer.fields().lookupField(fieldName) fieldType = fields[idx].type() if fieldType != QVariant.String and operator in self.STRING_OPERATORS: op = ''.join(['"%s", ' % o for o in self.STRING_OPERATORS]) raise GeoAlgorithmExecutionException( self.tr('Operators {0} can be used only with string fields.'). format(op)) field_ref = QgsExpression.quotedColumnRef(fieldName) quoted_val = QgsExpression.quotedValue(value) if operator == 'is null': expr = '{} IS NULL'.format(field_ref) elif operator == 'is not null': expr = '{} IS NOT NULL'.format(field_ref) elif operator == 'begins with': expr = """%s LIKE '%s%%'""" % (field_ref, value) elif operator == 'contains': expr = """%s LIKE '%%%s%%'""" % (field_ref, value) elif operator == 'does not contain': expr = """%s NOT LIKE '%%%s%%'""" % (field_ref, value) else: expr = '{} {} {}'.format(field_ref, operator, quoted_val) expression = QgsExpression(expr) if not expression.hasParserError(): req = QgsFeatureRequest(expression) else: raise GeoAlgorithmExecutionException( expression.parserErrorString()) for f in layer.getFeatures(req): writer.addFeature(f) del writer
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) fieldName = self.parameterAsString(parameters, self.FIELD, context) directory = self.parameterAsString(parameters, self.OUTPUT, context) mkdir(directory) fieldIndex = source.fields().lookupField(fieldName) uniqueValues = source.uniqueValues(fieldIndex) baseName = os.path.join(directory, '{0}'.format(fieldName)) fields = source.fields() crs = source.sourceCrs() geomType = source.wkbType() total = 100.0 / len(uniqueValues) if uniqueValues else 1 output_layers = [] for current, i in enumerate(uniqueValues): if feedback.isCanceled(): break fName = u'{0}_{1}.shp'.format(baseName, str(i).strip()) feedback.pushInfo(self.tr('Creating layer: {}').format(fName)) sink, dest = QgsProcessingUtils.createFeatureSink(fName, context, fields, geomType, crs) filter = '{} = {}'.format(QgsExpression.quotedColumnRef(fieldName), QgsExpression.quotedValue(i)) req = QgsFeatureRequest().setFilterExpression(filter) count = 0 for f in source.getFeatures(req): if feedback.isCanceled(): break sink.addFeature(f, QgsFeatureSink.FastInsert) count += 1 feedback.pushInfo(self.tr('Added {} features to layer').format(count)) output_layers.append(fName) del sink feedback.setProgress(int(current * total)) return {self.OUTPUT: directory, self.OUTPUT_LAYERS: output_layers}
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) fieldName = self.parameterAsString(parameters, self.FIELD, context) directory = self.parameterAsString(parameters, self.OUTPUT, context) mkdir(directory) fieldIndex = source.fields().lookupField(fieldName) uniqueValues = source.uniqueValues(fieldIndex) baseName = os.path.join(directory, '{0}'.format(fieldName)) fields = source.fields() crs = source.sourceCrs() geomType = source.wkbType() total = 100.0 / len(uniqueValues) if uniqueValues else 1 output_layers = [] for current, i in enumerate(uniqueValues): if feedback.isCanceled(): break fName = '{0}_{1}.gpkg'.format(baseName, str(i).strip()) feedback.pushInfo(self.tr('Creating layer: {}').format(fName)) sink, dest = QgsProcessingUtils.createFeatureSink(fName, context, fields, geomType, crs) filter = '{} = {}'.format(QgsExpression.quotedColumnRef(fieldName), QgsExpression.quotedValue(i)) req = QgsFeatureRequest().setFilterExpression(filter) count = 0 for f in source.getFeatures(req): if feedback.isCanceled(): break sink.addFeature(f, QgsFeatureSink.FastInsert) count += 1 feedback.pushInfo(self.tr('Added {} features to layer').format(count)) output_layers.append(fName) del sink feedback.setProgress(int(current * total)) return {self.OUTPUT: directory, self.OUTPUT_LAYERS: output_layers}
def processAlgorithm(self, feedback): layer = dataobjects.getLayerFromString(self.getParameterValue(self.INPUT)) fieldName = self.getParameterValue(self.FIELD) operator = self.OPERATORS[self.getParameterValue(self.OPERATOR)] value = self.getParameterValue(self.VALUE) fields = layer.fields() writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, layer.wkbType(), layer.crs()) idx = layer.fields().lookupField(fieldName) fieldType = fields[idx].type() if fieldType != QVariant.String and operator in self.STRING_OPERATORS: op = ''.join(['"%s", ' % o for o in self.STRING_OPERATORS]) raise GeoAlgorithmExecutionException( self.tr('Operators {0} can be used only with string fields.').format(op)) field_ref = QgsExpression.quotedColumnRef(fieldName) quoted_val = QgsExpression.quotedValue(value) if operator == 'is null': expr = '{} IS NULL'.format(field_ref) elif operator == 'is not null': expr = '{} IS NOT NULL'.format(field_ref) elif operator == 'begins with': expr = """%s LIKE '%s%%'""" % (field_ref, value) elif operator == 'contains': expr = """%s LIKE '%%%s%%'""" % (field_ref, value) elif operator == 'does not contain': expr = """%s NOT LIKE '%%%s%%'""" % (field_ref, value) else: expr = '{} {} {}'.format(field_ref, operator, quoted_val) expression = QgsExpression(expr) if not expression.hasParserError(): req = QgsFeatureRequest(expression) else: raise GeoAlgorithmExecutionException(expression.parserErrorString()) for f in layer.getFeatures(req): writer.addFeature(f) del writer
def processAlgorithm(self, parameters, context, feedback): layer = self.parameterAsVectorLayer(parameters, self.INPUT, context) fieldName = self.parameterAsString(parameters, self.FIELD, context) operator = self.OPERATORS[self.parameterAsEnum(parameters, self.OPERATOR, context)] value = self.parameterAsString(parameters, self.VALUE, context) fields = layer.fields() idx = layer.fields().lookupField(fieldName) fieldType = fields[idx].type() if fieldType != QVariant.String and operator in self.STRING_OPERATORS: op = ''.join(['"%s", ' % o for o in self.STRING_OPERATORS]) raise GeoAlgorithmExecutionException( self.tr('Operators {0} can be used only with string fields.'). format(op)) field_ref = QgsExpression.quotedColumnRef(fieldName) quoted_val = QgsExpression.quotedValue(value) if operator == 'is null': expression_string = '{} IS NULL'.format(field_ref) elif operator == 'is not null': expression_string = '{} IS NOT NULL'.format(field_ref) elif operator == 'begins with': expression_string = """%s LIKE '%s%%'""" % (field_ref, value) elif operator == 'contains': expression_string = """%s LIKE '%%%s%%'""" % (field_ref, value) elif operator == 'does not contain': expression_string = """%s NOT LIKE '%%%s%%'""" % (field_ref, value) else: expression_string = '{} {} {}'.format(field_ref, operator, quoted_val) expression = QgsExpression(expression_string) if expression.hasParserError(): raise GeoAlgorithmExecutionException( expression.parserErrorString()) layer.selectByExpression(expression_string) return {self.OUTPUT: parameters[self.INPUT]}
def setModelData(self, editor, model, index): if not editor: return column = index.column() fieldType = FieldsMappingModel.columns[column]['type'] if fieldType == QVariant.Type: value = editor.itemData(editor.currentIndex()) if value is None: value = QVariant.Invalid model.setData(index, value) elif fieldType == QgsExpression: (value, isExpression, isValid) = editor.currentField() if isExpression is True: model.setData(index, value) else: model.setData(index, QgsExpression.quotedColumnRef(value)) else: QStyledItemDelegate.setModelData(self, editor, model, index)
def setModelData(self, editor, model, index): if not editor: return column = index.column() fieldType = FieldsMappingModel.columns[column]['type'] if fieldType == QVariant.Type: value = editor.currentData() if value is None: value = QVariant.Invalid model.setData(index, value) elif fieldType == QgsExpression: (value, isExpression, isValid) = editor.currentField() if isExpression is True: model.setData(index, value) else: model.setData(index, QgsExpression.quotedColumnRef(value)) else: QStyledItemDelegate.setModelData(self, editor, model, index)
def processAlgorithm(self, feedback): fileName = self.getParameterValue(self.INPUT) layer = dataobjects.getLayerFromString(fileName) fieldName = self.getParameterValue(self.FIELD) operator = self.OPERATORS[self.getParameterValue(self.OPERATOR)] value = self.getParameterValue(self.VALUE) fields = layer.fields() idx = layer.fields().lookupField(fieldName) fieldType = fields[idx].type() if fieldType != QVariant.String and operator in self.STRING_OPERATORS: op = ''.join(['"%s", ' % o for o in self.STRING_OPERATORS]) raise GeoAlgorithmExecutionException( self.tr('Operators {0} can be used only with string fields.').format(op)) field_ref = QgsExpression.quotedColumnRef(fieldName) quoted_val = QgsExpression.quotedValue(value) if operator == 'is null': expression_string = '{} IS NULL'.format(field_ref) elif operator == 'is not null': expression_string = '{} IS NOT NULL'.format(field_ref) elif operator == 'begins with': expression_string = """%s LIKE '%s%%'""" % (field_ref, value) elif operator == 'contains': expression_string = """%s LIKE '%%%s%%'""" % (field_ref, value) elif operator == 'does not contain': expression_string = """%s NOT LIKE '%%%s%%'""" % (field_ref, value) else: expression_string = '{} {} {}'.format(field_ref, operator, quoted_val) expression = QgsExpression(expression_string) if expression.hasParserError(): raise GeoAlgorithmExecutionException(expression.parserErrorString()) layer.selectByExpression(expression_string) self.setOutputValue(self.OUTPUT, fileName)
def processAlgorithm(self, parameters, context, feedback): layer = self.parameterAsVectorLayer(parameters, self.INPUT, context) fieldName = self.parameterAsString(parameters, self.FIELD, context) operator = self.OPERATORS[self.parameterAsEnum(parameters, self.OPERATOR, context)] value = self.parameterAsString(parameters, self.VALUE, context) fields = layer.fields() idx = layer.fields().lookupField(fieldName) fieldType = fields[idx].type() if fieldType != QVariant.String and operator in self.STRING_OPERATORS: op = ''.join(['"%s", ' % o for o in self.STRING_OPERATORS]) raise QgsProcessingException( self.tr('Operators {0} can be used only with string fields.').format(op)) field_ref = QgsExpression.quotedColumnRef(fieldName) quoted_val = QgsExpression.quotedValue(value) if operator == 'is null': expression_string = '{} IS NULL'.format(field_ref) elif operator == 'is not null': expression_string = '{} IS NOT NULL'.format(field_ref) elif operator == 'begins with': expression_string = """%s LIKE '%s%%'""" % (field_ref, value) elif operator == 'contains': expression_string = """%s LIKE '%%%s%%'""" % (field_ref, value) elif operator == 'does not contain': expression_string = """%s NOT LIKE '%%%s%%'""" % (field_ref, value) else: expression_string = '{} {} {}'.format(field_ref, operator, quoted_val) expression = QgsExpression(expression_string) if expression.hasParserError(): raise QgsProcessingException(expression.parserErrorString()) layer.selectByExpression(expression_string) return {self.OUTPUT: parameters[self.INPUT]}
def get_lizmap_layer_filter(self, layer: 'QgsVectorLayer') -> str: """ Get lizmap layer filter based on login filter """ layer_filter = '' # Get Lizmap config cfg = self.get_lizmap_config() if not cfg: # Return empty filter return layer_filter # Get layers config cfg_layers = get_lizmap_layers_config(cfg) if not cfg_layers: # Return empty filter return layer_filter # Get layer name layer_name = layer.name() # Check that if layer_name not in cfg_layers: # Return empty filter return layer_filter # Get layer login filter cfg_layer_login_filter = get_lizmap_layer_login_filter(cfg, layer_name) if not cfg_layer_login_filter: # Return empty filter return layer_filter # Layer login fliter only for edition does not filter layer is_edition_only = 'edition_only' in cfg_layer_login_filter if is_edition_only and config_value_to_boolean( cfg_layer_login_filter['edition_only']): return layer_filter # Get Lizmap user groups provided by the request groups = self.get_lizmap_groups() user_login = self.get_lizmap_user_login() # If groups is empty, no Lizmap user groups provided by the request # Return empty filter if len(groups) == 0 and not user_login: return layer_filter # Override filter override_filter = self.get_lizmap_override_filter() if override_filter: return layer_filter attribute = cfg_layer_login_filter['filterAttribute'] # Default filter for no user connected # we use expression tools also for subset string layer_filter = QgsExpression.createFieldEqualityExpression( attribute, 'all') # If groups is not empty but the only group like user login has no name # Return the filter for no user connected if len(groups) == 1 and groups[0] == '' and user_login == '': return layer_filter # List of quoted values for expression quoted_values = [] if config_value_to_boolean(cfg_layer_login_filter['filterPrivate']): # If filter is private use user_login quoted_values.append(QgsExpression.quotedString(user_login)) else: # Else use user groups quoted_values = [QgsExpression.quotedString(g) for g in groups] # Add all to quoted values quoted_values.append(QgsExpression.quotedString('all')) # Build filter layer_filter = '{} IN ({})'.format( QgsExpression.quotedColumnRef(attribute), ', '.join(quoted_values)) # Return build filter return layer_filter
def layer_to_QgsVectorLayer( source_layer, # pylint: disable=too-many-locals,too-many-branches,too-many-statements input_file, context: Context, fallback_crs=QgsCoordinateReferenceSystem(), defer_layer_uri_set: bool = False): """ Converts a vector layer """ if source_layer.__class__.__name__ == 'CadFeatureLayer': layer = source_layer.layer else: layer = source_layer crs = CrsConverter.convert_crs( layer.layer_extent.crs, context) if layer.layer_extent else QgsCoordinateReferenceSystem() if not crs.isValid(): crs = fallback_crs subset_string = '' if layer.selection_set: subset_string = 'fid in ({})'.format(','.join( [str(s) for s in layer.selection_set])) elif layer.definition_query: subset_string = ExpressionConverter.convert_esri_sql( layer.definition_query) base, _ = os.path.split(input_file) uri, wkb_type, provider, encoding, file_name = VectorLayerConverter.get_uri( source_layer=source_layer, obj=layer, base=base, crs=crs, subset=subset_string, context=context) if wkb_type is None or wkb_type == QgsWkbTypes.Unknown: wkb_type = VectorLayerConverter.layer_to_wkb_type(layer) context.layer_type_hint = wkb_type if Qgis.QGIS_VERSION_INT >= 31600: # try to get the layer name so that we can remove it from field references. # e.g. if layer name is polys then qgis won't support to arcgis style "polys.field" format parts = QgsProviderRegistry.instance().decodeUri(provider, uri) context.main_layer_name = parts.get('layerName') if not context.main_layer_name and provider == 'ogr': context.main_layer_name = Path(parts['path']).stem if context.main_layer_name: subset_string = subset_string.replace( context.main_layer_name + '.', '') else: context.main_layer_name = None if provider == 'ogr' and (not file_name or not os.path.exists(file_name) ) and context.invalid_layer_resolver: res = context.invalid_layer_resolver(layer.name, uri, wkb_type) uri = res.uri provider = res.providerKey if Qgis.QGIS_VERSION_INT >= 31000: opts = QgsVectorLayer.LayerOptions() if wkb_type is not None: opts.fallbackWkbType = wkb_type if provider == 'ogr' and subset_string: uri += '|subset={}'.format(subset_string) original_uri = uri if defer_layer_uri_set: uri = 'xxxxxxxxx' + uri vl = QgsVectorLayer(uri, layer.name, provider, opts) if defer_layer_uri_set: vl.setCustomProperty('original_uri', original_uri) else: vl = QgsMemoryProviderUtils.createMemoryLayer( layer.name, QgsFields(), wkb_type, crs) # context.style_folder, _ = os.path.split(output_file) if layer.renderer: renderer = VectorRendererConverter.convert_renderer( layer.renderer, context) try: if not renderer.usingSymbolLevels(): renderer.setUsingSymbolLevels( layer.use_advanced_symbol_levels) except AttributeError: pass if layer.use_page_definition_query: filter_expression = '"{}" {} @atlas_pagename'.format( layer.page_name_field, layer.page_name_match_operator) root_rule = QgsRuleBasedRenderer.Rule(None) # special case -- convert a simple renderer if isinstance(renderer, QgsSingleSymbolRenderer): filter_rule = QgsRuleBasedRenderer.Rule( renderer.symbol().clone()) filter_rule.setFilterExpression(filter_expression) filter_rule.setLabel(layer.name) filter_rule.setDescription(layer.name) root_rule.appendChild(filter_rule) else: source_rule_renderer = QgsRuleBasedRenderer.convertFromRenderer( renderer) filter_rule = QgsRuleBasedRenderer.Rule(None) filter_rule.setFilterExpression(filter_expression) filter_rule.setLabel('Current Atlas Page') filter_rule.setDescription('Current Atlas Page') root_rule.appendChild(filter_rule) for child in source_rule_renderer.rootRule().children(): filter_rule.appendChild(child.clone()) renderer = QgsRuleBasedRenderer(root_rule) if renderer: vl.setRenderer(renderer) vl.triggerRepaint() else: vl.setRenderer(QgsNullSymbolRenderer()) vl.triggerRepaint() metadata = vl.metadata() metadata.setAbstract(layer.description) vl.setMetadata(metadata) # # layer.zoom_max = "don't show when zoomed out beyond" zoom_max = layer.zoom_max # layer.zoom_min = "don't show when zoomed in beyond" zoom_min = layer.zoom_min enabled_scale_range = bool(zoom_max or zoom_min) if zoom_max and zoom_min and zoom_min > zoom_max: # inconsistent scale range -- zoom_max should be bigger number than zoom_min zoom_min, zoom_max = zoom_max, zoom_min # qgis minimum scale = don't show when zoomed out beyond, i.e. ArcGIS zoom_max vl.setMinimumScale( zoom_max if enabled_scale_range else layer.stored_zoom_max) # qgis maximum scale = don't show when zoomed in beyond, i.e. ArcGIS zoom_min vl.setMaximumScale( zoom_min if enabled_scale_range else layer.stored_zoom_min) vl.setScaleBasedVisibility(enabled_scale_range) vl.setOpacity(1.0 - (layer.transparency or 0) / 100) if layer.display_expression_properties and layer.display_expression_properties.expression and layer.display_expression_properties.expression_parser is not None: vl.setDisplayExpression( ExpressionConverter.convert( layer.display_expression_properties.expression, layer.display_expression_properties.expression_parser, layer.display_expression_properties.advanced, context)) if Qgis.QGIS_VERSION_INT < 31000: vl.setDataSource(uri, layer.name, provider) if encoding: vl.dataProvider().setEncoding(encoding) if subset_string: vl.setSubsetString(subset_string) vl.setCrs(crs) for e in layer.extensions: if e.__class__.__name__ == 'ServerLayerExtension': if 'CopyrightText' in e.properties.properties: layer_credits = e.properties.properties['CopyrightText'] metadata = vl.metadata() rights = metadata.rights() rights.append(layer_credits) metadata.setRights(rights) vl.setMetadata(metadata) LabelConverter.convert_annotation_collection( layer.annotation_collection, dest_layer=vl, context=context) vl.setLabelsEnabled(layer.labels_enabled) DiagramConverter.convert_diagrams(layer.renderer, dest_layer=vl, context=context) # setup joins join_layer = VectorLayerConverter.add_joined_layer( source_layer=layer, input_file=input_file, base_layer=vl, context=context) context.dataset_name = '' vl.setLegend(QgsMapLayerLegend.defaultVectorLegend(vl)) if layer.hyperlinks: VectorLayerConverter.convert_hyperlinks(layer.hyperlinks, vl) vl.setDisplayExpression( QgsExpression.quotedColumnRef(layer.display_field)) res = [vl] if join_layer: res.append(join_layer) context.main_layer_name = None return res
def style_maps(layer, style_by, iface, output_type='damages-rlzs', perils=None, add_null_class=False, render_higher_on_top=False, repaint=True, use_sgc_style=False): symbol = QgsSymbol.defaultSymbol(layer.geometryType()) # see properties at: # https://qgis.org/api/qgsmarkersymbollayerv2_8cpp_source.html#l01073 symbol.setOpacity(1) if isinstance(symbol, QgsMarkerSymbol): # do it only for the layer with points symbol.symbolLayer(0).setStrokeStyle(Qt.PenStyle(Qt.NoPen)) style = get_style(layer, iface.messageBar()) # this is the default, as specified in the user settings ramp = QgsGradientColorRamp(style['color_from'], style['color_to']) style_mode = style['style_mode'] # in most cases, we override the user-specified setting, and use # instead a setting that was required by scientists if output_type in OQ_TO_LAYER_TYPES: default_qgs_style = QgsStyle().defaultStyle() default_color_ramp_names = default_qgs_style.colorRampNames() if output_type in ( 'damages-rlzs', 'avg_losses-rlzs', 'avg_losses-stats', ): # options are EqualInterval, Quantile, Jenks, StdDev, Pretty # jenks = natural breaks if Qgis.QGIS_VERSION_INT < 31000: style_mode = QgsGraduatedSymbolRenderer.Jenks else: style_mode = 'Jenks' ramp_type_idx = default_color_ramp_names.index('Reds') symbol.setColor(QColor(RAMP_EXTREME_COLORS['Reds']['top'])) inverted = False elif (output_type in ('gmf_data', 'ruptures') or (output_type == 'hmaps' and not use_sgc_style)): # options are EqualInterval, Quantile, Jenks, StdDev, Pretty # jenks = natural breaks if output_type == 'ruptures': if Qgis.QGIS_VERSION_INT < 31000: style_mode = QgsGraduatedSymbolRenderer.Pretty else: style_mode = 'PrettyBreaks' else: if Qgis.QGIS_VERSION_INT < 31000: style_mode = QgsGraduatedSymbolRenderer.EqualInterval else: style_mode = 'EqualInterval' ramp_type_idx = default_color_ramp_names.index('Spectral') inverted = True symbol.setColor(QColor(RAMP_EXTREME_COLORS['Reds']['top'])) elif output_type == 'hmaps' and use_sgc_style: # FIXME: for SGC they were using size 10000 map units # options are EqualInterval, Quantile, Jenks, StdDev, Pretty # jenks = natural breaks if Qgis.QGIS_VERSION_INT < 31000: style_mode = QgsGraduatedSymbolRenderer.Pretty else: style_mode = 'PrettyBreaks' try: ramp_type_idx = default_color_ramp_names.index( 'SGC_Green2Red_Hmap_Color_Ramp') except ValueError: raise ValueError( 'Color ramp SGC_Green2Red_Hmap_Color_Ramp was ' 'not found. Please import it from ' 'Settings -> Style Manager, loading ' 'svir/resources/sgc_green2red_hmap_color_ramp.xml') inverted = False registry = QgsApplication.symbolLayerRegistry() symbol_props = { 'name': 'square', 'color': '0,0,0', 'color_border': '0,0,0', 'offset': '0,0', 'size': '1.5', # FIXME 'angle': '0', } square = registry.symbolLayerMetadata( "SimpleMarker").createSymbolLayer(symbol_props) symbol = QgsSymbol.defaultSymbol(layer.geometryType()).clone() symbol.deleteSymbolLayer(0) symbol.appendSymbolLayer(square) symbol.symbolLayer(0).setStrokeStyle(Qt.PenStyle(Qt.NoPen)) elif output_type in ['asset_risk', 'input']: # options are EqualInterval, Quantile, Jenks, StdDev, Pretty # jenks = natural breaks if Qgis.QGIS_VERSION_INT < 31000: style_mode = QgsGraduatedSymbolRenderer.EqualInterval else: style_mode = 'EqualInterval' # exposure_strings = ['number', 'occupants', 'value'] # setting exposure colors by default colors = { 'single': RAMP_EXTREME_COLORS['Blues']['top'], 'ramp_name': 'Blues' } inverted = False if output_type == 'asset_risk': damage_strings = perils for damage_string in damage_strings: if damage_string in style_by: colors = { 'single': RAMP_EXTREME_COLORS['Spectral']['top'], 'ramp_name': 'Spectral' } inverted = True break else: # 'input' colors = { 'single': RAMP_EXTREME_COLORS['Greens']['top'], 'ramp_name': 'Greens' } symbol.symbolLayer(0).setShape( QgsSimpleMarkerSymbolLayerBase.Square) single_color = colors['single'] ramp_name = colors['ramp_name'] ramp_type_idx = default_color_ramp_names.index(ramp_name) symbol.setColor(QColor(single_color)) else: raise NotImplementedError( 'Undefined color ramp for output type %s' % output_type) ramp = default_qgs_style.colorRamp( default_color_ramp_names[ramp_type_idx]) if inverted: ramp.invert() # get unique values fni = layer.fields().indexOf(style_by) unique_values = layer.dataProvider().uniqueValues(fni) num_unique_values = len(unique_values - {NULL}) if num_unique_values > 2: if Qgis.QGIS_VERSION_INT < 31000: renderer = QgsGraduatedSymbolRenderer.createRenderer( layer, style_by, min(num_unique_values, style['classes']), style_mode, symbol.clone(), ramp) else: renderer = QgsGraduatedSymbolRenderer(style_by, []) # NOTE: the following returns an instance of one of the # subclasses of QgsClassificationMethod classification_method = \ QgsApplication.classificationMethodRegistry().method( style_mode) renderer.setClassificationMethod(classification_method) renderer.updateColorRamp(ramp) renderer.updateSymbols(symbol.clone()) renderer.updateClasses( layer, min(num_unique_values, style['classes'])) if not use_sgc_style: if Qgis.QGIS_VERSION_INT < 31000: label_format = renderer.labelFormat() # NOTE: the following line might be useful # label_format.setTrimTrailingZeroes(True) label_format.setPrecision(2) renderer.setLabelFormat(label_format, updateRanges=True) else: renderer.classificationMethod().setLabelPrecision(2) renderer.calculateLabelPrecision() elif num_unique_values == 2: categories = [] for unique_value in unique_values: symbol = symbol.clone() try: symbol.setColor( QColor(RAMP_EXTREME_COLORS[ramp_name] ['bottom' if unique_value == min(unique_values) else 'top'])) except Exception: symbol.setColor( QColor(style['color_from'] if unique_value == min(unique_values) else style['color_to'])) category = QgsRendererCategory(unique_value, symbol, str(unique_value)) # entry for the list of category items categories.append(category) renderer = QgsCategorizedSymbolRenderer(style_by, categories) else: renderer = QgsSingleSymbolRenderer(symbol.clone()) if add_null_class and NULL in unique_values: # add a class for NULL values rule_renderer = QgsRuleBasedRenderer(symbol.clone()) root_rule = rule_renderer.rootRule() not_null_rule = root_rule.children()[0].clone() # strip parentheses from stringified color HSL not_null_rule.setFilterExpression( '%s IS NOT NULL' % QgsExpression.quotedColumnRef(style_by)) not_null_rule.setLabel('%s:' % style_by) root_rule.appendChild(not_null_rule) null_rule = root_rule.children()[0].clone() null_rule.setSymbol( QgsFillSymbol.createSimple({ 'color': '160,160,160', 'style': 'diagonal_x' })) null_rule.setFilterExpression( '%s IS NULL' % QgsExpression.quotedColumnRef(style_by)) null_rule.setLabel(tr('No points')) root_rule.appendChild(null_rule) if isinstance(renderer, QgsGraduatedSymbolRenderer): # create value ranges rule_renderer.refineRuleRanges(not_null_rule, renderer) # remove default rule elif isinstance(renderer, QgsCategorizedSymbolRenderer): rule_renderer.refineRuleCategoris(not_null_rule, renderer) for rule in rule_renderer.rootRule().children()[1].children(): label = rule.label() # by default, labels are like: # ('"collapse-structural-ASH_DRY_sum" >= 0.0000 AND # "collapse-structural-ASH_DRY_sum" <= 2.3949') first, second = label.split(" AND ") bottom = first.rsplit(" ", 1)[1] top = second.rsplit(" ", 1)[1] simplified = "%s - %s" % (bottom, top) rule.setLabel(simplified) root_rule.removeChildAt(0) renderer = rule_renderer if render_higher_on_top: renderer.setUsingSymbolLevels(True) symbol_items = [item for item in renderer.legendSymbolItems()] for i in range(len(symbol_items)): sym = symbol_items[i].symbol().clone() key = symbol_items[i].ruleKey() for lay in range(sym.symbolLayerCount()): sym.symbolLayer(lay).setRenderingPass(i) renderer.setLegendSymbolItem(key, sym) layer.setRenderer(renderer) if not use_sgc_style: layer.setOpacity(0.7) if repaint: layer.triggerRepaint() iface.setActiveLayer(layer) iface.zoomToActiveLayer() # NOTE QGIS3: probably not needed # iface.layerTreeView().refreshLayerSymbology(layer.id()) iface.mapCanvas().refresh()
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) close_path = self.parameterAsBool(parameters, self.CLOSE_PATH, context) group_field_name = self.parameterAsString(parameters, self.GROUP_FIELD, context) order_field_name = self.parameterAsString(parameters, self.ORDER_FIELD, context) order_expression = self.parameterAsString(parameters, self.ORDER_EXPRESSION, context) date_format = self.parameterAsString(parameters, self.DATE_FORMAT, context) text_dir = self.parameterAsString(parameters, self.OUTPUT_TEXT_DIR, context) group_field_index = source.fields().lookupField(group_field_name) if group_field_index >= 0: group_field_def = source.fields().at(group_field_index) else: group_field_def = None if order_field_name: order_expression = QgsExpression.quotedColumnRef(order_field_name) if not order_expression: raise QgsProcessingException( self.tr('ORDER_EXPRESSION parameter is missing.')) expression_context = self.createExpressionContext( parameters, context, source) expression = QgsExpression(order_expression) if expression.hasParserError(): raise QgsProcessingException(expression.parserErrorString()) expression.prepare(expression_context) order_field_type = QVariant.String if expression.isField(): field_name = next(iter(expression.referencedColumns())) order_field_type = source.fields().field(field_name).type() fields = QgsFields() if group_field_def is not None: fields.append(group_field_def) begin_field = QgsField('begin', order_field_type) fields.append(begin_field) end_field = QgsField('end', order_field_type) fields.append(end_field) output_wkb = QgsWkbTypes.LineString if QgsWkbTypes.hasM(source.wkbType()): output_wkb = QgsWkbTypes.addM(output_wkb) if QgsWkbTypes.hasZ(source.wkbType()): output_wkb = QgsWkbTypes.addZ(output_wkb) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, output_wkb, source.sourceCrs()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) if text_dir and not (os.path.exists(text_dir)): raise QgsProcessingException( self.tr("The text output directory does not exist")) points = dict() required_fields = expression.referencedColumns() required_fields.add(group_field_name) features = source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes(required_fields, source.fields()), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break if not f.hasGeometry(): continue point = f.geometry().constGet().clone() if group_field_index >= 0: group = f[group_field_index] else: group = 1 expression_context.setFeature(f) order = expression.evaluate(expression_context) if date_format != '': order = datetime.strptime(str(order), date_format) if group in points: points[group].append((order, point)) else: points[group] = [(order, point)] feedback.setProgress(int(current * total)) feedback.setProgress(0) da = QgsDistanceArea() da.setSourceCrs(source.sourceCrs(), context.transformContext()) da.setEllipsoid(context.ellipsoid()) current = 0 total = 100.0 / len(points) if points else 1 for group, vertices in points.items(): if feedback.isCanceled(): break vertices.sort(key=lambda x: (x[0] is None, x[0])) f = QgsFeature() attributes = [] if group_field_index >= 0: attributes.append(group) attributes.extend([vertices[0][0], vertices[-1][0]]) f.setAttributes(attributes) line = [node[1] for node in vertices] if close_path is True: if line[0] != line[-1]: line.append(line[0]) if text_dir: fileName = os.path.join(text_dir, '%s.txt' % group) with open(fileName, 'w') as fl: fl.write('angle=Azimuth\n') fl.write('heading=Coordinate_System\n') fl.write('dist_units=Default\n') for i in range(len(line)): if i == 0: fl.write('startAt=%f;%f;90\n' % (line[i].x(), line[i].y())) fl.write('survey=Polygonal\n') fl.write('[data]\n') else: angle = line[i - 1].azimuth(line[i]) distance = da.measureLine(QgsPointXY(line[i - 1]), QgsPointXY(line[i])) fl.write('%f;%f;90\n' % (angle, distance)) f.setGeometry(QgsGeometry(QgsLineString(line))) sink.addFeature(f, QgsFeatureSink.FastInsert) current += 1 feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}