Ejemplo n.º 1
0
    def test_selected_feature_values(self):
        """
        Test value collection for selected features
        """

        layer_path = os.path.join(os.path.dirname(__file__), 'test_layer.shp')

        vl1 = QgsVectorLayer(layer_path, 'test_layer', 'ogr')
        vl1.setSubsetString('id < 10')
        self.assertTrue(vl1.isValid())
        QgsProject.instance().addMapLayer(vl1)

        # default plot settings
        settings = PlotSettings('scatter')
        settings.properties['selected_features_only'] = True
        settings.source_layer_id = vl1.id()

        settings.properties['x_name'] = 'so4'
        settings.properties['y_name'] = 'ca'
        factory = PlotFactory(settings)
        # no selection, no values
        self.assertEqual(factory.settings.x, [])
        self.assertEqual(factory.settings.y, [])
        self.assertEqual(factory.settings.z, [])
        self.assertEqual(factory.settings.additional_hover_text, [])

        vl1.selectByIds([1, 3, 4])
        factory = PlotFactory(settings)
        self.assertEqual(factory.settings.x, [88, 329, 319])
        self.assertEqual(factory.settings.y, [22.26, 35.05, 46.64])

        vl1.selectByIds([])
        factory = PlotFactory(settings)
        self.assertEqual(factory.settings.x, [])
        self.assertEqual(factory.settings.y, [])
Ejemplo n.º 2
0
    def test_data_defined_stroke_color(self):
        """
        Test data defined stroke color
        """
        layer_path = os.path.join(os.path.dirname(__file__), 'test_layer.shp')

        vl1 = QgsVectorLayer(layer_path, 'test_layer', 'ogr')
        vl1.setSubsetString('id < 10')
        self.assertTrue(vl1.isValid())
        QgsProject.instance().addMapLayer(vl1)

        settings = PlotSettings('scatter')
        settings.source_layer_id = vl1.id()
        settings.properties['x_name'] = 'so4'
        settings.properties['y_name'] = 'mg'
        settings.properties['in_color'] = 'red'

        factory = PlotFactory(settings)
        # should be empty, not using data defined size
        self.assertEqual(factory.settings.x,
                         [98, 88, 267, 329, 319, 137, 350, 151, 203])
        self.assertEqual(
            factory.settings.y,
            [72.31, 86.03, 85.26, 81.11, 131.59, 95.36, 112.88, 80.55, 78.34])
        self.assertEqual(factory.settings.data_defined_colors, [])

        class TestGenerator(QgsExpressionContextGenerator):  # pylint: disable=missing-docstring, too-few-public-methods
            def createExpressionContext(self) -> QgsExpressionContext:  # pylint: disable=missing-docstring, no-self-use
                context = QgsExpressionContext()
                scope = QgsExpressionContextScope()
                scope.setVariable('some_var', 10)
                context.appendScope(scope)
                context.appendScope(vl1.createExpressionContextScope())
                return context

        generator = TestGenerator()
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_STROKE_COLOR,
            QgsProperty.fromExpression(
                'case when round("ca"/@some_var)>10 then \'yellow\' else \'blue\' end'
            ))
        factory = PlotFactory(settings, context_generator=generator)
        self.assertEqual(factory.settings.x,
                         [98, 88, 267, 329, 319, 137, 350, 151, 203])
        self.assertEqual(
            factory.settings.y,
            [72.31, 86.03, 85.26, 81.11, 131.59, 95.36, 112.88, 80.55, 78.34])
        self.assertEqual(factory.settings.data_defined_stroke_colors, [
            '#0000ff', '#0000ff', '#0000ff', '#0000ff', '#0000ff', '#ffff00',
            '#ffff00', '#ffff00', '#ffff00'
        ])
