diff --git a/DataPlotly/core/plot_factory.py b/DataPlotly/core/plot_factory.py index 759d2d34..604277ad 100644 --- a/DataPlotly/core/plot_factory.py +++ b/DataPlotly/core/plot_factory.py @@ -163,6 +163,14 @@ def add_source_field_or_expression(field_or_expression): z_expression, z_needs_geom, z_attrs = add_source_field_or_expression(self.settings.properties['z_name']) if \ self.settings.properties[ 'z_name'] else (None, False, set()) + y_label_expression, _, y_label_attrs = add_source_field_or_expression(self.settings.properties['y_combo_radar_label']) if \ + self.settings.properties[ + 'y_combo_radar_label'] else (None, False, set()) + y_fields_expression = QgsExpression("array(" + ", ".join([f'"{field_name}"' + for field_name in self.settings.properties['y_fields_combo'].split(", ") + ]) + ")") if \ + self.settings.properties[ + 'y_fields_combo'] else None additional_info_expression, additional_needs_geom, additional_attrs = add_source_field_or_expression( self.settings.layout['additional_info_expression']) if self.settings.layout[ 'additional_info_expression'] else (None, False, set()) @@ -171,6 +179,7 @@ def add_source_field_or_expression(field_or_expression): x_attrs, y_attrs, z_attrs, + y_label_attrs, additional_attrs) request = QgsFeatureRequest() @@ -230,6 +239,9 @@ def add_source_field_or_expression(field_or_expression): colors = [] stroke_colors = [] stroke_widths = [] + y_radar_labels = [] + y_radar_values = [] + for f in it: if visible_geom_engine and not visible_geom_engine.intersects(f.geometry().constGet()): continue @@ -267,6 +279,22 @@ def add_source_field_or_expression(field_or_expression): if z == NULL or z is None: continue + y_radar_label = None + if y_label_expression: + y_radar_label = y_label_expression.evaluate(context) + if y_radar_label == NULL or y_radar_label is None: + continue + elif self.settings.properties['y_combo_radar_label']: + y_radar_label = f[self.settings.properties['y_combo_radar_label']] + if y_radar_label == NULL or y_radar_label is None: + continue + + y_radar_value = None + if y_fields_expression: + y_radar_value = y_fields_expression.evaluate(context) + if y_radar_value == NULL or y_radar_value is None: + continue + if additional_info_expression: additional_hover_text.append( additional_info_expression.evaluate(context)) @@ -280,6 +308,10 @@ def add_source_field_or_expression(field_or_expression): yy.append(y) if z is not None: zz.append(z) + if y_radar_label is not None: + y_radar_labels.append(y_radar_label) + if y_radar_value is not None: + y_radar_values.append(y_radar_value) if self.settings.data_defined_properties.isActive(PlotSettings.PROPERTY_MARKER_SIZE): default_value = self.settings.properties['marker_size'] @@ -338,6 +370,8 @@ def add_source_field_or_expression(field_or_expression): self.settings.x = xx self.settings.y = yy self.settings.z = zz + self.settings.y_radar_labels = y_radar_labels + self.settings.y_radar_values = y_radar_values if marker_sizes: self.settings.data_defined_marker_sizes = marker_sizes if colors: @@ -699,7 +733,6 @@ def build_figure(self) -> str: with open(self.plot_path, "w", encoding="utf8") as f: f.write(self.build_html(config)) - return self.plot_path def build_figures(self, plot_type, ptrace, config=None) -> str: @@ -740,7 +773,6 @@ def build_figures(self, plot_type, ptrace, config=None) -> str: self.layout = PlotFactory.PLOT_TYPES[plot_type].create_layout( self.settings) figures = go.Figure(data=ptrace, layout=self.layout) - else: figures = go.Figure(data=ptrace, layout=self.layout) diff --git a/DataPlotly/core/plot_settings.py b/DataPlotly/core/plot_settings.py index 420ccee7..b78e643d 100644 --- a/DataPlotly/core/plot_settings.py +++ b/DataPlotly/core/plot_settings.py @@ -101,6 +101,8 @@ def __init__(self, plot_type: str = 'scatter', properties: dict = None, layout: 'x_name': '', 'y_name': '', 'z_name': '', + 'y_combo_radar_label': '', + 'y_fields_combo': '', 'in_color': '#8ebad9', 'out_color': '#1f77b4', 'marker_width': 1, @@ -135,7 +137,12 @@ def __init__(self, plot_type: str = 'scatter', properties: dict = None, layout: 'show_mean_line': False, 'layout_filter_by_map': False, 'layout_filter_by_atlas': False, - 'pie_hole': 0 + 'pie_hole': 0, + 'fill': False, + 'line_combo_threshold': 'Dot Line', + 'line_dash_threshold': 'dash', + 'threshold_value': 1, + 'threshold': False } # layout nested dictionary @@ -205,6 +212,8 @@ def __init__(self, plot_type: str = 'scatter', properties: dict = None, layout: self.x = [] self.y = [] self.z = [] + self.y_radar_labels = [] + self.y_radar_values = [] self.feature_ids = [] self.additional_hover_text = [] self.data_defined_marker_sizes = [] diff --git a/DataPlotly/core/plot_types/__init__.py b/DataPlotly/core/plot_types/__init__.py index 3f033e43..418cc9be 100644 --- a/DataPlotly/core/plot_types/__init__.py +++ b/DataPlotly/core/plot_types/__init__.py @@ -14,6 +14,7 @@ from .histogram import HistogramFactory from .pie import PieChartFactory from .polar import PolarChartFactory +from .radar import RadarChartFactory from .scatter import ScatterPlotFactory from .ternary import TernaryFactory from .violin import ViolinFactory diff --git a/DataPlotly/core/plot_types/icons/radar.svg b/DataPlotly/core/plot_types/icons/radar.svg new file mode 100644 index 00000000..6261c28a --- /dev/null +++ b/DataPlotly/core/plot_types/icons/radar.svg @@ -0,0 +1,1770 @@ + + + +image/svg+xml diff --git a/DataPlotly/core/plot_types/radar.py b/DataPlotly/core/plot_types/radar.py new file mode 100644 index 00000000..299257ad --- /dev/null +++ b/DataPlotly/core/plot_types/radar.py @@ -0,0 +1,109 @@ +""" +Radar chart factory + +.. note:: This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. +""" + +import os +from plotly import graph_objs +from qgis.PyQt.QtCore import QCoreApplication +from qgis.PyQt.QtGui import QIcon +from DataPlotly.core.plot_types.plot_type import PlotType +import plotly.colors as pc + +import numpy as np +class RadarChartFactory(PlotType): + """ + Factory for radar charts + """ + + @staticmethod + def type_name(): + return 'radar' + + @staticmethod + def name(): + return PlotType.tr('Radar Plot') + + @staticmethod + def icon(): + return QIcon(os.path.join(os.path.dirname(__file__), 'icons/radar.svg')) + + @staticmethod + def create_trace(settings): + + if len(settings.y_radar_values) == 0: + return [] + + x = settings.properties["y_fields_combo"].split(", ") + + # Sample colors from the color scale based on the length of settings.y_radar_values + colors_list = pc.sample_colorscale(settings.properties['color_scale'], np.linspace(0, 1, len(settings.y_radar_values[0]))) + # List repeating the line type for each element in settings.y_radar_values + line_type_list = [settings.properties['line_dash']] * len(settings.y_radar_values) + + # Add a black color and a threshold line to the data + if settings.properties['threshold']: + colors_list.append('#000000') + settings.y_radar_values.append([settings.properties['threshold_value']] * len(settings.y_radar_values[0])) + settings.y_radar_labels.append(QCoreApplication.translate('DataPlotly', 'threshold')) + line_type_list.append(settings.properties['line_dash_threshold']) + + radar_plot_list = [] + for (y, name, colors_list, line_type_list) in zip(settings.y_radar_values, settings.y_radar_labels, colors_list, line_type_list): + # If the marker type includes lines, close the plot by repeating the first (x, y) point + if settings.properties['marker'] in ('lines', 'lines+markers'): + x.append(x[0]) + y.append(y[0]) + + radar_plot_list.append(graph_objs.Scatterpolar( + r=y, + theta=x, + mode=settings.properties['marker'], + name=name, + marker={ + "color": colors_list, + "size": settings.data_defined_marker_sizes if settings.data_defined_marker_sizes else settings.properties['marker_size'], + "symbol": settings.properties['marker_symbol'], + "line": { + "color": settings.properties['out_color'], + "width": settings.properties['marker_width'] + } + }, + line={ + "color": colors_list, + "width": settings.data_defined_stroke_widths if settings.data_defined_stroke_widths else settings.properties['marker_width'], + "dash": line_type_list + + }, + opacity=settings.properties['opacity'], + fill="toself" if settings.properties['fill'] else None + )) + + return radar_plot_list + + @staticmethod + def create_layout(settings): + layout = super(RadarChartFactory, RadarChartFactory).create_layout(settings) + + layout['polar'] = settings.layout['polar'] + layout['polar'].update({ + 'radialaxis': { + 'tickfont':{ + "size": settings.layout.get('font_xticks_size',30), + "color": settings.layout.get('font_xticks_color',"#00000"), + "family": settings.layout.get('font_xticks_family', "Arial"), + } + }, + 'angularaxis':{ + 'tickfont':{ + "size": settings.layout.get('font_ylabel_size',30), + "color": settings.layout.get('font_ylabel_color',"#00000"), + "family": settings.layout.get('font_ylabel_family', "Arial") + } + } + }) + return layout diff --git a/DataPlotly/gui/plot_settings_widget.py b/DataPlotly/gui/plot_settings_widget.py index 9ec9ec20..5d57f1f7 100644 --- a/DataPlotly/gui/plot_settings_widget.py +++ b/DataPlotly/gui/plot_settings_widget.py @@ -44,7 +44,8 @@ from qgis.PyQt.QtCore import ( QUrl, pyqtSignal, - QDir + QDir, + Qt ) from qgis.PyQt.QtWebKit import QWebSettings from qgis.PyQt.QtWebKitWidgets import ( @@ -79,7 +80,6 @@ WIDGET, _ = uic.loadUiType( GuiUtils.get_ui_file_path('dataplotly_dockwidget_base.ui')) - class DataPlotlyPanelWidget(QgsPanelWidget, WIDGET): # pylint: disable=too-many-lines,too-many-instance-attributes,too-many-public-methods """ Main configuration panel widget for plot settings @@ -182,7 +182,6 @@ def __init__(self, mode=MODE_CANVAS, parent=None, override_iface=None, message_b for clazz in type_classes: self.plot_combo.addItem( clazz.icon(), clazz.name(), clazz.type_name()) - # default to scatter plots self.set_plot_type('scatter') @@ -194,7 +193,6 @@ def __init__(self, mode=MODE_CANVAS, parent=None, override_iface=None, message_b # widgets self.refreshWidgets() self.refreshWidgets2() - self.refreshWidgets3() self.plot_combo.currentIndexChanged.connect(self.refreshWidgets) self.plot_combo.currentIndexChanged.connect(self.helpPage) self.subcombo.currentIndexChanged.connect(self.refreshWidgets2) @@ -493,11 +491,15 @@ def selected_layer_changed(self, layer): """ Trigger actions after selected layer changes """ + self.y_fields_combo.clear() self.x_combo.setLayer(layer) self.y_combo.setLayer(layer) + self.y_combo_radar_label.setLayer(layer) self.z_combo.setLayer(layer) self.additional_info_combo.setLayer(layer) + if layer is not None : + self.y_fields_combo.addItems([field.name() for field in layer.fields()]) buttons = self.findChildren(QgsPropertyOverrideButton) for button in buttons: button.setVectorLayer(layer) @@ -638,7 +640,6 @@ def refreshWidgets(self): # pylint: disable=too-many-statements,too-many-branch # get the plot type from the combobox self.ptype = self.plot_combo.currentData() - # BoxPlot BarPlot and Histogram orientation (same values) self.orientation_combo.clear() self.orientation_combo.addItem(self.tr('Vertical'), 'v') @@ -724,8 +725,12 @@ def refreshWidgets(self): # pylint: disable=too-many-statements,too-many-branch ]) self.line_combo.clear() + self.line_combo_threshold.clear() for k, v in self.line_types.items(): self.line_combo.addItem(k, v) + self.line_combo_threshold.addItem(k,v) + + # BarPlot bar mode self.bar_mode_combo.clear() @@ -764,10 +769,11 @@ def refreshWidgets(self): # pylint: disable=too-many-statements,too-many-branch 'BlackRedYellowBlue': 'Blackbody', 'Terrain': 'Earth', 'Electric Scale': 'Electric', - 'RedOrangeYellow': 'YIOrRd', - 'DeepblueBlueWhite': 'YIGnBu', + 'RedOrangeYellow': 'YlOrRd', # fix from https://github.com/plotly/graphing-library-docs/issues/14 + 'DeepblueBlueWhite': 'YlGnBu', # fix from https://github.com/plotly/graphing-library-docs/issues/14 'BlueWhitePurple': 'Picnic'} + self.color_scale_combo.clear() self.color_scale_data_defined_in.clear() @@ -790,7 +796,7 @@ def refreshWidgets(self): # pylint: disable=too-many-statements,too-many-branch self.register_data_defined_button( self.in_color_defined_button, PlotSettings.PROPERTY_COLOR) - elif self.ptype in ('scatter', 'ternary', 'bar', '2dhistogram', 'contour', 'polar'): + elif self.ptype in ('scatter', 'ternary', 'bar', '2dhistogram', 'contour', 'polar','radar'): self.x_label.setText(self.tr('X field')) self.x_label.setFont(self.font()) @@ -868,8 +874,12 @@ def refreshWidgets(self): # pylint: disable=too-many-statements,too-many-branch # plot properties self.layer_combo: ['all'], self.feature_subset_defined_button: ['all'], - self.x_label: ['all'], - self.x_combo: ['all'], + self.x_label: ['scatter', 'bar', 'box', 'pie', '2dhistogram','histogram', 'polar', 'ternary', 'violin', 'contour'], + self.x_combo: ['scatter', 'bar', 'box','pie' '2dhistogram','histogram', 'polar', 'ternary', 'violin', 'contour'], + self.y_fields_label: ['radar'], + self.y_fields_combo: ['radar'], + self.y_combo_radar_label: ['radar'], + self.y_radar_label: ['radar'], self.y_label: ['scatter', 'bar', 'box', 'pie', '2dhistogram', 'polar', 'ternary', 'contour', 'violin'], self.y_combo: ['scatter', 'bar', 'box', 'pie', '2dhistogram', 'polar', 'ternary', 'contour', 'violin'], self.z_label: ['ternary'], @@ -889,14 +899,14 @@ def refreshWidgets(self): # pylint: disable=too-many-statements,too-many-branch self.marker_width_lab: ['scatter', 'bar', 'box', 'histogram', 'polar', 'ternary', 'violin'], self.marker_width: ['scatter', 'bar', 'box', 'histogram', 'polar', 'ternary', 'violin'], self.stroke_defined_button: ['scatter', 'bar', 'box', 'histogram', 'polar', 'ternary', 'violin'], - self.marker_size_lab: ['scatter', 'polar', 'ternary', 'bar'], - self.marker_size: ['scatter', 'polar', 'ternary', 'bar'], - self.size_defined_button: ['scatter', 'polar', 'ternary', 'bar'], - self.marker_type_lab: ['scatter', 'polar'], - self.marker_type_combo: ['scatter', 'polar'], - self.alpha_lab: ['scatter', 'bar', 'box', 'histogram', 'polar', 'ternary', 'violin', 'contour'], - self.opacity_widget: ['scatter', 'bar', 'box', 'pie', 'histogram', 'polar', 'ternary', 'violin', 'contour'], - self.properties_group_box: ['scatter', 'bar', 'box', 'pie', 'histogram', 'polar', 'ternary', 'contour', '2dhistogram', + self.marker_size_lab: ['scatter', 'polar', 'ternary', 'bar', 'radar'], + self.marker_size: ['scatter', 'polar', 'ternary', 'bar', 'radar'], + self.size_defined_button: ['scatter', 'polar','ternary', 'bar'], + self.marker_type_lab: ['scatter', 'polar','radar'], + self.marker_type_combo: ['scatter', 'polar','radar'], + self.alpha_lab: ['scatter', 'bar', 'box', 'histogram', 'polar','radar', 'ternary', 'violin', 'contour'], + self.opacity_widget: ['scatter', 'bar', 'box', 'pie', 'histogram', 'polar', 'radar','ternary', 'violin', 'contour'], + self.properties_group_box: ['scatter', 'bar', 'box', 'pie', 'histogram', 'polar', 'radar','ternary', 'contour', '2dhistogram', 'violin'], self.bar_mode_lab: ['bar', 'histogram'], self.bar_mode_combo: ['bar', 'histogram'], @@ -905,14 +915,13 @@ def refreshWidgets(self): # pylint: disable=too-many-statements,too-many-branch self.legend_title_defined_button: ['all'], self.point_lab: ['scatter', 'ternary', 'polar'], self.point_combo: ['scatter', 'ternary', 'polar'], - self.line_lab: ['scatter', 'polar'], - self.line_combo: ['scatter', 'polar'], - self.color_scale_label: ['contour', '2dhistogram'], - self.color_scale_combo: ['contour', '2dhistogram'], + self.line_lab: ['scatter', 'polar', 'radar',], + self.line_combo: ['scatter', 'polar', 'radar'], + self.color_scale_label: ['contour', '2dhistogram', 'radar'], + self.color_scale_combo: ['contour', '2dhistogram', 'radar'], self.contour_type_label: ['contour'], self.contour_type_combo: ['contour'], self.show_lines_check: ['contour'], - # layout customization self.show_legend_check: ['all'], self.orientation_legend_check: ['scatter', 'bar', 'box', 'histogram', 'ternary', 'pie', 'violin'], @@ -920,20 +929,20 @@ def refreshWidgets(self): # pylint: disable=too-many-statements,too-many-branch self.plot_title_line: ['all'], self.plot_title_defined_button: ['all'], self.font_title_label: ['all'], - self.font_xlabel_label: ['all'], + self.font_xlabel_label: ['scatter', 'bar', 'box', 'pie', '2dhistogram','histogram', 'polar','ternary', 'contour', 'violin'], self.font_xticks_label: ['all'], self.font_ylabel_label: ['all'], - self.font_yticks_label: ['all'], + self.font_yticks_label: ['scatter', 'bar', 'box', 'pie', '2dhistogram','histogram', 'polar','ternary', 'contour', 'violin'], self.font_title_style: ['all'], - self.font_xlabel_style: ['all'], + self.font_xlabel_style: ['scatter', 'bar', 'box', 'pie', '2dhistogram','histogram', 'polar','ternary', 'contour', 'violin'], self.font_xticks_style: ['all'], self.font_ylabel_style: ['all'], - self.font_yticks_style: ['all'], + self.font_yticks_style: ['scatter', 'bar', 'box', 'pie', '2dhistogram','histogram', 'polar','ternary', 'contour', 'violin'], self.font_title_color: ['all'], - self.font_xlabel_color: ['all'], + self.font_xlabel_color: ['scatter', 'bar', 'box', 'pie', '2dhistogram','histogram', 'polar','ternary', 'contour', 'violin'], self.font_xticks_color: ['all'], self.font_ylabel_color: ['all'], - self.font_yticks_color: ['all'], + self.font_yticks_color: ['scatter', 'bar', 'box', 'pie', '2dhistogram','histogram', 'polar','ternary', 'contour', 'violin'], self.x_axis_label: ['scatter', 'bar', 'box', 'histogram', '2dhistogram', 'ternary', 'violin'], self.x_axis_title: ['scatter', 'bar', 'box', 'histogram', '2dhistogram', 'ternary', 'violin'], self.x_axis_title_defined_button: ['scatter', 'bar', 'box', 'histogram', '2dhistogram', 'ternary', 'violin'], @@ -989,8 +998,14 @@ def refreshWidgets(self): # pylint: disable=too-many-statements,too-many-branch self.violinBox: ['violin'], self.pie_hole_label : ['pie'], self.pie_hole : ['pie'], - } + self.fill : ['radar'], + self.threshold: ['radar'], + self.threshold_value: ['radar'], + self.line_threshold_value: ['radar'], + self.line_combo_threshold: ['radar'], + self.threshold_value_label: ['radar'] + } # enable the widget according to the plot type for k, v in self.widgetType.items(): if 'all' in v or self.ptype in v: @@ -1010,6 +1025,8 @@ def refreshWidgets(self): # pylint: disable=too-many-statements,too-many-branch self.color_scale_data_defined_in_check.setVisible(False) self.color_scale_data_defined_in_invert_check.setVisible(False) + self.refreshWidgets3() + def refreshWidgets2(self): """ just refresh the UI to make the radiobuttons visible when SubPlots @@ -1069,6 +1086,7 @@ def setLegend(self): self.legend_title.setText(self.y_combo.currentText()) elif self.ptype == 'histogram': self.legend_title.setText(self.x_combo.currentText()) + else: legend_title_string = ( f'{self.x_combo.currentText()} - {self.y_combo.currentText()}') @@ -1080,7 +1098,6 @@ def get_settings(self) -> PlotSettings: # pylint: disable=R0915 """ # get the plot type from the combo box self.ptype = self.plot_combo.currentData() - # if colorscale should be visible or not color_scale_visible = self.color_scale_data_defined_in_check.isVisible( ) and self.color_scale_data_defined_in_check.isChecked() @@ -1128,7 +1145,14 @@ def get_settings(self) -> PlotSettings: # pylint: disable=R0915 'show_lines_check': self.show_lines_check.isChecked(), 'layout_filter_by_map': self.filter_by_map_check.isChecked(), 'layout_filter_by_atlas': self.filter_by_atlas_check.isChecked(), - 'pie_hole' : self.pie_hole.value() + 'pie_hole': self.pie_hole.value(), + 'fill': self.fill.isChecked(), + 'threshold': self.threshold.isChecked(), + 'y_combo_radar_label': self.y_combo_radar_label.currentText(), + 'line_dash_threshold': self.line_types2[self.line_combo_threshold.currentText()], + 'line_combo_threshold': self.line_combo_threshold.currentText(), + 'threshold_value': self.threshold_value.value(), + 'y_fields_combo': ', '.join(self.y_fields_combo.checkedItems()) } if self.in_color_defined_button.isActive(): @@ -1146,6 +1170,7 @@ def get_settings(self) -> PlotSettings: # pylint: disable=R0915 # build the layout customizations layout_properties = {'legend': self.show_legend_check.isChecked(), 'legend_orientation': 'h' if self.orientation_legend_check.isChecked() else 'v', + 'title': self.plot_title_line.text(), 'font_title_size': max( self.font_title_style.currentFont().pixelSize(), @@ -1190,7 +1215,6 @@ def get_settings(self) -> PlotSettings: # pylint: disable=R0915 'additional_info_expression': self.additional_info_combo.expression(), 'bins_check': self.bins_check.isChecked(), 'gridcolor': self.layout_grid_axis_color.color().name()} - settings = PlotSettings(plot_type=self.ptype, properties=plot_properties, layout=layout_properties, source_layer_id=self.layer_combo.currentLayer().id( ) if self.layer_combo.currentLayer() else None, @@ -1357,13 +1381,21 @@ def set_settings(self, settings: PlotSettings): # pylint: disable=too-many-stat self.layout_grid_axis_color.setColor( QColor(settings.layout.get('gridcolor') or '#bdbfc0')) self.pie_hole.setValue(settings.properties.get('pie_hole', 0)) + for name in settings.properties.get('y_fields_combo', '').split(", "): + self.y_fields_combo.setItemCheckState(self.y_fields_combo.findText(name), Qt.CheckState.Checked) + self.line_combo_threshold.setCurrentText( + settings.properties.get('line_combo_threshold', 'Dash Line') + ) + self.y_combo_radar_label.setExpression(settings.properties.get('y_combo_radar_label', '')) + self.threshold.setChecked(settings.properties.get('threshold', True)) + self.threshold_value.setValue(settings.properties.get('threshold_value', 1)) + self.fill.setChecked(settings.properties.get('fill', False)) def create_plot_factory(self) -> PlotFactory: """ Creates a PlotFactory based on the settings defined in the dialog """ settings = self.get_settings() - visible_region = None if settings.properties['visible_features_only']: visible_region = QgsReferencedRectangle(self.iface.mapCanvas().extent(), @@ -1371,7 +1403,6 @@ def create_plot_factory(self) -> PlotFactory: # plot instance plot_factory = PlotFactory(settings, visible_region=visible_region) - # unique name for each plot trace (name is idx_plot, e.g. 1_scatter) self.pid = f'{self.idx}_{settings.plot_type}' @@ -1424,17 +1455,15 @@ def create_plot(self): if self.subcombo.currentData() == 'single': # plot single plot, check the object dictionary length - if len(self.plot_factories) <= 1: + if len(self.plot_factories) <= 1 or self.ptype == 'radar': self.plot_path = plot_factory.build_figure() # to plot many plots in the same figure else: # plot list ready to be called within go.Figure pl = [] - for _, v in self.plot_factories.items(): pl.append(v.trace[0]) - self.plot_path = plot_factory.build_figures(self.ptype, pl) # choice to draw subplots instead depending on the combobox @@ -1606,7 +1635,6 @@ def showPlotFromDic(self, plot_input_dic): # plot type in the plot_combo combobox self.plot_combo.setCurrentIndex( self.plot_combo.findData(plot_input_dic["plot_type"])) - try: self.layer_combo.setLayer(plot_input_dic["layer"]) if 'x_name' in plot_input_dic["plot_prop"] and plot_input_dic["plot_prop"]["x_name"]: @@ -1615,13 +1643,17 @@ def showPlotFromDic(self, plot_input_dic): self.y_combo.setField(plot_input_dic["plot_prop"]["y_name"]) if 'z_name' in plot_input_dic["plot_prop"] and plot_input_dic["plot_prop"]["z_name"]: self.z_combo.setField(plot_input_dic["plot_prop"]["z_name"]) + if 'y_radar_label' in plot_input_dic["plot_prop"] and plot_input_dic["plot_prop"]["y_radar_label"]: + self.y_combo_radar_label.setField(plot_input_dic["plot_prop"]["y_radar_label"]) + if 'y_radar_fields' in plot_input_dic["plot_prop"] and plot_input_dic["plot_prop"]["y_radar_fields"]: + for name in plot_input_dic["plot_prop"]["y_radar_fields"]: + self.y_fields_combo.setItemCheckState(self.y_fields_combo.findText(name), Qt.CheckState.Checked) except: # pylint: disable=bare-except # noqa: F401 pass settings = PlotSettings(plot_input_dic['plot_type'], properties=plot_input_dic["plot_prop"], layout=plot_input_dic["layout_prop"]) - # create Plot instance factory = PlotFactory(settings) diff --git a/DataPlotly/ui/dataplotly_dockwidget_base.ui b/DataPlotly/ui/dataplotly_dockwidget_base.ui index 2cfd3f03..7b763325 100644 --- a/DataPlotly/ui/dataplotly_dockwidget_base.ui +++ b/DataPlotly/ui/dataplotly_dockwidget_base.ui @@ -320,9 +320,9 @@ QListWidget::item::selected { 0 - -270 + 0 673 - 989 + 1200 @@ -357,15 +357,56 @@ QListWidget::item::selected { Plot Parameters - + + + + + + + ... + + + + + + + Linked map + + + + Y field - - + + + + true + + + Use only selected features + + + + + + + Use only features visible in map + + + + + + + true + + + Use only visible features + + @@ -392,37 +433,43 @@ QListWidget::item::selected { - - + + - Use only features inside atlas feature + Y fields - + + + + Z field - - + + + + + + + + - Use only features visible in map + Feature subset - - + + - ... + Use only features inside atlas feature - - - @@ -433,39 +480,9 @@ QListWidget::item::selected { - - - - Linked map - - - - - - - true - - - Use only selected features - - - - + - - - - - - - true - - - Use only visible features - - - @@ -473,13 +490,16 @@ QListWidget::item::selected { - - + + - Feature subset + Y label + + + @@ -489,378 +509,422 @@ QListWidget::item::selected { Properties - - - - - - + + + ... - - - - - 0 - 0 - + + + + Legend title - - - - If checked, box plots will be overlaid on top of violin plots - + + - Include box plots + Show statistics + + + + + + + + + + + + Visible true - - + + + + Invert color + + + + + + + + + + - Violin side + Marker color - - + + - ... + Stroke color - - + + - Marker size + ... - - + + + + + + + + - Line type + Hover tooltip - - + + + + Contour type + + - - + + + + + + + - Marker color + Show lines + + + true - - - - Color scale - - + - + + + + - + ... - - - - - + + - - + + - Point type + Label text position - - + + - Show mean line + Threshold true - - - - - - - + + + + + - Visible + Marker size - - true + + + + + + + + + + 0 + 0 + - - + + - Invert color + Bar orientation - + + + + Violin side + + - - + + + + Opacity + + + + + + + + - Outliers + Threshold line type - + Qt::StrongFocus - - - - Manual bin size - - + + - - + + - Legend title + Line type - - + + - Color scale + Normalization - - + + - - + + + + + - Contour type + Manual bin size - - + + - - + + - Hover tooltip + Pie hole - - - - - - - - - Show lines + + + + false - - true + + 1000 + + + 10 - + + + + + 0 + 0 + + + - - - - - - true - + + - Invert histogram direction + Fill - - - - true - + + - Cumulative histogram + Outliers - - - - + + - ... + Stroke width - - - - + ... - - - - Opacity + + + + 0.950000000000000 + + + 0.050000000000000 + + + 0.000000000000000 + + + false - - - - - - - - 0 - 0 - + + + + Color scale - - - - - - - false - - - 1000 - - - 10 + + + + ... - - - - - - - - + + - - + + - Bar orientation + Hover label as text - - + + + + Point type + + - - + + + + If checked, box plots will be overlaid on top of violin plots + - Normalization + Include box plots + + + true - - + + + + + + true + - Stroke width + Invert histogram direction - - + + + + true + - Show statistics + Cumulative histogram - - + - - - - Label text position - - + + - + Marker type - - - - - + + - Stroke color + Show mean line - - - - - - Hover label as text + + true - - + + - Pie hole + Color scale - - + + + + + - 0.950000000000000 - - - 0.050000000000000 + 99990000.000000000000000 - 0.000000000000000 + 1.000000000000000 - - false + + + + + + + + + Threshold value @@ -906,8 +970,8 @@ QListWidget::item::selected { 0 0 - 414 - 583 + 449 + 820 @@ -1499,6 +1563,11 @@ QListWidget::item::selected { + + QgsCheckableComboBox + QComboBox +
qgscheckablecombobox.h
+
QgsCollapsibleGroupBox QGroupBox @@ -1558,22 +1627,6 @@ QListWidget::item::selected {
- - x_combo - fieldChanged(QString) - x_axis_title - setText(QString) - - - 903 - -14 - - - 364 - 3 - - - y_combo fieldChanged(QString) @@ -1622,5 +1675,21 @@ QListWidget::item::selected { + + x_combo + fieldChanged(QString) + x_axis_title + setText(QString) + + + 903 + -14 + + + 364 + 3 + + +