コード例 #1
0
ファイル: dock.py プロジェクト: SebastienPeillet/DataPlotly
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle(self.tr('DataPlotly'))
        self.setObjectName('DataPlotlyDock')

        self.panel_stack = QgsPanelWidgetStack()
        self.setWidget(self.panel_stack)

        self.main_panel = DataPlotlyPanelWidget()
        self.panel_stack.setMainPanel(self.main_panel)
        self.main_panel.setDockMode(True)
コード例 #2
0
 def show_properties(self):
     """
     Shows the plot properties panel
     """
     self.panel = DataPlotlyPanelWidget(
         mode=DataPlotlyPanelWidget.MODE_LAYOUT)
     self.panel.set_settings(self.plot_item.plot_settings)
     # self.panel.set_settings(self.layoutItem().plot_settings)
     self.openPanel(self.panel)
     self.panel.widgetChanged.connect(self.update_item_settings)
     self.panel.panelAccepted.connect(self.set_item_settings)
コード例 #3
0
ファイル: dock.py プロジェクト: SebastienPeillet/DataPlotly
class DataPlotlyDock(QgsDockWidget):  # pylint: disable=too-few-public-methods
    """
    Plot settings dock widget
    """
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle(self.tr('DataPlotly'))
        self.setObjectName('DataPlotlyDock')

        self.panel_stack = QgsPanelWidgetStack()
        self.setWidget(self.panel_stack)

        self.main_panel = DataPlotlyPanelWidget()
        self.panel_stack.setMainPanel(self.main_panel)
        self.main_panel.setDockMode(True)
コード例 #4
0
    def show_properties(self):
        """
        Shows the plot properties panel
        """
        selected_plot_index = self.plot_list.currentRow()
        if selected_plot_index < 0:
            return

        self.panel = DataPlotlyPanelWidget(mode=DataPlotlyPanelWidget.MODE_LAYOUT, message_bar=self.message_bar)

        # not quite right -- we ideally want to also add the source layer scope into the context given by plot item,
        # but that causes a hard lock in the Python GIL (because PyQt doesn't release the GIL when creating the menu
        # for the property override buttons). Nothing much we can do about that here (or in QGIS,
        # it's a Python/PyQt limitation)
        self.panel.registerExpressionContextGenerator(self.plot_item)
        self.panel.set_print_layout(self.plot_item.layout())

        self.panel.linked_map_combo.blockSignals(True)
        self.panel.linked_map_combo.setItem(self.plot_item.linked_map)
        self.panel.linked_map_combo.blockSignals(False)

        self.panel.filter_by_map_check.toggled.connect(self.filter_by_map_toggled)
        self.panel.filter_by_atlas_check.toggled.connect(self.filter_by_atlas_toggled)
        self.panel.linked_map_combo.itemChanged.connect(self.linked_map_changed)

        self.panel.filter_by_map_check.blockSignals(True)
        self.panel.filter_by_map_check.setChecked(self.plot_item.filter_by_map)
        self.panel.filter_by_map_check.blockSignals(False)

        self.panel.filter_by_atlas_check.blockSignals(True)
        self.panel.filter_by_atlas_check.setChecked(self.plot_item.filter_by_atlas)
        self.panel.filter_by_atlas_check.blockSignals(False)

        self.panel.set_settings(self.plot_item.plot_settings[selected_plot_index])
        # self.panel.set_settings(self.layoutItem().plot_settings)
        self.openPanel(self.panel)
        self.panel.widgetChanged.connect(self.update_item_settings)
        self.panel.panelAccepted.connect(self.set_item_settings)
コード例 #5
0
    def test_get_settings(self):
        """
        Test retrieving settings from the dialog
        """
        dialog = DataPlotlyPanelWidget(None, override_iface=IFACE)
        settings = dialog.get_settings()
        # default should be scatter plot
        self.assertEqual(settings.plot_type, 'scatter')

        dialog.set_plot_type('violin')
        settings = dialog.get_settings()
        # default should be scatter plot
        self.assertEqual(settings.plot_type, 'violin')
コード例 #6
0
    def test_set_default_settings(self):
        """
        Test setting dialog to a newly constructed settings object
        """
        settings = PlotSettings()
        dialog = DataPlotlyPanelWidget(None, override_iface=IFACE)
        dialog.set_settings(settings)

        self.assertEqual(dialog.get_settings().plot_type, settings.plot_type)
        for k in settings.properties.keys():
            if k in ['x', 'y', 'z', 'additional_hover_text', 'featureIds', 'featureBox', 'custom',
                     'marker_size', 'hover_text', 'hover_label_text']:
                continue

            self.assertEqual(dialog.get_settings().properties[k], settings.properties[k])
        for k in settings.layout.keys():
            self.assertEqual(dialog.get_settings().layout[k], settings.layout[k])
