def set_metadata_layer(self, request, **kwargs): self.layer = self.get_layer_by_params(kwargs) # set layer_name self.layer_name = self.layer.origname geomodel, self.database_to_use, geometrytype = create_geomodel_from_qdjango_layer( self.layer) if geometrytype is None: geometrytype = QGIS_LAYER_TYPE_NO_GEOM # set bbox_filter_field with geomentry model field if geometrytype != QGIS_LAYER_TYPE_NO_GEOM: serializer = QGISGeoLayerSerializer self.bbox_filter_field = get_geometry_column(geomodel).name else: serializer = QGISLayerSerializer # create model and add to editing_layers self.metadata_layer = MetadataVectorLayer(geomodel, serializer, geometrytype, self.layer.origname, layer_id=self.layer.pk)
def set_metadata_relations(self, request, **kwargs): # init relations self.set_relations() # Determine if we are using an old and bugged version of QGIS IS_QGIS_3_10 = Qgis.QGIS_VERSION.startswith('3.10') for idr, relation in list(self.relations.items()): # check if in relation there is referencedLayer == self layer if relation['referencedLayer'] == self.layer.qgs_layer_id: # get relation layer object relation_layer = self._layer_model.objects.get( qgs_layer_id=relation['referencingLayer'], project=self.layer.project) # qgis_layer is the referenced layer qgis_layer = self.layer.qgis_layer referenced_field_is_pk = [ qgis_layer.fields().indexFromName( relation['fieldRef']['referencedField']) ] == qgis_layer.primaryKeyAttributes() # It's an old and buggy QGIS version so we cannot trust primaryKeyAttributes() and we go guessing if IS_QGIS_3_10: field_index = qgis_layer.fields().indexFromName( relation['fieldRef']['referencedField']) # Safety check if field_index >= 0: field = qgis_layer.fields()[field_index] default_clause = qgis_layer.dataProvider( ).defaultValueClause(field_index) constraints = qgis_layer.fieldConstraints(field_index) not_null = bool(constraints & QgsFieldConstraints.ConstraintNotNull) and \ field.constraints().constraintStrength( QgsFieldConstraints.ConstraintNotNull) == QgsFieldConstraints.ConstraintStrengthHard unique = bool(constraints & QgsFieldConstraints.ConstraintUnique) and \ field.constraints().constraintStrength( QgsFieldConstraints.ConstraintUnique) == QgsFieldConstraints.ConstraintStrengthHard referenced_field_is_pk = unique and default_clause and not_null self.metadata_relations[ relation['referencingLayer']] = MetadataVectorLayer( get_qgis_layer(relation_layer), relation_layer.origname, idr, layer=relation_layer, referencing_field=relation['fieldRef'] ['referencingField'], layer_id=relation_layer.pk, referenced_field_is_pk=referenced_field_is_pk)
def set_metadata_layer(self, request, **kwargs): """Set the metadata layer to a QgsVectorLayer instance returns a dictionary with layer information and the QGIS layer instance """ self.layer = self.get_layer_by_params(kwargs) # set layer_name self.layer_name = self.layer.origname qgis_layer = get_qgis_layer(self.layer) # create model and add to editing_layers self.metadata_layer = MetadataVectorLayer(qgis_layer, self.layer.origname, layer_id=self.layer.pk)
def set_metadata_relations(self, request, **kwargs): # init relations self.set_relations() for idr, relation in self.relations.items(): # check if in relation there is referencedLayer == self layer if relation['referencedLayer'] == self.layer.qgs_layer_id: # get relation layer object relation_layer = Layer.objects.get( qgs_layer_id=relation['referencingLayer'], project=self.layer.project) geomodel, database_to_use, geometrytype = create_geomodel_from_qdjango_layer( relation_layer) if geometrytype and geometrytype != QGIS_LAYER_TYPE_NO_GEOM: serializer = QGISGeoLayerSerializer else: serializer = QGISLayerSerializer self.metadata_relations[ relation['referencingLayer']] = MetadataVectorLayer( geomodel, serializer, geometrytype, relation_layer.origname, idr, using=database_to_use, layer=relation_layer, referencing_field=relation['fieldRef'] ['referencingField'], referenced_field_is_pk=self.metadata_layer.model._meta. pk.name == relation['fieldRef']['referencedField'], layer_id=relation_layer.pk)
def fetch_values_from_layer(self): """ (Re)fetches plot values from the source layer. Modified by Walter lorenzetti for integration into G3W-SUITE :param djrequest: Django HttpRequest instance. """ # Note: we keep things nice and efficient and only iterate a single time over the layer! if self.layer: self.metadata_layer = MetadataVectorLayer( self.source_layer, self.layer.origname, layer_id=self.layer.pk ) if not self.context_generator: context = QgsExpressionContext() context.appendScopes( QgsExpressionContextUtils.globalProjectLayerScopes(self.source_layer)) else: context = self.context_generator.createExpressionContext() # add a new scope corresponding to the source layer -- this will potentially overwrite any other # layer scopes which may be present in the context (e.g. from atlas layers), but we need to ensure # that source layer fields and attributes are present in the context context.appendScope( self.source_layer.createExpressionContextScope()) self.settings.data_defined_properties.prepare(context) self.fetch_layout_properties(context) def add_source_field_or_expression(field_or_expression): field_index = self.source_layer.fields().lookupField(field_or_expression) if field_index == -1: expression = QgsExpression(field_or_expression) if not expression.hasParserError(): expression.prepare(context) return expression, expression.needsGeometry(), expression.referencedColumns() return None, False, {field_or_expression} x_expression, x_needs_geom, x_attrs = add_source_field_or_expression(self.settings.properties['x_name']) if \ self.settings.properties[ 'x_name'] else (None, False, set()) y_expression, y_needs_geom, y_attrs = add_source_field_or_expression(self.settings.properties['y_name']) if \ self.settings.properties[ 'y_name'] else (None, False, set()) z_expression, z_needs_geom, z_attrs = add_source_field_or_expression(self.settings.properties['z_name']) if \ self.settings.properties[ 'z_name'] else (None, False, set()) additional_info_expression, additional_needs_geom, additional_attrs = add_source_field_or_expression( self.settings.layout['additional_info_expression']) if self.settings.layout[ 'additional_info_expression'] else (None, False, set()) attrs = set().union(self.settings.data_defined_properties.referencedFields(), x_attrs, y_attrs, z_attrs, additional_attrs) request = QgsFeatureRequest() if self.settings.data_defined_properties.property(PlotSettings.PROPERTY_FILTER).isActive(): expression = self.settings.data_defined_properties.property( PlotSettings.PROPERTY_FILTER).asExpression() request.setFilterExpression(expression) request.setExpressionContext(context) original_subset_string = self.source_layer.subsetString() if hasattr(self, 'filter_backends') \ and hasattr(self, 'djrequest') \ and hasattr(self, 'layer') \ and self.djrequest \ and self.layer: for backend in self.filter_backends: backend().apply_filter(self.djrequest, self.metadata_layer, request, self) request.setSubsetOfAttributes(attrs, self.source_layer.fields()) if not x_needs_geom and not y_needs_geom and not z_needs_geom and not additional_needs_geom and not self.settings.data_defined_properties.hasActiveProperties(): request.setFlags(QgsFeatureRequest.NoGeometry) visible_geom_engine = None if self.visible_features_only and self.visible_region is not None: ct = QgsCoordinateTransform(self.visible_region.crs(), self.source_layer.crs(), QgsProject.instance().transformContext()) try: rect = ct.transformBoundingBox(self.visible_region) request.setFilterRect(rect) except QgsCsException: pass elif self.visible_features_only and self.polygon_filter is not None: ct = QgsCoordinateTransform(self.polygon_filter.crs(), self.source_layer.crs(), QgsProject.instance().transformContext()) try: rect = ct.transformBoundingBox( self.polygon_filter.geometry.boundingBox()) request.setFilterRect(rect) g = self.polygon_filter.geometry g.transform(ct) visible_geom_engine = QgsGeometry.createGeometryEngine( g.constGet()) visible_geom_engine.prepareGeometry() except QgsCsException: pass # self.selected_features_only is not used into qplotly module ! # ------------------------------------------------------------- # if self.selected_features_only: # it = self.source_layer.getSelectedFeatures(request) # else: it = self.source_layer.getFeatures(request) self.qgsrequest = request # Some plot types don't draw individual glyphs for each feature, but aggregate them instead. # In that case it doesn't make sense to evaluate expressions for settings like marker size or color for each # feature. Instead, the evaluation should be executed only once for these settings. aggregating = self.settings.plot_type in ['box', 'histogram'] executed = False xx = [] yy = [] zz = [] additional_hover_text = [] marker_sizes = [] colors = [] stroke_colors = [] stroke_widths = [] for f in it: if visible_geom_engine and not visible_geom_engine.intersects(f.geometry().constGet()): continue self.settings.feature_ids.append(f.id()) context.setFeature(f) x = None if x_expression: x = x_expression.evaluate(context) if x == NULL or x is None: continue elif self.settings.properties['x_name']: x = f[self.settings.properties['x_name']] if x == NULL or x is None: continue y = None if y_expression: y = y_expression.evaluate(context) if y == NULL or y is None: continue elif self.settings.properties['y_name']: y = f[self.settings.properties['y_name']] if y == NULL or y is None: continue z = None if z_expression: z = z_expression.evaluate(context) if z == NULL or z is None: continue elif self.settings.properties['z_name']: z = f[self.settings.properties['z_name']] if z == NULL or z is None: continue if additional_info_expression: additional_hover_text.append( additional_info_expression.evaluate(context)) elif self.settings.layout['additional_info_expression']: additional_hover_text.append( f[self.settings.layout['additional_info_expression']]) if x is not None: xx.append(x) if y is not None: yy.append(y) if z is not None: zz.append(z) if self.settings.data_defined_properties.isActive(PlotSettings.PROPERTY_MARKER_SIZE): default_value = self.settings.properties['marker_size'] context.setOriginalValueVariable(default_value) value, _ = self.settings.data_defined_properties.valueAsDouble(PlotSettings.PROPERTY_MARKER_SIZE, context, default_value) marker_sizes.append(value) if self.settings.data_defined_properties.isActive(PlotSettings.PROPERTY_STROKE_WIDTH): default_value = self.settings.properties['marker_width'] context.setOriginalValueVariable(default_value) value, _ = self.settings.data_defined_properties.valueAsDouble(PlotSettings.PROPERTY_STROKE_WIDTH, context, default_value) stroke_widths.append(value) if self.settings.data_defined_properties.isActive(PlotSettings.PROPERTY_COLOR) and (not aggregating or not executed): default_value = QColor(self.settings.properties['in_color']) value, conversion_success = self.settings.data_defined_properties.valueAsColor(PlotSettings.PROPERTY_COLOR, context, default_value) if conversion_success: # We were given a valid color specification, use that color colors.append(value.name()) else: try: # Attempt to interpret the value as a list of color specifications value_list = self.settings.data_defined_properties.value( PlotSettings.PROPERTY_COLOR, context) color_list = [QgsSymbolLayerUtils.decodeColor( item).name() for item in value_list] colors.extend(color_list) except TypeError: # Not a list of color specifications, use the default color instead colors.append(default_value.name()) if self.settings.data_defined_properties.isActive(PlotSettings.PROPERTY_STROKE_COLOR) and (not aggregating or not executed): default_value = QColor(self.settings.properties['out_color']) value, conversion_success = self.settings.data_defined_properties.valueAsColor(PlotSettings.PROPERTY_STROKE_COLOR, context, default_value) if conversion_success: # We were given a valid color specification, use that color stroke_colors.append(value.name()) else: try: # Attempt to interpret the value as a list of color specifications value_list = self.settings.data_defined_properties.value( PlotSettings.PROPERTY_STROKE_COLOR, context) color_list = [QgsSymbolLayerUtils.decodeColor( item).name() for item in value_list] stroke_colors.extend(color_list) except TypeError: # Not a list of color specifications, use the default color instead stroke_colors.append(default_value.name()) executed = True self.settings.additional_hover_text = additional_hover_text self.settings.x = xx self.settings.y = yy self.settings.z = zz if marker_sizes: self.settings.data_defined_marker_sizes = marker_sizes if colors: self.settings.data_defined_colors = colors if stroke_colors: self.settings.data_defined_stroke_colors = stroke_colors if stroke_widths: self.settings.data_defined_stroke_widths = stroke_widths # Restore the original subset string self.source_layer.setSubsetString(original_subset_string)