Ejemplo n.º 3
0
    def test_data_defined_histogram_color(self):
        """
        Test data defined stroke color
        """
        layer_path = os.path.join(os.path.dirname(__file__),
                                  'test_layer.geojson')

        vl1 = QgsVectorLayer(layer_path, 'test_layer', 'ogr')
        QgsProject.instance().addMapLayer(vl1)

        settings = PlotSettings('histogram')
        settings.source_layer_id = vl1.id()
        settings.properties['x_name'] = 'so4'

        factory = PlotFactory(settings)

        self.assertEqual(factory.settings.x, [
            203, 151, 350, 137, 319, 329, 267, 88, 98, 84, 100, 627, 306, 513,
            267, 457, 683, 791, 788, 265, 296, 680, 536, 1122, 632, 1055, 1322
        ])
        self.assertEqual(factory.settings.data_defined_colors, [])

        class TestGenerator(QgsExpressionContextGenerator):  # pylint: disable=missing-docstring, too-few-public-methods
            def createExpressionContext(self) -> QgsExpressionContext:  # pylint: disable=missing-docstring, no-self-use
                context = QgsExpressionContext()
                scope = QgsExpressionContextScope()
                context.appendScope(scope)
                context.appendScope(vl1.createExpressionContextScope())
                return context

        generator = TestGenerator()
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_COLOR,
            QgsProperty.fromExpression("""array('215,25,28,255',
                     '241,124,74,255',
                     '254,201,128,255',
                     '255,255,191,255',
                     '199,230,219,255',
                     '129,186,216,255',
                     '44,123,182,255')"""))
        factory = PlotFactory(settings, context_generator=generator)
        self.assertEqual(factory.settings.x, [
            203, 151, 350, 137, 319, 329, 267, 88, 98, 84, 100, 627, 306, 513,
            267, 457, 683, 791, 788, 265, 296, 680, 536, 1122, 632, 1055, 1322
        ])
        self.assertEqual(factory.settings.y, [])
        self.assertEqual(factory.settings.data_defined_colors, [
            "#d7191c", "#f17c4a", "#fec980", "#ffffbf", "#c7e6db", "#81bad8",
            "#2c7bb6"
        ])
Ejemplo n.º 4
0
    def test_data_defined_sizes(self):
        """
        Test data defined marker sizes
        """
        layer_path = os.path.join(os.path.dirname(__file__), 'test_layer.shp')

        vl1 = QgsVectorLayer(layer_path, 'test_layer', 'ogr')
        vl1.setSubsetString('id < 10')
        self.assertTrue(vl1.isValid())
        QgsProject.instance().addMapLayer(vl1)

        settings = PlotSettings('scatter')
        settings.source_layer_id = vl1.id()
        settings.properties['x_name'] = 'so4'
        settings.properties['y_name'] = 'mg'
        settings.properties['marker_size'] = 15

        factory = PlotFactory(settings)
        # should be empty, not using data defined size
        self.assertEqual(factory.settings.x,
                         [98, 88, 267, 329, 319, 137, 350, 151, 203])
        self.assertEqual(
            factory.settings.y,
            [72.31, 86.03, 85.26, 81.11, 131.59, 95.36, 112.88, 80.55, 78.34])
        self.assertEqual(factory.settings.data_defined_marker_sizes, [])

        class TestGenerator(QgsExpressionContextGenerator):  # pylint: disable=missing-docstring, too-few-public-methods
            def createExpressionContext(self) -> QgsExpressionContext:  # pylint: disable=missing-docstring, no-self-use
                context = QgsExpressionContext()
                scope = QgsExpressionContextScope()
                scope.setVariable('some_var', 10)
                context.appendScope(scope)
                context.appendScope(vl1.createExpressionContextScope())
                return context

        generator = TestGenerator()
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_MARKER_SIZE,
            QgsProperty.fromExpression('round("ca"/@some_var *@value)'))
        factory = PlotFactory(settings, context_generator=generator)
        self.assertEqual(factory.settings.x,
                         [98, 88, 267, 329, 319, 137, 350, 151, 203])
        self.assertEqual(
            factory.settings.y,
            [72.31, 86.03, 85.26, 81.11, 131.59, 95.36, 112.88, 80.55, 78.34])
        self.assertEqual(
            factory.settings.data_defined_marker_sizes,
            [123.0, 33.0, 111.0, 53.0, 70.0, 190.0, 175.0, 162.0, 166.0])
Ejemplo n.º 5
0
    def test_selected_feature_values_dynamic(self):
        """
        Test that factory proactively updates when a selection changes, when desired
        """

        layer_path = os.path.join(os.path.dirname(__file__), 'test_layer.shp')

        vl1 = QgsVectorLayer(layer_path, 'test_layer', 'ogr')
        vl1.setSubsetString('id < 10')
        self.assertTrue(vl1.isValid())
        QgsProject.instance().addMapLayer(vl1)

        # not using selected features
        settings = PlotSettings('scatter')
        settings.properties['selected_features_only'] = False
        settings.source_layer_id = vl1.id()

        settings.properties['x_name'] = 'so4'
        settings.properties['y_name'] = 'ca'
        factory = PlotFactory(settings)
        spy = QSignalSpy(factory.plot_built)
        vl1.selectByIds([1, 3, 4])
        self.assertEqual(len(spy), 0)

        # using selected features
        settings = PlotSettings('scatter')
        settings.properties['selected_features_only'] = True
        settings.source_layer_id = vl1.id()
        settings.properties['x_name'] = 'so4'
        settings.properties['y_name'] = 'ca'
        factory = PlotFactory(settings)
        spy = QSignalSpy(factory.plot_built)

        vl1.selectByIds([1])
        self.assertEqual(len(spy), 1)
        self.assertEqual(factory.settings.x, [88])
        self.assertEqual(factory.settings.y, [22.26])

        vl1.selectByIds([1, 3, 4])
        self.assertEqual(len(spy), 2)
        self.assertEqual(factory.settings.x, [88, 329, 319])
        self.assertEqual(factory.settings.y, [22.26, 35.05, 46.64])

        vl1.selectByIds([])
        self.assertEqual(len(spy), 3)
        self.assertEqual(factory.settings.x, [])
        self.assertEqual(factory.settings.y, [])
