Esempio n. 1
0
    def testProjectStorage(self):
        # New project without fileName
        p0 = QgsProject()
        self.assertTrue(p0.auxiliaryStorage().isValid())

        # Create new layers with key otherwise auxiliary layers are not
        # automacially created when added in project
        vl0 = createLayer()
        vl0Shp = writeShape(vl0, 'vl0.shp')

        vl1 = createLayer()
        vl1Shp = writeShape(vl1, 'vl1.shp')

        vl0 = QgsVectorLayer(vl0Shp, 'points', 'ogr')
        self.assertTrue(vl0.isValid())

        vl1 = QgsVectorLayer(vl1Shp, 'points', 'ogr')
        self.assertTrue(vl1.isValid())

        # Add layers to project and check underlying auxiliary layers
        p0.addMapLayers([vl0, vl1])

        self.assertTrue(vl0.loadAuxiliaryLayer(p0.auxiliaryStorage(), 'pk'))
        self.assertTrue(
            vl1.loadAuxiliaryLayer(p0.auxiliaryStorage(), 'num_char'))

        al0 = vl0.auxiliaryLayer()
        al1 = vl1.auxiliaryLayer()

        self.assertEqual(al0.joinInfo().targetFieldName(), 'pk')
        self.assertEqual(al1.joinInfo().targetFieldName(), 'num_char')

        # Add a field in auxiliary layers
        pdef0 = QgsPropertyDefinition('propname',
                                      QgsPropertyDefinition.DataTypeNumeric,
                                      '', '', 'ut')
        self.assertTrue(al0.addAuxiliaryField(pdef0))

        pdef1 = QgsPropertyDefinition('propname1',
                                      QgsPropertyDefinition.DataTypeString, '',
                                      '', 'ut')
        self.assertTrue(al1.addAuxiliaryField(pdef1))

        # Check auxiliary fields names
        af0Name = QgsAuxiliaryLayer.nameFromProperty(pdef0, False)
        self.assertEqual(af0Name, 'ut_propname')
        af1Name = QgsAuxiliaryLayer.nameFromProperty(pdef1, False)
        self.assertEqual(af1Name, 'ut_propname1')

        # Set value for auxiliary fields
        req = QgsFeatureRequest().setFilterExpression("name = 'Honey'")
        f = QgsFeature()
        vl0.getFeatures(req).nextFeature(f)
        self.assertTrue(f.isValid())
        af0Name = QgsAuxiliaryLayer.nameFromProperty(pdef0, True)
        index0 = vl0.fields().indexOf(af0Name)
        vl0.changeAttributeValue(f.id(), index0, 333)

        req = QgsFeatureRequest().setFilterExpression("name = 'Apple'")
        f = QgsFeature()
        vl1.getFeatures(req).nextFeature(f)
        self.assertTrue(f.isValid())
        af1Name = QgsAuxiliaryLayer.nameFromProperty(pdef1, True)
        index1 = vl1.fields().indexOf(af1Name)
        vl1.changeAttributeValue(f.id(), index0, 'myvalue')

        req = QgsFeatureRequest().setFilterExpression("name = 'Orange'")
        f = QgsFeature()
        vl1.getFeatures(req).nextFeature(f)
        self.assertTrue(f.isValid())
        vl1.changeAttributeValue(f.id(), index0, 'myvalue1')

        # Save the project in a zip file
        f = tmpPath() + '.qgz'
        p0.write(f)

        # Open the zip file with embedded auxiliary storage
        p1 = QgsProject()
        p1.read(f)

        # Check that auxiliary fields are well loaded in layers
        self.assertEqual(len(p1.mapLayers().values()), 2)

        for vl in p1.mapLayers().values():
            al = vl.auxiliaryLayer()
            self.assertEqual(len(al.auxiliaryFields()), 1)

            af = al.auxiliaryFields()[0]
            afPropDef = QgsAuxiliaryLayer.propertyDefinitionFromField(af)
            self.assertEqual(afPropDef.origin(), 'ut')

            if vl.auxiliaryLayer().joinInfo().targetFieldName() == 'pk':
                self.assertEqual(afPropDef.name(), 'propname')
                self.assertEqual(al.featureCount(), 1)

                req = QgsFeatureRequest().setFilterExpression("name = 'Honey'")
                f = QgsFeature()
                vl.getFeatures(req).nextFeature(f)
                self.assertTrue(f.isValid())
                self.assertEqual(f.attributes()[index0], 333.0)
            else:  # num_char
                self.assertEqual(al.featureCount(), 2)
                self.assertEqual(afPropDef.name(), 'propname1')

                req = QgsFeatureRequest().setFilterExpression("name = 'Apple'")
                f = QgsFeature()
                vl.getFeatures(req).nextFeature(f)
                self.assertTrue(f.isValid())
                self.assertEqual(f.attributes()[index1], 'myvalue')

                req = QgsFeatureRequest().setFilterExpression(
                    "name = 'Orange'")
                f = QgsFeature()
                vl.getFeatures(req).nextFeature(f)
                self.assertTrue(f.isValid())
                self.assertEqual(f.attributes()[index1], 'myvalue1')