コード例 #7
0
class PlotLayoutItemWidget(QgsLayoutItemBaseWidget):
    """
    Configuration widget for layout plot items
    """
    def __init__(self, parent, layout_object):
        super().__init__(parent, layout_object)
        self.plot_item = layout_object

        vl = QVBoxLayout()
        vl.setContentsMargins(0, 0, 0, 0)

        self.plot_properties_button = QPushButton(self.tr('Setup Plot'))
        vl.addWidget(self.plot_properties_button)
        self.plot_properties_button.clicked.connect(self.show_properties)

        self.panel = None
        self.setPanelTitle(self.tr('Plot Properties'))
        self.item_properties_widget = QgsLayoutItemPropertiesWidget(
            self, layout_object)
        vl.addWidget(self.item_properties_widget)
        self.setLayout(vl)

    def show_properties(self):
        """
        Shows the plot properties panel
        """
        self.panel = DataPlotlyPanelWidget(
            mode=DataPlotlyPanelWidget.MODE_LAYOUT)
        self.panel.set_settings(self.plot_item.plot_settings)
        # self.panel.set_settings(self.layoutItem().plot_settings)
        self.openPanel(self.panel)
        self.panel.widgetChanged.connect(self.update_item_settings)
        self.panel.panelAccepted.connect(self.set_item_settings)

    def update_item_settings(self):
        """
        Updates the plot item without dismissing the properties panel
        """
        if not self.panel:
            return

        self.plot_item.set_plot_settings(self.panel.get_settings())
        self.plot_item.update()

    def set_item_settings(self):
        """
        Updates the plot item based on the settings from the properties panel
        """
        if not self.panel:
            return

        self.plot_item.set_plot_settings(self.panel.get_settings())
        self.panel = None
        self.plot_item.update()

    def setNewItem(self, item):  # pylint: disable=missing-docstring
        if item.type() != ITEM_TYPE:
            return False

        self.plot_item = item
        self.item_properties_widget.setItem(item)

        if self.panel is not None:
            self.panel.set_settings(self.plot_item.plot_settings)

        return True
コード例 #8
0
class PlotLayoutItemWidget(QgsLayoutItemBaseWidget):
    """
    Configuration widget for layout plot items
    """
    def __init__(self, parent, layout_object):
        super().__init__(parent, layout_object)
        self.plot_item = layout_object
        self.message_bar = None

        vl = QVBoxLayout()
        vl.setContentsMargins(0, 0, 0, 0)

        self.plot_properties_button = QPushButton(self.tr('Setup Plot'))
        vl.addWidget(self.plot_properties_button)
        self.plot_properties_button.clicked.connect(self.show_properties)

        self.panel = None
        self.setPanelTitle(self.tr('Plot Properties'))
        self.item_properties_widget = QgsLayoutItemPropertiesWidget(
            self, layout_object)
        vl.addWidget(self.item_properties_widget)
        self.setLayout(vl)

    def show_properties(self):
        """
        Shows the plot properties panel
        """
        self.panel = DataPlotlyPanelWidget(
            mode=DataPlotlyPanelWidget.MODE_LAYOUT,
            message_bar=self.message_bar)
        self.panel.registerExpressionContextGenerator(self.plot_item)
        self.panel.set_print_layout(self.plot_item.layout())

        self.panel.linked_map_combo.blockSignals(True)
        self.panel.linked_map_combo.setItem(self.plot_item.linked_map)
        self.panel.linked_map_combo.blockSignals(False)

        self.panel.filter_by_map_check.toggled.connect(
            self.filter_by_map_toggled)
        self.panel.filter_by_atlas_check.toggled.connect(
            self.filter_by_atlas_toggled)
        self.panel.linked_map_combo.itemChanged.connect(
            self.linked_map_changed)

        self.panel.filter_by_map_check.blockSignals(True)
        self.panel.filter_by_map_check.setChecked(self.plot_item.filter_by_map)
        self.panel.filter_by_map_check.blockSignals(False)

        self.panel.filter_by_atlas_check.blockSignals(True)
        self.panel.filter_by_atlas_check.setChecked(
            self.plot_item.filter_by_atlas)
        self.panel.filter_by_atlas_check.blockSignals(False)

        self.panel.set_settings(self.plot_item.plot_settings)
        # self.panel.set_settings(self.layoutItem().plot_settings)
        self.openPanel(self.panel)
        self.panel.widgetChanged.connect(self.update_item_settings)
        self.panel.panelAccepted.connect(self.set_item_settings)

    def update_item_settings(self):
        """
        Updates the plot item without dismissing the properties panel
        """
        if not self.panel:
            return

        self.plot_item.set_plot_settings(self.panel.get_settings())
        self.plot_item.update()

    def set_item_settings(self):
        """
        Updates the plot item based on the settings from the properties panel
        """
        if not self.panel:
            return

        self.plot_item.set_plot_settings(self.panel.get_settings())
        self.panel = None
        self.plot_item.update()

    def filter_by_map_toggled(self, value):
        """
        Triggered when the filter by map option is toggled
        """
        self.plot_item.filter_by_map = bool(value)
        self.plot_item.update()

    def filter_by_atlas_toggled(self, value):
        """
        Triggered when the filter by atlas option is toggled
        """
        self.plot_item.filter_by_atlas = bool(value)
        self.plot_item.update()

    def linked_map_changed(self, linked_map):
        """
        Triggered when the linked map is changed
        """
        self.plot_item.set_linked_map(linked_map)
        self.plot_item.update()

    def setNewItem(self, item):  # pylint: disable=missing-docstring
        if item.type() != ITEM_TYPE:
            return False

        self.plot_item = item
        self.item_properties_widget.setItem(item)

        if self.panel is not None:
            self.panel.set_settings(self.plot_item.plot_settings)

            self.panel.filter_by_map_check.blockSignals(True)
            self.panel.filter_by_map_check.setChecked(item.filter_by_map)
            self.panel.filter_by_map_check.blockSignals(False)

            self.panel.filter_by_atlas_check.blockSignals(True)
            self.panel.filter_by_atlas_check.setChecked(item.filter_by_atlas)
            self.panel.filter_by_atlas_check.blockSignals(False)

            self.panel.linked_map_combo.blockSignals(True)
            self.panel.linked_map_combo.setItem(self.plot_item.linked_map)
            self.panel.linked_map_combo.blockSignals(False)

        return True

    def setDesignerInterface(self, iface):  # pylint: disable=missing-docstring
        super().setDesignerInterface(iface)
        self.message_bar = iface.messageBar()
        if self.panel:
            self.panel.message_bar = self.message_bar