Ejemplo n.º 6
0
    def create_plot(self):
        polygon_filter, visible_features_only = self.get_polygon_filter(0)

        config = {'displayModeBar': False, 'staticPlot': True}

        if len(self.plot_settings) == 1:
            plot_factory = PlotFactory(self.plot_settings[0], self, polygon_filter=polygon_filter)
            self.plot_settings[0].properties['visible_features_only'] = visible_features_only
            return plot_factory.build_html(config)

        # to plot many plots in the same figure
        elif len(self.plot_settings) > 1:
            # plot list ready to be called within go.Figure
            pl = []
            plot_factory = PlotFactory(self.plot_settings[0], self, polygon_filter=polygon_filter)

            for current, plot_setting in enumerate(self.plot_settings):
                polygon_filter, visible_features_only = self.get_polygon_filter(current)
                plot_setting.properties['visible_features_only'] = visible_features_only
                factory = PlotFactory(plot_setting, self, polygon_filter=polygon_filter)
                pl.append(factory.trace[0])

            plot_path = plot_factory.build_figures(self.plot_settings[0].plot_type, pl, config=config)
            with open(plot_path, 'r') as myfile:
                return myfile.read()
Ejemplo n.º 7
0
    def create_plot(self):
        if self.linked_map and self.filter_by_map:
            polygon_filter = FilterRegion(QgsGeometry.fromQPolygonF(self.linked_map.visibleExtentPolygon()),
                                          self.linked_map.crs())
            visible_features_only = True
        elif self.filter_by_atlas and self.layout().reportContext().layer() and self.layout().reportContext().feature().isValid():
            polygon_filter = FilterRegion(self.layout().reportContext().currentGeometry(), self.layout().reportContext().layer().crs())
            visible_features_only = True
        else:
            polygon_filter = None
            visible_features_only = False

        config = {'displayModeBar': False, 'staticPlot': True}

        if len(self.plot_settings) == 1:
            plot_factory = PlotFactory(self.plot_settings[0], self, polygon_filter=polygon_filter)
            self.plot_settings[0].properties['visible_features_only'] = visible_features_only
            return plot_factory.build_html(config)

        # to plot many plots in the same figure
        elif len(self.plot_settings) > 1:
            # plot list ready to be called within go.Figure
            pl = []
            plot_factory = PlotFactory(self.plot_settings[0], self, polygon_filter=polygon_filter)

            for plot_setting in self.plot_settings:
                plot_setting.properties['visible_features_only'] = visible_features_only
                factory = PlotFactory(plot_setting, self, polygon_filter=polygon_filter)
                pl.append(factory.trace[0])

            plot_path = plot_factory.build_figures(self.plot_settings[0].plot_type, pl, config=config)
            with open(plot_path, 'r') as myfile:
                return myfile.read()
Ejemplo n.º 8
0
    def test_visible_features(self):
        """
        Test filtering to visible features only
        """
        layer_path = os.path.join(os.path.dirname(__file__), 'test_layer.shp')

        vl1 = QgsVectorLayer(layer_path, 'test_layer', 'ogr')
        vl1.setSubsetString('id < 10')
        self.assertTrue(vl1.isValid())
        QgsProject.instance().addMapLayer(vl1)

        # not using visible features
        settings = PlotSettings('scatter')
        settings.source_layer_id = vl1.id()

        settings.properties['x_name'] = 'so4'
        settings.properties['y_name'] = 'ca'

        rect = QgsReferencedRectangle(QgsRectangle(10.1, 43.5, 10.8, 43.85),
                                      QgsCoordinateReferenceSystem(4326))
        factory = PlotFactory(settings, visible_region=rect)
        spy = QSignalSpy(factory.plot_built)
        self.assertEqual(len(spy), 0)
        self.assertEqual(factory.settings.x,
                         [98, 88, 267, 329, 319, 137, 350, 151, 203])
        self.assertEqual(factory.settings.y, [
            81.87, 22.26, 74.16, 35.05, 46.64, 126.73, 116.44, 108.25, 110.45
        ])

        settings.properties['visible_features_only'] = True
        factory = PlotFactory(settings, visible_region=rect)
        spy = QSignalSpy(factory.plot_built)
        self.assertEqual(factory.settings.x, [88, 350, 151, 203])
        self.assertEqual(factory.settings.y, [22.26, 116.44, 108.25, 110.45])

        factory.set_visible_region(
            QgsReferencedRectangle(QgsRectangle(10.6, 43.1, 12, 43.8),
                                   QgsCoordinateReferenceSystem(4326)))
        self.assertEqual(len(spy), 1)
        self.assertEqual(factory.settings.x, [98, 267, 319, 137])
        self.assertEqual(factory.settings.y, [81.87, 74.16, 46.64, 126.73])

        # with reprojection
        factory.set_visible_region(
            QgsReferencedRectangle(
                QgsRectangle(1167379, 5310986, 1367180, 5391728),
                QgsCoordinateReferenceSystem(3857)))
        self.assertEqual(len(spy), 2)
        self.assertEqual(factory.settings.x, [98, 267, 329, 319, 137])
        self.assertEqual(factory.settings.y,
                         [81.87, 74.16, 35.05, 46.64, 126.73])