Esempio n. 2
0
    def testAuxiliaryFieldWidgets(self):
        # Init storage
        s = QgsAuxiliaryStorage()
        self.assertTrue(s.isValid())

        # Create a new auxiliary layer with 'pk' as key
        vl = createLayer()
        pkf = vl.fields().field(vl.fields().indexOf('pk'))
        al = s.createAuxiliaryLayer(pkf, vl)
        self.assertTrue(al.isValid())

        # Set the auxiliary layer to the vector layer
        vl.setAuxiliaryLayer(al)

        # Add a visible property
        p = QgsPropertyDefinition('propName', QgsPropertyDefinition.DataTypeNumeric, '', '', 'user')
        self.assertTrue(al.addAuxiliaryField(p))

        index = al.indexOfPropertyDefinition(p)
        self.assertFalse(al.isHiddenProperty(index))

        afName = QgsAuxiliaryLayer.nameFromProperty(p, True)
        index = vl.fields().indexOf(afName)
        setup = vl.editorWidgetSetup(index)
        self.assertEqual(setup.type(), '')

        tested = False
        for c in vl.attributeTableConfig().columns():
            if c.name == afName:
                self.assertFalse(c.hidden)
                tested = True
                break
        self.assertTrue(tested)

        # Add a hidden property
        p = QgsPalLayerSettings.propertyDefinitions()[QgsPalLayerSettings.PositionX]
        self.assertTrue(al.addAuxiliaryField(p))

        index = al.indexOfPropertyDefinition(p)
        self.assertTrue(al.isHiddenProperty(index))

        afName = QgsAuxiliaryLayer.nameFromProperty(p, True)
        index = vl.fields().indexOf(afName)
        setup = vl.editorWidgetSetup(index)
        self.assertEqual(setup.type(), 'Hidden')

        tested = False
        for c in vl.attributeTableConfig().columns():
            if c.name == afName:
                self.assertTrue(c.hidden)
                tested = True
                break
        self.assertTrue(tested)

        # Add a color property
        p = QgsSymbolLayer.propertyDefinitions()[QgsSymbolLayer.PropertyFillColor]
        self.assertTrue(al.addAuxiliaryField(p))

        index = al.indexOfPropertyDefinition(p)
        self.assertFalse(al.isHiddenProperty(index))

        afName = QgsAuxiliaryLayer.nameFromProperty(p, True)
        index = vl.fields().indexOf(afName)
        setup = vl.editorWidgetSetup(index)
        self.assertEqual(setup.type(), 'Color')