コード例 #9
0
    def test_settings_round_trip(self):  # pylint: disable=too-many-statements
        """
        Test setting and retrieving settings results in identical results
        """
        layer_path = os.path.join(os.path.dirname(__file__),
                                  'test_layer.geojson')

        vl1 = QgsVectorLayer(layer_path, 'test_layer', 'ogr')
        vl2 = QgsVectorLayer(layer_path, 'test_layer1', 'ogr')
        vl3 = QgsVectorLayer(layer_path, 'test_layer2', 'ogr')
        QgsProject.instance().addMapLayers([vl1, vl2, vl3])

        dialog = DataPlotlyPanelWidget(None, override_iface=IFACE)
        settings = dialog.get_settings()
        # default should be scatter plot
        self.assertEqual(settings.plot_type, 'scatter')
        # print('dialog loaded')

        # customise settings
        settings.plot_type = 'bar'
        settings.properties['name'] = 'my legend title'
        settings.properties['hover_text'] = 'y'
        settings.properties['box_orientation'] = 'h'
        settings.properties['normalization'] = 'probability'
        settings.properties['box_stat'] = 'sd'
        settings.properties['box_outliers'] = 'suspectedoutliers'
        settings.properties['violin_side'] = 'negative'
        settings.properties['show_mean_line'] = True
        settings.properties['cumulative'] = True
        settings.properties['invert_hist'] = 'decreasing'
        settings.source_layer_id = vl3.id()
        settings.properties['x_name'] = 'so4'
        settings.properties['y_name'] = 'ca'
        settings.properties['z_name'] = 'mg'
        settings.properties['color_scale'] = 'Earth'
        settings.properties['violin_box'] = True
        settings.properties['layout_filter_by_map'] = True
        settings.properties['layout_filter_by_atlas'] = True

        # TODO: likely need to test other settings.properties values here!

        settings.layout['legend'] = False
        settings.layout['legend_orientation'] = 'h'
        settings.layout['title'] = 'my title'
        settings.layout['x_title'] = 'my x title'
        settings.layout['y_title'] = 'my y title'
        settings.layout['z_title'] = 'my z title'
        settings.layout['font_title_size'] = 10
        settings.layout['font_title_family'] = "Arial"
        settings.layout['font_title_color'] = "#000000"
        settings.layout['font_xlabel_size'] = 10
        settings.layout['font_xlabel_family'] = "Arial"
        settings.layout['font_xlabel_color'] = "#000000"
        settings.layout['font_xticks_size'] = 10
        settings.layout['font_xticks_family'] = "Arial"
        settings.layout['font_xticks_color'] = "#000000"
        settings.layout['font_ylabel_size'] = 10
        settings.layout['font_ylabel_family'] = "Arial"
        settings.layout['font_ylabel_color'] = "#000000"
        settings.layout['font_yticks_size'] = 10
        settings.layout['font_yticks_family'] = "Arial"
        settings.layout['font_yticks_color'] = "#000000"
        settings.layout['range_slider']['visible'] = True
        settings.layout['bar_mode'] = 'overlay'
        settings.layout['x_type'] = 'log'
        settings.layout['y_type'] = 'category'
        settings.layout['x_inv'] = 'reversed'
        settings.layout['y_inv'] = 'reversed'
        settings.layout['bargaps'] = 0.8
        settings.layout['additional_info_expression'] = '1+2'
        settings.layout['bins_check'] = True
        settings.layout['gridcolor'] = '#bdbfc0'

        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_FILTER,
            QgsProperty.fromExpression('"ap">50'))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_MARKER_SIZE,
            QgsProperty.fromExpression('5+64'))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_COLOR, QgsProperty.fromExpression("'red'"))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_STROKE_WIDTH,
            QgsProperty.fromExpression("12/2"))
        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*10"))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_X_MAX, QgsProperty.fromExpression("+1*10"))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_Y_MIN, QgsProperty.fromExpression("-1*10"))
        settings.data_defined_properties.setProperty(
            PlotSettings.PROPERTY_Y_MAX, QgsProperty.fromExpression("+1*10"))

        dialog2 = DataPlotlyPanelWidget(None, override_iface=IFACE)
        dialog2.set_settings(settings)

        # print('set settings')

        self.assertEqual(dialog2.get_settings().plot_type, settings.plot_type)
        for k in settings.properties.keys():
            # print(k)
            if k in [
                    'x', 'y', 'z', 'additional_hover_text', 'featureIds',
                    'featureBox', 'custom'
            ]:
                continue
            self.assertEqual(dialog2.get_settings().properties[k],
                             settings.properties[k])
        for k in settings.layout.keys():
            self.assertEqual(dialog2.get_settings().layout[k],
                             settings.layout[k])
        self.assertEqual(dialog2.get_settings().source_layer_id, vl3.id())
        self.assertEqual(
            dialog2.get_settings().data_defined_properties.property(
                PlotSettings.PROPERTY_FILTER),
            settings.data_defined_properties.property(
                PlotSettings.PROPERTY_FILTER))
        self.assertEqual(
            dialog2.get_settings().data_defined_properties.property(
                PlotSettings.PROPERTY_MARKER_SIZE),
            settings.data_defined_properties.property(
                PlotSettings.PROPERTY_MARKER_SIZE))
        self.assertEqual(
            dialog2.get_settings().data_defined_properties.property(
                PlotSettings.PROPERTY_COLOR),
            settings.data_defined_properties.property(
                PlotSettings.PROPERTY_COLOR))
        self.assertEqual(
            dialog2.get_settings().data_defined_properties.property(
                PlotSettings.PROPERTY_STROKE_WIDTH),
            settings.data_defined_properties.property(
                PlotSettings.PROPERTY_STROKE_WIDTH))
        self.assertEqual(
            dialog2.get_settings().data_defined_properties.property(
                PlotSettings.PROPERTY_X_MIN),
            settings.data_defined_properties.property(
                PlotSettings.PROPERTY_X_MIN))
        self.assertEqual(
            dialog2.get_settings().data_defined_properties.property(
                PlotSettings.PROPERTY_X_MAX),
            settings.data_defined_properties.property(
                PlotSettings.PROPERTY_X_MAX))
        self.assertEqual(
            dialog2.get_settings().data_defined_properties.property(
                PlotSettings.PROPERTY_Y_MIN),
            settings.data_defined_properties.property(
                PlotSettings.PROPERTY_Y_MIN))
        self.assertEqual(
            dialog2.get_settings().data_defined_properties.property(
                PlotSettings.PROPERTY_Y_MAX),
            settings.data_defined_properties.property(
                PlotSettings.PROPERTY_Y_MAX))
        self.assertEqual(
            dialog2.get_settings().data_defined_properties.property(
                PlotSettings.PROPERTY_TITLE),
            settings.data_defined_properties.property(
                PlotSettings.PROPERTY_TITLE))
        self.assertEqual(
            dialog2.get_settings().data_defined_properties.property(
                PlotSettings.PROPERTY_LEGEND_TITLE),
            settings.data_defined_properties.property(
                PlotSettings.PROPERTY_LEGEND_TITLE))
        self.assertEqual(
            dialog2.get_settings().data_defined_properties.property(
                PlotSettings.PROPERTY_X_TITLE),
            settings.data_defined_properties.property(
                PlotSettings.PROPERTY_X_TITLE))
        self.assertEqual(
            dialog2.get_settings().data_defined_properties.property(
                PlotSettings.PROPERTY_Y_TITLE),
            settings.data_defined_properties.property(
                PlotSettings.PROPERTY_Y_TITLE))
        self.assertEqual(
            dialog2.get_settings().data_defined_properties.property(
                PlotSettings.PROPERTY_Z_TITLE),
            settings.data_defined_properties.property(
                PlotSettings.PROPERTY_Z_TITLE))

        dialog2.deleteLater()
        del dialog2

        settings = dialog.get_settings()
        dialog.deleteLater()
        del dialog

        dialog3 = DataPlotlyPanelWidget(None, override_iface=IFACE)
        # print('dialog 2')
        dialog3.set_settings(settings)
        # print('set settings')

        self.assertEqual(dialog3.get_settings().plot_type, settings.plot_type)
        for k in settings.properties.keys():
            # print(k)
            self.assertEqual(dialog3.get_settings().properties[k],
                             settings.properties[k])
        self.assertEqual(dialog3.get_settings().properties,
                         settings.properties)
        for k in settings.layout.keys():
            # print(k)
            self.assertEqual(dialog3.get_settings().layout[k],
                             settings.layout[k])

        dialog3.deleteLater()
        del dialog3

        # print('done')
        QgsProject.instance().clear()