Ejemplo n.º 9
0
    def test_filter(self):
        """
        Test that filters are correctly applied
        """
        layer_path = os.path.join(os.path.dirname(__file__), 'test_layer.shp')

        vl1 = QgsVectorLayer(layer_path, 'test_layer', 'ogr')
        vl1.setSubsetString('id < 10')
        self.assertTrue(vl1.isValid())
        QgsProject.instance().addMapLayer(vl1)

        settings = PlotSettings('scatter')
        settings.source_layer_id = vl1.id()
        settings.properties['x_name'] = 'so4'
        settings.properties['y_name'] = 'mg'
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_FILTER,
            QgsProperty.fromExpression('so4/@some_var > 20'))

        factory = PlotFactory(settings)
        # should be empty, variable is not available
        self.assertEqual(factory.settings.x, [])
        self.assertEqual(factory.settings.y, [])
        self.assertEqual(factory.settings.z, [])
        self.assertEqual(factory.settings.additional_hover_text, [])

        class TestGenerator(QgsExpressionContextGenerator):  # pylint: disable=missing-docstring, too-few-public-methods
            def createExpressionContext(self) -> QgsExpressionContext:  # pylint: disable=missing-docstring, no-self-use
                context = QgsExpressionContext()
                scope = QgsExpressionContextScope()
                scope.setVariable('some_var', 10)
                context.appendScope(scope)
                return context

        generator = TestGenerator()
        factory = PlotFactory(settings, context_generator=generator)
        self.assertEqual(factory.settings.x, [267, 329, 319, 350, 203])
        self.assertEqual(factory.settings.y,
                         [85.26, 81.11, 131.59, 112.88, 78.34])
        self.assertEqual(factory.settings.z, [])
        self.assertEqual(factory.settings.additional_hover_text, [])
Ejemplo n.º 10
0
    def test_expression_context(self):
        """
        Test that correct expression context is used when evaluating expressions
        """
        layer_path = os.path.join(os.path.dirname(__file__), 'test_layer.shp')

        vl1 = QgsVectorLayer(layer_path, 'test_layer', 'ogr')
        vl1.setSubsetString('id < 10')
        self.assertTrue(vl1.isValid())
        QgsProject.instance().addMapLayer(vl1)

        settings = PlotSettings('scatter')
        settings.source_layer_id = vl1.id()
        settings.properties['x_name'] = '"so4"/@some_var'
        settings.properties['y_name'] = 'mg'

        factory = PlotFactory(settings)
        # should be empty, variable is not available
        self.assertEqual(factory.settings.x, [])
        self.assertEqual(factory.settings.y, [])
        self.assertEqual(factory.settings.z, [])
        self.assertEqual(factory.settings.additional_hover_text, [])

        class TestGenerator(QgsExpressionContextGenerator):  # pylint: disable=missing-docstring, too-few-public-methods
            def createExpressionContext(self) -> QgsExpressionContext:  # pylint: disable=missing-docstring, no-self-use
                context = QgsExpressionContext()
                scope = QgsExpressionContextScope()
                scope.setVariable('some_var', 10)
                context.appendScope(scope)
                return context

        generator = TestGenerator()
        factory = PlotFactory(settings, context_generator=generator)
        self.assertEqual(factory.settings.x,
                         [9.8, 8.8, 26.7, 32.9, 31.9, 13.7, 35.0, 15.1, 20.3])
        self.assertEqual(
            factory.settings.y,
            [72.31, 86.03, 85.26, 81.11, 131.59, 95.36, 112.88, 80.55, 78.34])
        self.assertEqual(factory.settings.z, [])
        self.assertEqual(factory.settings.additional_hover_text, [])