Esempio n. 3
0
    def testProjectColor(self):
        scheme = [
            s for s in QgsApplication.colorSchemeRegistry().schemes()
            if isinstance(s, QgsProjectColorScheme)
        ][0]
        scheme.setColors([])

        definition = QgsPropertyDefinition(
            'test', 'test', QgsPropertyDefinition.ColorWithAlpha)
        button = QgsPropertyOverrideButton()
        button.init(0, QgsProperty(), definition)

        button.aboutToShowMenu()

        self.assertIn('Project Color',
                      [a.text() for a in button.menu().actions()])
        self.assertIn('Color', [a.text() for a in button.menu().actions()])
        color_action = [
            a for a in button.menu().actions() if a.text() == 'Color'
        ][0]
        self.assertEqual([a.text() for a in color_action.menu().actions()][0],
                         'No colors set')

        # add some project colors
        scheme.setColors([[QColor(255, 0, 0), 'color 1'],
                          [QColor(255, 255, 0), 'burnt marigold']])

        button.aboutToShowMenu()
        self.assertIn('Project Color',
                      [a.text() for a in button.menu().actions()])
        self.assertIn('Color', [a.text() for a in button.menu().actions()])
        color_action = [
            a for a in button.menu().actions() if a.text() == 'Color'
        ][0]
        self.assertEqual([a.text() for a in color_action.menu().actions()],
                         ['color 1', 'burnt marigold'])

        button.menuActionTriggered(color_action.menu().actions()[1])
        self.assertTrue(button.toProperty().isActive())
        self.assertEqual(button.toProperty().asExpression(),
                         'project_color(\'burnt marigold\')')

        button.menuActionTriggered(color_action.menu().actions()[0])
        self.assertTrue(button.toProperty().isActive())
        self.assertEqual(button.toProperty().asExpression(),
                         'project_color(\'color 1\')')

        button.setToProperty(
            QgsProperty.fromExpression('project_color(\'burnt marigold\')'))
        button.aboutToShowMenu()
        color_action = [
            a for a in button.menu().actions() if a.text() == 'Color'
        ][0]
        self.assertTrue(color_action.isChecked())
        self.assertEqual(
            [a.isChecked() for a in color_action.menu().actions()],
            [False, True])

        # should also see color menu for ColorNoAlpha properties
        definition = QgsPropertyDefinition('test', 'test',
                                           QgsPropertyDefinition.ColorNoAlpha)
        button = QgsPropertyOverrideButton()
        button.init(0, QgsProperty(), definition)

        button.aboutToShowMenu()
        self.assertIn('Project Color',
                      [a.text() for a in button.menu().actions()])
        self.assertIn('Color', [a.text() for a in button.menu().actions()])

        # but no color menu for other types
        definition = QgsPropertyDefinition('test', 'test',
                                           QgsPropertyDefinition.Double)
        button = QgsPropertyOverrideButton()
        button.init(0, QgsProperty(), definition)

        button.aboutToShowMenu()
        self.assertNotIn('Project Color',
                         [a.text() for a in button.menu().actions()])
        self.assertNotIn('Color', [a.text() for a in button.menu().actions()])