コード例 #10
0
    def test_read_write_project(self):
        """
        Test saving/restoring dialog state in project
        """
        # print('read write project test')
        p = QgsProject.instance()
        dialog = DataPlotlyPanelWidget(None, override_iface=IFACE)
        dialog.set_plot_type('violin')

        # first, disable saving to project
        dialog.read_from_project = False
        dialog.save_to_project = False

        path = os.path.join(tempfile.gettempdir(),
                            'test_dataplotly_project.qgs')
        layer_path = os.path.join(os.path.dirname(__file__),
                                  'test_layer.geojson')

        # create QgsVectorLayer from path and test validity
        vl = QgsVectorLayer(layer_path, 'test_layer', 'ogr')
        self.assertTrue(vl.isValid())

        # print(dialog.layer_combo.currentLayer())

        self.assertTrue(p.write(path))

        res = PlotSettings()

        # def read(doc):
        #    self.assertTrue(res.read_from_project(doc))
        #    self.assertEqual(res.plot_type, 'violin')
        #    self.read_triggered = True

        p.clear()
        for _ in range(100):
            QCoreApplication.processEvents()

        self.assertTrue(p.read(path))
        self.assertEqual(res.plot_type, 'scatter')

        # TODO - enable when dialog can restore properties and avoid this fragile test
        # # enable saving to project
        # dialog.save_to_project = True
        # dialog.read_from_project = True
        # self.assertTrue(p.write(path))
        # for _ in range(100):
        #     QCoreApplication.processEvents()

        # p.clear()

        # p.readProject.connect(read)
        # self.assertTrue(p.read(path))
        # for _ in range(100):
        #     QCoreApplication.processEvents()

        # self.assertTrue(self.read_triggered)

        # todo - test that dialog can restore properties, but requires the missing set_settings method
        dialog.x_combo.setExpression('"Ca"')
        dialog.layer_combo.setLayer(vl)

        dialog.x_combo.currentText()

        self.assertTrue(dialog.x_combo.expression(), '"Ca"')