Ejemplo n.º 11
0
    def create_plot(self):
        if self.linked_map and self.filter_by_map:
            polygon_filter = FilterRegion(
                QgsGeometry.fromQPolygonF(
                    self.linked_map.visibleExtentPolygon()),
                self.linked_map.crs())
            self.plot_settings.properties['visible_features_only'] = True
        elif self.filter_by_atlas and self.layout().reportContext().layer(
        ) and self.layout().reportContext().feature().isValid():
            polygon_filter = FilterRegion(
                self.layout().reportContext().currentGeometry(),
                self.layout().reportContext().layer().crs())
            self.plot_settings.properties['visible_features_only'] = True
        else:
            polygon_filter = None
            self.plot_settings.properties['visible_features_only'] = False

        factory = PlotFactory(self.plot_settings,
                              self,
                              polygon_filter=polygon_filter)
        config = {'displayModeBar': False, 'staticPlot': True}
        return factory.build_html(config)
Ejemplo n.º 12
0
    def test_dates(self):  # pylint: disable=too-many-statements
        """
        Test handling of dates
        """
        # default plot settings
        settings = PlotSettings('scatter')

        # no source layer, fixed values must be used
        settings.source_layer_id = ''
        settings.x = [QDate(2020, 1, 1), QDate(2020, 2, 1), QDate(2020, 3, 1)]
        settings.y = [4, 5, 6]
        factory = PlotFactory(settings)

        # Build the dictionary from teh figure
        plot_dict = factory.build_plot_dict()

        # get the x and y fields as list
        for items in plot_dict['data']:
            # converts the QDate into strings
            x = [str(i.toPyDate()) for i in items['x']]
            y = items['y']

        self.assertEqual(x, ["2020-01-01", "2020-02-01", "2020-03-01"])
        self.assertEqual(y, [4, 5, 6])

        settings.x = [
            QDateTime(2020, 1, 1, 11, 21),
            QDateTime(2020, 2, 1, 0, 15),
            QDateTime(2020, 3, 1, 17, 23, 11)
        ]
        settings.y = [4, 5, 6]
        factory = PlotFactory(settings)

        # Build the dictionary from teh figure
        plot_dict = factory.build_plot_dict()

        # get the x and y fields as list
        for items in plot_dict['data']:
            # converts the QDate into strings
            x = [str(i.toString(Qt.ISODate)) for i in items['x']]
            y = items['y']

        self.assertEqual(x, [
            "2020-01-01T11:21:00", "2020-02-01T00:15:00", "2020-03-01T17:23:11"
        ])
        self.assertEqual(y, [4, 5, 6])
Ejemplo n.º 13
0
    def test_changed_feature_values_dynamic(self):
        """
        Test that factory proactively updates when a layer changes
        """

        layer_path = os.path.join(os.path.dirname(__file__), 'test_layer.shp')

        vl1 = QgsVectorLayer(layer_path, 'test_layer', 'ogr')
        vl1.setSubsetString('id < 10')
        self.assertTrue(vl1.isValid())
        QgsProject.instance().addMapLayer(vl1)

        # not using selected features
        settings = PlotSettings('scatter')
        settings.source_layer_id = vl1.id()

        settings.properties['x_name'] = 'so4'
        settings.properties['y_name'] = 'ca'
        factory = PlotFactory(settings)
        spy = QSignalSpy(factory.plot_built)
        self.assertEqual(len(spy), 0)
        self.assertEqual(factory.settings.x,
                         [98, 88, 267, 329, 319, 137, 350, 151, 203])
        self.assertEqual(factory.settings.y, [
            81.87, 22.26, 74.16, 35.05, 46.64, 126.73, 116.44, 108.25, 110.45
        ])

        self.assertTrue(vl1.startEditing())
        vl1.changeAttributeValue(1, vl1.fields().lookupField('so4'), 500)
        self.assertEqual(len(spy), 1)
        self.assertEqual(factory.settings.x,
                         [98, 500, 267, 329, 319, 137, 350, 151, 203])
        self.assertEqual(factory.settings.y, [
            81.87, 22.26, 74.16, 35.05, 46.64, 126.73, 116.44, 108.25, 110.45
        ])

        vl1.rollBack()