Esempio n. 4
0
class PlotSettings:  # pylint: disable=too-many-instance-attributes
    """
    The PlotSettings class encapsulates all settings relating to a plot, and contains
    methods for serializing and deserializing these settings.
    """

    PROPERTY_FILTER = 1
    PROPERTY_MARKER_SIZE = 2
    PROPERTY_COLOR = 3
    PROPERTY_STROKE_COLOR = 4
    PROPERTY_STROKE_WIDTH = 5

    DYNAMIC_PROPERTIES = {
        PROPERTY_FILTER:
        QgsPropertyDefinition('filter', 'Feature filter',
                              QgsPropertyDefinition.Boolean),
        PROPERTY_MARKER_SIZE:
        QgsPropertyDefinition('marker_size', 'Marker size',
                              QgsPropertyDefinition.DoublePositive),
        PROPERTY_COLOR:
        QgsPropertyDefinition('color', 'Color',
                              QgsPropertyDefinition.ColorWithAlpha),
        PROPERTY_STROKE_COLOR:
        QgsPropertyDefinition('stroke_color', 'Stroke color',
                              QgsPropertyDefinition.ColorWithAlpha),
        PROPERTY_STROKE_WIDTH:
        QgsPropertyDefinition('stroke_width', 'Stroke width',
                              QgsPropertyDefinition.DoublePositive)
    }

    def __init__(self,
                 plot_type: str = 'scatter',
                 properties: dict = None,
                 layout: dict = None,
                 source_layer_id=None):
        # Define default plot dictionary used as a basis for plot initialization
        # prepare the default dictionary with None values
        # plot properties
        plot_base_properties = {
            'marker': 'markers',
            'custom': None,
            'hover_text': None,
            'additional_hover_text': None,
            'x_name': '',
            'y_name': '',
            'z_name': '',
            'in_color': '#8ebad9',
            'out_color': '#1f77b4',
            'marker_width': 1,
            'marker_size': 10,
            'marker_symbol': 0,
            'line_dash': 'solid',
            'box_orientation': 'v',
            'box_stat': None,
            'box_outliers': False,
            'name': '',
            'normalization': None,
            'cont_type': 'fill',
            'color_scale': None,
            'show_lines': False,
            'cumulative': False,
            'show_colorscale_legend': False,
            'invert_color_scale': False,
            'invert_hist': 'increasing',
            'bins': 0,
            'selected_features_only': False,
            'visible_features_only': False,
            'color_scale_data_defined_in_check': False,
            'color_scale_data_defined_in_invert_check': False,
            'marker_type_combo': 'Points',
            'point_combo': '',
            'line_combo': 'Solid Line',
            'contour_type_combo': 'Fill',
            'show_lines_check': False,
            'opacity': 1,
            'violin_side': None,
            'show_mean_line': False
        }

        # layout nested dictionary
        plot_base_layout = {
            'title': 'Plot Title',
            'legend': True,
            'legend_title': None,
            'legend_orientation': 'h',
            'x_title': '',
            'y_title': '',
            'z_title': '',
            'xaxis': None,
            'bar_mode': None,
            'x_type': None,
            'y_type': None,
            'x_inv': None,
            'y_inv': None,
            'range_slider': {
                'borderwidth': 1,
                'visible': False
            },
            'bargaps': 0,
            'polar': {
                'angularaxis': {
                    'direction': 'clockwise'
                }
            },
            'additional_info_expression': '',
            'bins_check': False
        }

        self.plot_base_dic = {
            'plot_type': None,
            'layer': None,
            'plot_prop': plot_base_properties,
            'layout_prop': plot_base_layout
        }

        self.data_defined_properties = QgsPropertyCollection()

        # Set class properties - we use the base dictionaries, replacing base values with
        # those from the passed properties dicts
        if properties is None:
            self.properties = plot_base_properties
        else:
            self.properties = {**plot_base_properties, **properties}
        if layout is None:
            self.layout = plot_base_layout
        else:
            self.layout = {**plot_base_layout, **layout}

        self.plot_type = plot_type

        self.x = []
        self.y = []
        self.z = []
        self.feature_ids = []
        self.additional_hover_text = []
        self.data_defined_marker_sizes = []
        self.data_defined_colors = []
        self.data_defined_stroke_colors = []
        self.data_defined_stroke_widths = []
        self.source_layer_id = source_layer_id

    def write_xml(self, document: QDomDocument):
        """
        Writes the plot settings to an XML element
        """
        element = QgsXmlUtils.writeVariant(
            {
                'plot_type':
                self.plot_type,
                'plot_properties':
                self.properties,
                'plot_layout':
                self.layout,
                'source_layer_id':
                self.source_layer_id,
                'dynamic_properties':
                self.data_defined_properties.toVariant(
                    PlotSettings.DYNAMIC_PROPERTIES)
            }, document)
        return element

    def read_xml(self, element: QDomElement) -> bool:
        """
        Reads the plot settings from an XML element
        """
        res = QgsXmlUtils.readVariant(element)
        if not isinstance(res, dict) or \
                'plot_type' not in res or \
                'plot_properties' not in res or \
                'plot_layout' not in res:
            return False

        self.plot_type = res['plot_type']
        self.properties = res['plot_properties']
        self.layout = res['plot_layout']
        self.source_layer_id = res.get('source_layer_id', None)
        self.data_defined_properties.loadVariant(
            res.get('dynamic_properties', None),
            PlotSettings.DYNAMIC_PROPERTIES)

        return True

    def write_to_project(self, document: QDomDocument):
        """
        Writes the settings to a project (represented by the given DOM document)
        """
        elem = self.write_xml(document)
        parent_elem = document.createElement('DataPlotly')
        parent_elem.appendChild(elem)

        root_node = document.elementsByTagName("qgis").item(0)
        root_node.appendChild(parent_elem)

    def read_from_project(self, document: QDomDocument):
        """
        Reads the settings from a project (represented by the given DOM document)
        """
        root_node = document.elementsByTagName("qgis").item(0)
        if root_node.isNull():
            return False

        node = root_node.toElement().firstChildElement('DataPlotly')
        if node.isNull():
            return False

        elem = node.toElement()
        return self.read_xml(elem.firstChildElement())

    def write_to_file(self, file_name: str) -> bool:
        """
        Writes the settings to an XML file
        """
        document = QDomDocument("dataplotly")
        elem = self.write_xml(document)
        document.appendChild(elem)

        try:
            with open(file_name, "w") as f:
                f.write('<?xml version="1.0" encoding="UTF-8"?>\n')
                f.write(document.toString())
                return True
        except FileNotFoundError:
            return False

    def read_from_file(self, file_name: str) -> bool:
        """
        Reads the settings from an XML file
        """
        f = QFile(file_name)
        if f.open(QIODevice.ReadOnly):
            document = QDomDocument()
            if document.setContent(f):
                if self.read_xml(document.firstChildElement()):
                    return True

        return False