コード例 #11
0
    def test_settings_round_trip_secondary(self):  # pylint: disable=too-many-statements
        """
        Test setting and retrieving settings results in identical results -- this secondary test allows for
        different values to be checked (e.g. True if the first test checks for False)
        """
        layer_path = os.path.join(os.path.dirname(__file__),
                                  'test_layer.geojson')

        vl1 = QgsVectorLayer(layer_path, 'test_layer', 'ogr')
        vl2 = QgsVectorLayer(layer_path, 'test_layer1', 'ogr')
        vl3 = QgsVectorLayer(layer_path, 'test_layer2', 'ogr')
        QgsProject.instance().addMapLayers([vl1, vl2, vl3])

        dialog = DataPlotlyPanelWidget(None, override_iface=IFACE)
        settings = dialog.get_settings()
        # default should be scatter plot
        self.assertEqual(settings.plot_type, 'scatter')
        # print('dialog loaded')

        # customise settings
        settings.plot_type = 'bar'
        settings.properties['violin_box'] = False

        dialog2 = DataPlotlyPanelWidget(None, override_iface=IFACE)
        dialog2.set_settings(settings)

        # print('set settings')

        self.assertEqual(dialog2.get_settings().plot_type, settings.plot_type)
        for k in settings.properties.keys():
            # print(k)
            if k in [
                    'x', 'y', 'z', 'additional_hover_text', 'featureIds',
                    'featureBox', 'custom'
            ]:
                continue
            self.assertEqual(dialog2.get_settings().properties[k],
                             settings.properties[k])
        for k in settings.layout.keys():
            self.assertEqual(dialog2.get_settings().layout[k],
                             settings.layout[k])

        dialog2.deleteLater()
        del dialog2

        settings = dialog.get_settings()
        dialog.deleteLater()
        del dialog

        dialog3 = DataPlotlyPanelWidget(None, override_iface=IFACE)
        # print('dialog 2')
        dialog3.set_settings(settings)
        # print('set settings')

        self.assertEqual(dialog3.get_settings().plot_type, settings.plot_type)
        for k in settings.properties.keys():
            # print(k)
            self.assertEqual(dialog3.get_settings().properties[k],
                             settings.properties[k])
        self.assertEqual(dialog3.get_settings().properties,
                         settings.properties)
        for k in settings.layout.keys():
            # print(k)
            self.assertEqual(dialog3.get_settings().layout[k],
                             settings.layout[k])

        dialog3.deleteLater()
        del dialog3

        # print('done')
        QgsProject.instance().clear()