Ejemplo n.º 14
0
    def test_dates(self):  # pylint: disable=too-many-statements
        """
        Test handling of dates
        """
        # default plot settings
        settings = PlotSettings('scatter')

        # no source layer, fixed values must be used
        settings.source_layer_id = ''
        settings.x = [QDate(2020, 1, 1), QDate(2020, 2, 1), QDate(2020, 3, 1)]
        settings.y = [4, 5, 6]
        factory = PlotFactory(settings)

        # Build the HTML/JavaScript for the plot
        plot_html = factory.build_html({})

        # Find the plot specification in the HTML
        match = re.search(r'\[.*\]', plot_html)
        plot_dictionary = json.loads(match.group(0))[0]

        self.assertEqual(plot_dictionary['x'],
                         ["2020-01-01", "2020-02-01", "2020-03-01"])
        self.assertEqual(plot_dictionary['y'], [4, 5, 6])

        settings.x = [
            QDateTime(2020, 1, 1, 11, 21),
            QDateTime(2020, 2, 1, 0, 15),
            QDateTime(2020, 3, 1, 17, 23, 11)
        ]
        settings.y = [4, 5, 6]
        factory = PlotFactory(settings)

        # Build the HTML/JavaScript for the plot
        plot_html = factory.build_html({})

        # Find the plot specification in the HTML
        match = re.search(r'\[.*\]', plot_html)
        plot_dictionary = json.loads(match.group(0))[0]

        self.assertEqual(plot_dictionary['x'], [
            "2020-01-01T11:21:00", "2020-02-01T00:15:00", "2020-03-01T17:23:11"
        ])
        self.assertEqual(plot_dictionary['y'], [4, 5, 6])
Ejemplo n.º 15
0
 def create_plot(self):
     factory = PlotFactory(self.plot_settings)
     config = {'displayModeBar': False, 'staticPlot': True}
     return factory.build_html(config)
Ejemplo n.º 16
0
    def test_values(self):  # pylint: disable=too-many-statements
        """
        Test value collection
        """

        layer_path = os.path.join(os.path.dirname(__file__), 'test_layer.shp')

        vl1 = QgsVectorLayer(layer_path, 'test_layer', 'ogr')
        vl1.setSubsetString('id < 10')
        self.assertTrue(vl1.isValid())
        QgsProject.instance().addMapLayer(vl1)

        # default plot settings
        settings = PlotSettings('scatter')

        # no source layer, fixed values must be used
        settings.source_layer_id = ''
        settings.x = [1, 2, 3]
        settings.y = [4, 5, 6]
        settings.z = [7, 8, 9]

        factory = PlotFactory(settings)
        self.assertEqual(factory.settings.x, [1, 2, 3])
        self.assertEqual(factory.settings.y, [4, 5, 6])
        self.assertEqual(factory.settings.z, [7, 8, 9])
        self.assertEqual(factory.settings.additional_hover_text, [])

        # use source layer
        settings.source_layer_id = vl1.id()

        # no source set => no values
        factory = PlotFactory(settings)
        self.assertEqual(factory.settings.x, [])
        self.assertEqual(factory.settings.y, [])
        self.assertEqual(factory.settings.z, [])
        self.assertEqual(factory.settings.additional_hover_text, [])

        settings.properties['x_name'] = 'so4'
        settings.properties['y_name'] = 'ca'
        factory = PlotFactory(settings)
        self.assertEqual(factory.settings.x,
                         [98, 88, 267, 329, 319, 137, 350, 151, 203])
        self.assertEqual(factory.settings.y, [
            81.87, 22.26, 74.16, 35.05, 46.64, 126.73, 116.44, 108.25, 110.45
        ])
        self.assertEqual(factory.settings.z, [])
        self.assertEqual(factory.settings.additional_hover_text, [])

        # with z
        settings.properties['z_name'] = 'mg'
        factory = PlotFactory(settings)
        self.assertEqual(factory.settings.x,
                         [98, 88, 267, 329, 319, 137, 350, 151, 203])
        self.assertEqual(factory.settings.y, [
            81.87, 22.26, 74.16, 35.05, 46.64, 126.73, 116.44, 108.25, 110.45
        ])
        self.assertEqual(
            factory.settings.z,
            [72.31, 86.03, 85.26, 81.11, 131.59, 95.36, 112.88, 80.55, 78.34])
        self.assertEqual(factory.settings.additional_hover_text, [])

        # with expressions
        settings.properties['x_name'] = '"so4"/10'
        settings.properties[
            'y_name'] = 'case when "profm" >-16 then "ca" else "mg" end'
        settings.properties['z_name'] = 'case when $x < 10.5 then 1 else 0 end'
        factory = PlotFactory(settings)
        self.assertEqual(factory.settings.x,
                         [9.8, 8.8, 26.7, 32.9, 31.9, 13.7, 35.0, 15.1, 20.3])
        self.assertEqual(
            factory.settings.y,
            [81.87, 86.03, 85.26, 35.05, 131.59, 95.36, 112.88, 108.25, 78.34])
        self.assertEqual(factory.settings.z, [0, 1, 0, 0, 0, 0, 0, 1, 1])
        self.assertEqual(factory.settings.additional_hover_text, [])

        # with some nulls
        settings.properties['x_name'] = '"so4"/10'
        settings.properties[
            'y_name'] = 'case when "profm" >-16 then "ca" else "mg" end'
        settings.properties[
            'z_name'] = 'case when $x < 10.5 then NULL else 1 end'
        factory = PlotFactory(settings)
        self.assertEqual(factory.settings.x,
                         [9.8, 26.7, 32.9, 31.9, 13.7, 35.0])
        self.assertEqual(factory.settings.y,
                         [81.87, 85.26, 35.05, 131.59, 95.36, 112.88])
        self.assertEqual(factory.settings.z, [1, 1, 1, 1, 1, 1])
        self.assertEqual(factory.settings.additional_hover_text, [])

        # with additional values
        settings.layout['additional_info_expression'] = 'id'
        factory = PlotFactory(settings)
        self.assertEqual(factory.settings.x,
                         [9.8, 26.7, 32.9, 31.9, 13.7, 35.0])
        self.assertEqual(factory.settings.y,
                         [81.87, 85.26, 35.05, 131.59, 95.36, 112.88])
        self.assertEqual(factory.settings.z, [1, 1, 1, 1, 1, 1])
        self.assertEqual(factory.settings.additional_hover_text,
                         [9, 7, 6, 5, 4, 3])