Esempio n. 5
0
    def testCreateField(self):
        s = QgsAuxiliaryStorage()
        self.assertTrue(s.isValid())

        # Create a new auxiliary layer with 'pk' as key
        vl = createLayer()
        pkf = vl.fields().field(vl.fields().indexOf('pk'))
        al = s.createAuxiliaryLayer(pkf, vl)
        self.assertTrue(al.isValid())
        vl.setAuxiliaryLayer(al)

        prop = QgsPropertyDefinition()
        prop.setComment('test_field')
        prop.setDataType(QgsPropertyDefinition.DataTypeNumeric)
        prop.setOrigin('user')
        prop.setName('custom')
        self.assertTrue(al.addAuxiliaryField(prop))

        prop = QgsPropertyDefinition()
        prop.setComment('test_field_string')
        prop.setDataType(QgsPropertyDefinition.DataTypeString)
        prop.setOrigin('user')
        prop.setName('custom')
        self.assertTrue(al.addAuxiliaryField(prop))

        self.assertEqual(len(al.auxiliaryFields()), 2)
        self.assertEqual(al.auxiliaryFields()[0].name(),
                         'user_custom_test_field')
        self.assertEqual(al.auxiliaryFields()[0].type(), QVariant.Double)
        self.assertEqual(al.auxiliaryFields()[0].typeName(), 'Real')
        self.assertEqual(al.auxiliaryFields()[1].name(),
                         'user_custom_test_field_string')
        self.assertEqual(al.auxiliaryFields()[1].type(), QVariant.String)
        self.assertEqual(al.auxiliaryFields()[1].typeName(), 'String')
Esempio n. 6
0
    def initAlgorithm(self, config=None):

        # layer
        self.addParameter(
            QgsProcessingParameterFeatureSource(self.INPUT,
                                                self.tr('Input layer')))

        # x fields (or expression)
        self.addParameter(
            QgsProcessingParameterExpression(
                self.XEXPRESSION,
                self.tr('X Field'),
                parentLayerParameterName=self.INPUT))

        # y field (or expression)
        self.addParameter(
            QgsProcessingParameterExpression(
                self.YEXPRESSION,
                self.tr('Y Field'),
                parentLayerParameterName=self.INPUT))

        # size
        size_param = QgsProcessingParameterNumber(self.SIZE,
                                                  self.tr('Marker size'),
                                                  defaultValue=10)
        size_param.setIsDynamic(True)
        size_param.setDynamicLayerParameterName(self.INPUT)
        size_param.setDynamicPropertyDefinition(
            QgsPropertyDefinition(
                "SIZE",
                self.tr("Size"),
                QgsPropertyDefinition.Double,
            ))
        self.addParameter(size_param)

        # color
        color_param = QgsProcessingParameterColor(self.COLOR,
                                                  self.tr('Color'),
                                                  optional=True,
                                                  defaultValue='#8ebad9')
        color_param.setIsDynamic(True)
        color_param.setDynamicLayerParameterName(self.INPUT)
        color_param.setDynamicPropertyDefinition(
            QgsPropertyDefinition(
                "COLOR",
                self.tr("Color"),
                QgsPropertyDefinition.Double,
            ))
        self.addParameter(color_param)

        facet_row = QgsProcessingParameterExpression(
            self.FACET_ROW,
            self.tr('Facet row'),
            parentLayerParameterName=self.INPUT)
        facet_row.setFlags(QgsProcessingParameterDefinition.FlagAdvanced
                           | QgsProcessingParameterDefinition.FlagOptional)
        self.addParameter(facet_row)

        facet_col = QgsProcessingParameterExpression(
            self.FACET_COL,
            self.tr('Facet col'),
            optional=True,
            parentLayerParameterName=self.INPUT)
        facet_col.setFlags(QgsProcessingParameterDefinition.FlagAdvanced
                           | QgsProcessingParameterDefinition.FlagOptional)
        self.addParameter(facet_col)

        # offline parameter
        offline_param = QgsProcessingParameterBoolean(
            self.OFFLINE,
            self.tr('Complete offline usage'),
            defaultValue=False)
        offline_param.setFlags(QgsProcessingParameterDefinition.FlagAdvanced)
        self.addParameter(offline_param)

        # html file output
        self.addParameter(
            QgsProcessingParameterFileDestination(
                self.OUTPUT_HTML_FILE, self.tr('Scatter Plot'),
                self.tr('HTML files (*.html)')))

        # json file output
        self.addParameter(
            QgsProcessingParameterFileDestination(
                self.OUTPUT_JSON_FILE,
                self.tr('JSON file'),
                self.tr('JSON Files (*.json)'),
                createByDefault=False,
                optional=True))