コード例 #12
0
class PlotLayoutItemWidget(QgsLayoutItemBaseWidget):
    """
    Configuration widget for layout plot items
    """
    def __init__(self, parent, layout_object):
        super().__init__(parent, layout_object)
        self.plot_item = layout_object
        self.message_bar = None

        vl = QVBoxLayout()
        vl.setContentsMargins(0, 0, 0, 0)

        plot_tools_layout = QHBoxLayout()

        plot_add_button = QPushButton()
        plot_add_button.setIcon(GuiUtils.get_icon('symbologyAdd.svg'))
        plot_add_button.setToolTip('Add a new plot')
        plot_tools_layout.addWidget(plot_add_button)
        plot_add_button.clicked.connect(self.add_plot)

        plot_remove_button = QPushButton()
        plot_remove_button.setIcon(GuiUtils.get_icon('symbologyRemove.svg'))
        plot_remove_button.setToolTip('Remove selected plot')
        plot_tools_layout.addWidget(plot_remove_button)
        plot_remove_button.clicked.connect(self.remove_plot)

        plot_duplicate_button = QPushButton()
        plot_duplicate_button.setIcon(
            GuiUtils.get_icon('mActionDuplicateLayer.svg'))
        plot_duplicate_button.setToolTip('Duplicates the selected plot')
        plot_tools_layout.addWidget(plot_duplicate_button)
        plot_duplicate_button.clicked.connect(self.duplicate_plot)

        plot_move_up_button = QPushButton()
        plot_move_up_button.setIcon(GuiUtils.get_icon('mActionArrowUp.svg'))
        plot_move_up_button.setToolTip('Move selected plot up')
        plot_tools_layout.addWidget(plot_move_up_button)
        plot_move_up_button.clicked.connect(self.move_up_plot)

        plot_move_down_button = QPushButton()
        plot_move_down_button.setIcon(
            GuiUtils.get_icon('mActionArrowDown.svg'))
        plot_move_down_button.setToolTip('Move selected plot down')
        plot_tools_layout.addWidget(plot_move_down_button)
        plot_move_down_button.clicked.connect(self.move_down_plot)

        vl.addLayout(plot_tools_layout)

        self.plot_list = QListWidget()
        self.plot_list.setSelectionMode(QListWidget.SingleSelection)
        self.plot_list.doubleClicked.connect(self.show_properties)
        vl.addWidget(self.plot_list)
        self.populate_plot_list()

        plot_properties_button = QPushButton(self.tr('Setup Selected Plot'))
        vl.addWidget(plot_properties_button)
        plot_properties_button.clicked.connect(self.show_properties)

        self.panel = None
        self.setPanelTitle(self.tr('Plot Properties'))
        self.item_properties_widget = QgsLayoutItemPropertiesWidget(
            self, layout_object)
        vl.addWidget(self.item_properties_widget)
        self.setLayout(vl)

    def populate_plot_list(self):
        """
        Clears and re-populates the plot list widget. The currently selection is retained
        """
        selected_index = self.plot_list.currentRow()
        self.plot_list.clear()
        for setting in self.plot_item.plot_settings:
            plot_type = setting.plot_type if setting.plot_type is not None else '(not set)'
            legend_title = ('[' + setting.properties.get('name') + ']') \
                if setting.properties.get('name', '') != '' else ''
            self.plot_list.addItem(plot_type + ' ' + legend_title)

        # select index within range [0, len(plot_settings)-1]
        selected_index = max(
            0, min(len(self.plot_item.plot_settings) - 1, selected_index))
        self.plot_list.setCurrentRow(selected_index,
                                     QItemSelectionModel.SelectCurrent)

    def add_plot(self):
        """
         Adds a new plot and updates the plot list and the plot item
        """
        self.plot_item.add_plot()
        self.populate_plot_list()
        self.plot_item.refresh()

    def duplicate_plot(self):
        """
         Duplicates an existing plot and updates the plot list and the plot item
        """

        selected_plot_index = self.plot_list.currentRow()
        if selected_plot_index < 0:
            return

        self.plot_item.duplicate_plot(selected_plot_index)
        self.populate_plot_list()
        self.plot_item.refresh()

    def remove_plot(self):
        """
        Removes the selected plot and updates the plot list and the plot item
        """
        selected_index = self.plot_list.currentRow()
        if selected_index < 0:
            return

        self.plot_item.remove_plot(selected_index)
        self.populate_plot_list()
        self.plot_item.refresh()

    def move_up_plot(self):
        """
        Moves the selected plot up and updates the plot list and the plot item
        """
        selected_index = self.plot_list.currentRow()
        if selected_index <= 0:
            return

        item = self.plot_item.plot_settings.pop(selected_index)
        self.plot_item.plot_settings.insert(selected_index - 1, item)
        self.plot_list.setCurrentRow(selected_index - 1,
                                     QItemSelectionModel.SelectCurrent)
        self.populate_plot_list()
        self.plot_item.refresh()

    def move_down_plot(self):
        """
        Moves the selected plot down and updates the plot list and the plot item
        """
        selected_index = self.plot_list.currentRow()
        if selected_index >= len(self.plot_item.plot_settings) - 1:
            return

        item = self.plot_item.plot_settings.pop(selected_index)
        self.plot_item.plot_settings.insert(selected_index + 1, item)
        self.plot_list.setCurrentRow(selected_index + 1,
                                     QItemSelectionModel.SelectCurrent)
        self.populate_plot_list()
        self.plot_item.refresh()

    def show_properties(self):
        """
        Shows the plot properties panel
        """
        selected_plot_index = self.plot_list.currentRow()
        if selected_plot_index < 0:
            return

        self.panel = DataPlotlyPanelWidget(
            mode=DataPlotlyPanelWidget.MODE_LAYOUT,
            message_bar=self.message_bar)

        # not quite right -- we ideally want to also add the source layer scope into the context given by plot item,
        # but that causes a hard lock in the Python GIL (because PyQt doesn't release the GIL when creating the menu
        # for the property override buttons). Nothing much we can do about that here (or in QGIS,
        # it's a Python/PyQt limitation)
        self.panel.registerExpressionContextGenerator(self.plot_item)
        self.panel.set_print_layout(self.plot_item.layout())

        self.panel.linked_map_combo.blockSignals(True)
        self.panel.linked_map_combo.setItem(self.plot_item.linked_map)
        self.panel.linked_map_combo.blockSignals(False)

        self.panel.linked_map_combo.itemChanged.connect(
            self.linked_map_changed)

        self.panel.set_settings(
            self.plot_item.plot_settings[selected_plot_index])
        # self.panel.set_settings(self.layoutItem().plot_settings)
        self.openPanel(self.panel)
        self.panel.widgetChanged.connect(self.update_item_settings)
        self.panel.panelAccepted.connect(self.set_item_settings)

    def update_item_settings(self):
        """
        Updates the plot item without dismissing the properties panel
        """
        if not self.panel:
            return

        self.plot_item.set_plot_settings(self.plot_list.currentRow(),
                                         self.panel.get_settings())
        self.populate_plot_list()
        self.plot_item.update()

    def set_item_settings(self):
        """
        Updates the plot item based on the settings from the properties panel
        """
        if not self.panel:
            return

        self.plot_item.set_plot_settings(self.plot_list.currentRow(),
                                         self.panel.get_settings())
        self.populate_plot_list()
        self.panel = None
        self.plot_item.update()

    def linked_map_changed(self, linked_map):
        """
        Triggered when the linked map is changed
        """
        self.plot_item.set_linked_map(linked_map)
        self.plot_item.update()

    def setNewItem(self, item):  # pylint: disable=missing-docstring
        if item.type() != ITEM_TYPE:
            return False

        self.plot_item = item
        self.item_properties_widget.setItem(item)
        self.populate_plot_list()

        if self.panel is not None:
            self.panel.set_settings(self.plot_item.plot_settings[0])

            self.panel.linked_map_combo.blockSignals(True)
            self.panel.linked_map_combo.setItem(self.plot_item.linked_map)
            self.panel.linked_map_combo.blockSignals(False)

        return True

    def setDesignerInterface(self, iface):  # pylint: disable=missing-docstring
        super().setDesignerInterface(iface)
        self.message_bar = iface.messageBar()
        if self.panel:
            self.panel.message_bar = self.message_bar