Ejemplo n.º 17
0
    def processAlgorithm(self, parameters, context, feedback):
        """
        :param parameters:
        :param context:
        """

        layer = self.parameterAsSource(parameters, self.INPUT, context)
        fields = layer.fields()

        xfieldname = self.parameterAsString(parameters, self.XFIELD, context)
        yfieldname = self.parameterAsString(parameters, self.YFIELD, context)

        outputHtmlFile = self.parameterAsFileOutput(parameters,
                                                    self.OUTPUT_HTML_FILE,
                                                    context)
        outputJsonFile = self.parameterAsFileOutput(parameters,
                                                    self.OUTPUT_JSON_FILE,
                                                    context)

        plot_type = 'bar'
        plot_type_input = self.parameterAsInt(parameters, self.PLOT_TYPE,
                                              context)
        plot_type = self.PLOT_TYPE_OPTIONS[plot_type_input]

        plot_title = self.parameterAsString(parameters, self.PLOT_TITLE,
                                            context)

        in_color_input = self.parameterAsInt(parameters, self.IN_COLOR,
                                             context)
        in_color_hex = self.IN_COLOR_OPTIONS[in_color_input]
        in_color_html = self.parameterAsString(parameters, self.IN_COLOR_HTML,
                                               context)

        # Some controls
        msg = []
        if plot_type in self.X_MANDATORY and not xfieldname:
            msg.append(self.tr("The chosen plot type needs a X field !"))
        if plot_type in self.Y_MANDATORY and not yfieldname:
            msg.append(self.tr("The chosen plot type needs a Y field !"))
        if msg:
            feedback.reportError(' '.join(msg))
            raise QgsProcessingException(msg)

        # Build needed dictionary
        settings = PlotSettings(plot_type)
        properties = {}

        # Add X dimension
        x_title = ''
        if xfieldname:
            # get field index for x
            idxX = layer.fields().lookupField(xfieldname)
            # get list of values for x
            x_var = [
                i[xfieldname]
                for i in layer.getFeatures(QgsFeatureRequest().setFlags(
                    QgsFeatureRequest.NoGeometry).setSubsetOfAttributes([idxX
                                                                         ]))
            ]
            fieldTypeX = fields[idxX].type()
            x_title = fields[idxX].alias() or xfieldname
            properties.x = x_var

        # Add Y dimension
        y_title = ''
        if yfieldname:
            # get field index for y
            idxY = layer.fields().lookupField(yfieldname)
            # get list of values for y
            y_var = [
                i[yfieldname]
                for i in layer.getFeatures(QgsFeatureRequest().setFlags(
                    QgsFeatureRequest.NoGeometry).setSubsetOfAttributes([idxY
                                                                         ]))
            ]
            y_title = fields[idxY].alias() or yfieldname
            properties.y = y_var

        # Draw only markers for scatter plot
        if plot_type in ['scatter', 'polar']:
            properties['marker'] = 'markers'

        # Colours
        properties['in_color'] = in_color_html or in_color_hex or 'DodgerBlue'

        # Add layout
        layout = {'title': plot_title or layer.sourceName()}
        if plot_type in self.X_MANDATORY:
            layout['x_title'] = x_title
        if plot_type in self.Y_MANDATORY:
            layout['y_title'] = y_title

        settings = PlotSettings(plot_type,
                                properties=properties,
                                layout=layout)

        # Create plot instance
        factory = PlotFactory(settings)

        # Prepare results
        results = {self.OUTPUT_HTML_FILE: None, self.OUTPUT_JSON_FILE: None}

        # Save plot as HTML
        if outputHtmlFile:
            standalone_plot_path = factory.build_figure()
            if os.path.isfile(standalone_plot_path):
                # html file output
                copyfile(standalone_plot_path, outputHtmlFile)
                results[self.OUTPUT_HTML_FILE] = outputHtmlFile

        # Save plot as JSON
        if outputJsonFile:
            ojson = {'data': trace, 'layout': plot_layout}
            with codecs.open(outputJsonFile, 'w', encoding='utf-8') as f:
                f.write(json.dumps(ojson))
                results[self.OUTPUT_JSON_FILE] = outputJsonFile

        return results
Ejemplo n.º 18
0
    def test_data_defined_layout_properties(self):  # pylint: disable=too-many-statements
        """
        Test data defined stroke color
        """
        layer_path = os.path.join(os.path.dirname(__file__), 'test_layer.shp')

        vl1 = QgsVectorLayer(layer_path, 'test_layer', 'ogr')
        vl1.setSubsetString('id < 10')
        self.assertTrue(vl1.isValid())
        QgsProject.instance().addMapLayer(vl1)

        settings = PlotSettings('scatter')
        settings.source_layer_id = vl1.id()
        settings.properties['x_name'] = 'so4'
        settings.properties['y_name'] = 'mg'
        settings.layout['title'] = 'title'
        settings.layout['legend_title'] = 'legend_title'
        settings.layout['x_title'] = 'x_title'
        settings.layout['y_title'] = 'y_title'
        settings.layout['z_title'] = 'z_title'
        settings.layout['x_min'] = 0
        settings.layout['x_max'] = 1
        settings.layout['y_min'] = 0
        settings.layout['y_max'] = 1

        factory = PlotFactory(settings)
        # should be empty, not using data defined size
        self.assertEqual(factory.settings.x,
                         [98, 88, 267, 329, 319, 137, 350, 151, 203])
        self.assertEqual(
            factory.settings.y,
            [72.31, 86.03, 85.26, 81.11, 131.59, 95.36, 112.88, 80.55, 78.34])
        self.assertEqual(factory.settings.data_defined_title, '')
        self.assertEqual(factory.settings.data_defined_legend_title, '')
        self.assertEqual(factory.settings.data_defined_x_title, '')
        self.assertEqual(factory.settings.data_defined_y_title, '')
        self.assertEqual(factory.settings.data_defined_z_title, '')
        self.assertEqual(factory.settings.data_defined_x_min, None)
        self.assertEqual(factory.settings.data_defined_x_max, None)
        self.assertEqual(factory.settings.data_defined_y_min, None)
        self.assertEqual(factory.settings.data_defined_y_max, None)

        class TestGenerator(QgsExpressionContextGenerator):  # pylint: disable=missing-docstring, too-few-public-methods
            def createExpressionContext(self) -> QgsExpressionContext:  # pylint: disable=missing-docstring, no-self-use
                context = QgsExpressionContext()
                scope = QgsExpressionContextScope()
                scope.setVariable('some_var', 10)
                context.appendScope(scope)
                context.appendScope(vl1.createExpressionContextScope())
                return context

        generator = TestGenerator()
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_TITLE,
            QgsProperty.fromExpression("concat('my', '_title_', @some_var)"))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_LEGEND_TITLE,
            QgsProperty.fromExpression("concat('my', '_legend_', @some_var)"))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_X_TITLE,
            QgsProperty.fromExpression("concat('my', '_x_axis_', @some_var)"))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_Y_TITLE,
            QgsProperty.fromExpression("concat('my', '_y_axis_', @some_var)"))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_Z_TITLE,
            QgsProperty.fromExpression("concat('my', '_z_axis_', @some_var)"))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_X_MIN,
            QgsProperty.fromExpression("-1*@some_var"))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_X_MAX,
            QgsProperty.fromExpression("+1*@some_var"))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_Y_MIN,
            QgsProperty.fromExpression("-1*@some_var"))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_Y_MAX,
            QgsProperty.fromExpression("+1*@some_var"))
        factory = PlotFactory(settings, context_generator=generator)
        self.assertEqual(factory.settings.x,
                         [98, 88, 267, 329, 319, 137, 350, 151, 203])
        self.assertEqual(
            factory.settings.y,
            [72.31, 86.03, 85.26, 81.11, 131.59, 95.36, 112.88, 80.55, 78.34])
        self.assertEqual(factory.settings.data_defined_title, 'my_title_10')
        self.assertEqual(factory.settings.data_defined_legend_title,
                         'my_legend_10')
        self.assertEqual(factory.settings.data_defined_x_title, 'my_x_axis_10')
        self.assertEqual(factory.settings.data_defined_y_title, 'my_y_axis_10')
        self.assertEqual(factory.settings.data_defined_z_title, 'my_z_axis_10')
        self.assertEqual(factory.settings.data_defined_x_min, -10)
        self.assertEqual(factory.settings.data_defined_x_max, 10)
        self.assertEqual(factory.settings.data_defined_y_min, -10)
        self.assertEqual(factory.settings.data_defined_y_max, 10)