コード例 #13
0
    def test_settings_round_trip(self):  # pylint: disable=too-many-statements
        """
        Test setting and retrieving settings results in identical results
        """
        layer_path = os.path.join(
            os.path.dirname(__file__), 'test_layer.geojson')

        vl1 = QgsVectorLayer(layer_path, 'test_layer', 'ogr')
        vl2 = QgsVectorLayer(layer_path, 'test_layer1', 'ogr')
        vl3 = QgsVectorLayer(layer_path, 'test_layer2', 'ogr')
        QgsProject.instance().addMapLayers([vl1, vl2, vl3])

        dialog = DataPlotlyPanelWidget(None, iface=IFACE)
        settings = dialog.get_settings()
        # default should be scatter plot
        self.assertEqual(settings.plot_type, 'scatter')

        # customise settings
        settings.plot_type = 'violin'
        settings.properties['name'] = 'my legend title'
        settings.properties['hover_text'] = 'y'
        settings.properties['box_orientation'] = 'h'
        settings.properties['normalization'] = 'probability'
        settings.properties['box_stat'] = 'sd'
        settings.properties['box_outliers'] = 'suspectedoutliers'
        settings.properties['violin_side'] = 'negative'
        settings.properties['show_mean_line'] = True
        settings.properties['cumulative'] = True
        settings.properties['invert_hist'] = 'decreasing'
        settings.source_layer_id = vl3.id()
        settings.properties['x_name'] = 'so4'
        settings.properties['y_name'] = 'ca'
        settings.properties['z_name'] = 'mg'
        settings.properties['in_color_value'] = '100,150,180,50'
        settings.properties['in_color_property'] = QgsProperty.fromExpression('5+6').toVariant()
        settings.properties['size_property'] = QgsProperty.fromExpression('5+64').toVariant()
        settings.properties['color_scale'] = 'Earth'
        settings.properties['colorscale_in'] = 'Earth'

        # TODO: likely need to test other settings.properties values here!

        settings.layout['legend'] = False
        settings.layout['legend_orientation'] = 'h'
        settings.layout['title'] = 'my title'
        settings.layout['x_title'] = 'my x title'
        settings.layout['y_title'] = 'my y title'
        settings.layout['z_title'] = 'my z title'
        settings.layout['range_slider']['visible'] = True
        settings.layout['bar_mode'] = 'overlay'
        settings.layout['x_type'] = 'log'
        settings.layout['y_type'] = 'category'
        settings.layout['x_inv'] = 'reversed'
        settings.layout['y_inv'] = 'reversed'
        settings.layout['bargaps'] = 0.8
        settings.layout['additional_info_expression'] = '1+2'
        settings.layout['bins_check'] = True

        dialog2 = DataPlotlyPanelWidget(None, iface=IFACE)
        dialog2.set_settings(settings)

        self.assertEqual(dialog2.get_settings().plot_type, settings.plot_type)
        for k in settings.properties.keys():
            if k in ['x', 'y', 'z', 'additional_hover_text', 'featureIds', 'featureBox', 'custom', 'in_color',
                     'marker_size']:
                continue

            print(k)
            self.assertEqual(dialog2.get_settings().properties[k], settings.properties[k])
        for k in settings.layout.keys():
            print(k)
            self.assertEqual(dialog2.get_settings().layout[k], settings.layout[k])
        self.assertEqual(dialog2.get_settings().source_layer_id, vl3.id())

        settings = dialog.get_settings()
        dialog3 = DataPlotlyPanelWidget(None, iface=IFACE)
        dialog3.set_settings(settings)

        self.assertEqual(dialog3.get_settings().plot_type, settings.plot_type)
        for k in settings.properties.keys():
            print(k)
            self.assertEqual(dialog3.get_settings().properties[k], settings.properties[k])
        self.assertEqual(dialog3.get_settings().properties, settings.properties)
        for k in settings.layout.keys():
            print(k)
            self.assertEqual(dialog3.get_settings().layout[k], settings.layout[k])

        QgsProject.instance().clear()