From 70b33b737b9159d2346bdaf4c8794e468b447970 Mon Sep 17 00:00:00 2001 From: Sophie Aubier Date: Fri, 7 Mar 2025 17:34:25 +0100 Subject: [PATCH 01/24] first radar plot add --- DataPlotly/core/plot_factory.py | 20 +- DataPlotly/core/plot_settings.py | 6 +- DataPlotly/core/plot_types/__init__.py | 1 + DataPlotly/core/plot_types/radar.py | 90 +++ DataPlotly/gui/plot_settings_widget.py | 92 ++- DataPlotly/ui/dataplotly_dockwidget_base.ui | 637 +++++++++++--------- 6 files changed, 526 insertions(+), 320 deletions(-) create mode 100644 DataPlotly/core/plot_types/radar.py diff --git a/DataPlotly/core/plot_factory.py b/DataPlotly/core/plot_factory.py index 759d2d34..3f2b7961 100644 --- a/DataPlotly/core/plot_factory.py +++ b/DataPlotly/core/plot_factory.py @@ -163,6 +163,9 @@ 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_needs_geom, 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()) 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()) @@ -230,6 +233,8 @@ def add_source_field_or_expression(field_or_expression): colors = [] stroke_colors = [] stroke_widths = [] + y_radar_labels = [] + for f in it: if visible_geom_engine and not visible_geom_engine.intersects(f.geometry().constGet()): continue @@ -267,6 +272,16 @@ 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 + if additional_info_expression: additional_hover_text.append( additional_info_expression.evaluate(context)) @@ -280,6 +295,8 @@ 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 self.settings.data_defined_properties.isActive(PlotSettings.PROPERTY_MARKER_SIZE): default_value = self.settings.properties['marker_size'] @@ -338,6 +355,7 @@ 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 if marker_sizes: self.settings.data_defined_marker_sizes = marker_sizes if colors: @@ -740,9 +758,9 @@ 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) + print(ptrace) # set some configurations if config is None: diff --git a/DataPlotly/core/plot_settings.py b/DataPlotly/core/plot_settings.py index 420ccee7..d51ffcfe 100644 --- a/DataPlotly/core/plot_settings.py +++ b/DataPlotly/core/plot_settings.py @@ -135,7 +135,9 @@ 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, + 'radar_fill' : None + } # layout nested dictionary @@ -175,6 +177,7 @@ def __init__(self, plot_type: str = 'scatter', properties: dict = None, layout: 'range_slider': {'borderwidth': 1, 'visible': False}, 'bargaps': 0, 'polar': {'angularaxis': {'direction': 'clockwise'}}, + 'radar': {'angularaxis': {'direction': 'clockwise'}}, 'additional_info_expression': '', 'bins_check': False, 'gridcolor': '#bdbfc0' @@ -205,6 +208,7 @@ def __init__(self, plot_type: str = 'scatter', properties: dict = None, layout: self.x = [] self.y = [] self.z = [] + self.y_radar_labels = [] 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/radar.py b/DataPlotly/core/plot_types/radar.py new file mode 100644 index 00000000..b55b5a8f --- /dev/null +++ b/DataPlotly/core/plot_types/radar.py @@ -0,0 +1,90 @@ +""" +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.QtGui import QIcon +from DataPlotly.core.plot_types.plot_type import PlotType +import plotly.colors as pc +import matplotlib.cm as cm +import matplotlib.colors as mcolors +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/polar.svg')) + + @staticmethod + def create_trace(settings): + radar_plot_list = [] + x =settings.x[0] + + # Change plot colors + colors = pc.sample_colorscale(settings.properties['color_scale'], np.linspace(0, 1, len(settings.y))) + + # change type line for threshold + line = [settings.properties['line_dash']] *len(settings.y) + + if settings.properties['radar_threshold'] is True : + colors.append('#000000') + settings.y.append([settings.properties['threshold_value']] * len(settings.y)) + settings.y_radar_labels.append('seuil') + line.append(settings.properties['line_type_threshold']) + + for (y, name, color,line) in zip(settings.y, settings.y_radar_labels, colors,line): + + # Close circle, create fictif points + if settings.properties['marker'] in ('lines', 'lines+markers'): + x= x+[x[0]] + y= y+ y+[y[0]] + radar_plot_list.append(graph_objs.Scatterpolar( + r=y, + theta=x, + mode=settings.properties['marker'], + name=name, + marker={ + "color": colors, + "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": color, + "width": settings.data_defined_stroke_widths if settings.data_defined_stroke_widths else settings.properties['marker_width'], + "dash": line + + }, + opacity=settings.properties['opacity'], + fill = "toself" if settings.properties['radar_fill'] else None + )) + + return radar_plot_list + + @staticmethod + def create_layout(settings): + layout = super(RadarChartFactory, RadarChartFactory).create_layout(settings) + + layout['polar'] = settings.layout['radar'] + + return layout diff --git a/DataPlotly/gui/plot_settings_widget.py b/DataPlotly/gui/plot_settings_widget.py index 9ec9ec20..f69b62ec 100644 --- a/DataPlotly/gui/plot_settings_widget.py +++ b/DataPlotly/gui/plot_settings_widget.py @@ -459,7 +459,7 @@ def data_defined_color_updated(self): # if data defined button is active if self.in_color_defined_button.isActive(): # if plot is type for which using an expression for the color selection makes sense - if self.ptype in ['scatter', 'bar', 'pie', 'ternary', 'histogram']: + if self.ptype in ['scatter', 'bar', 'pie', 'ternary', 'histogram', 'radar']: self.in_color_combo.setEnabled(False) self.color_scale_data_defined_in.setVisible(True) self.color_scale_data_defined_in.setEnabled(True) @@ -493,10 +493,16 @@ 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 : + field_names = [field.name() for field in layer.fields()] + self.y_fields_combo.addItems(field_names) buttons = self.findChildren(QgsPropertyOverrideButton) for button in buttons: @@ -670,8 +676,8 @@ def refreshWidgets(self): # pylint: disable=too-many-statements,too-many-branch # ScatterPlot marker types self.marker_types = OrderedDict([ - (self.tr('Points'), 'markers'), (self.tr('Lines'), 'lines'), + (self.tr('Points'), 'markers'), (self.tr('Points and Lines'), 'lines+markers') ]) self.marker_type_combo.clear() @@ -726,6 +732,7 @@ def refreshWidgets(self): # pylint: disable=too-many-statements,too-many-branch self.line_combo.clear() for k, v in self.line_types.items(): self.line_combo.addItem(k, v) + self.line_type_threshold.addItem(k,v) # BarPlot bar mode self.bar_mode_combo.clear() @@ -768,6 +775,7 @@ def refreshWidgets(self): # pylint: disable=too-many-statements,too-many-branch 'DeepblueBlueWhite': 'YIGnBu', 'BlueWhitePurple': 'Picnic'} + self.color_scale_combo.clear() self.color_scale_data_defined_in.clear() @@ -790,7 +798,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,51 +876,54 @@ 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.y_label: ['scatter', 'bar', 'box', 'pie', '2dhistogram', 'polar', 'ternary', 'contour', 'violin'], - self.y_combo: ['scatter', 'bar', 'box', 'pie', '2dhistogram', 'polar', 'ternary', 'contour', 'violin'], + self.x_label: ['scatter', 'bar', 'box', 'pie', '2dhistogram', 'polar','ternary', 'contour', 'violin'], + self.x_combo: ['scatter', 'bar', 'box', 'pie', '2dhistogram', 'polar', 'ternary', 'contour', 'violin'], + 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'], self.z_combo: ['ternary'], self.info_label: ['scatter'], self.info_combo: ['scatter'], self.in_color_lab: ['scatter', 'bar', 'box', 'pie', 'histogram', 'polar', 'ternary', 'violin'], self.in_color_combo: ['scatter', 'bar', 'box', 'pie', 'histogram', 'polar', 'ternary', 'violin'], - self.in_color_defined_button: ['scatter', 'bar', 'box', 'pie', 'histogram', 'polar', 'ternary'], + self.in_color_defined_button: ['scatter', 'bar', 'box', 'pie', 'histogram', 'polar', 'ternary'], self.color_scale_data_defined_in: ['scatter', 'bar', 'pie', 'histogram', 'ternary'], self.color_scale_data_defined_in_label: ['scatter', 'bar', 'ternary'], self.color_scale_data_defined_in_check: ['scatter', 'bar', 'ternary'], self.color_scale_data_defined_in_invert_check: ['bar', 'ternary'], self.out_color_lab: ['scatter', 'bar', 'box', 'pie', 'histogram', 'polar', 'ternary', 'violin'], self.out_color_combo: ['scatter', 'bar', 'box', 'pie', 'histogram', 'polar', 'ternary', 'violin'], - self.out_color_defined_button: ['scatter', 'bar', 'box', 'pie', 'histogram', 'polar', 'ternary', 'violin'], + self.out_color_defined_button: ['scatter', 'bar', 'box', 'pie', 'histogram', 'polar', 'ternary', 'violin'], 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'], self.legend_label: ['all'], self.legend_title: ['all'], self.legend_title_defined_button: ['all'], - self.point_lab: ['scatter', 'ternary', 'polar'], + 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'], @@ -989,8 +1000,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.radar_fill : ['radar'], + self.radar_threshold: ['radar'], + self.threshold_value: ['radar'], + self.line_threshold_value: ['radar'], + self.line_type_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: @@ -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,8 +1145,20 @@ 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(), + 'radar_fill': self.radar_fill.isChecked(), + 'radar_threshold': self.radar_threshold.isChecked(), + 'y_combo_radar_label': self.y_combo_radar_label.currentText(), + 'line_type_threshold' : self.line_types2[self.line_type_threshold.currentText()], + 'threshold_value' : self.threshold_value.value() + + } + print(self.radar_fill.isChecked()) + print(self.marker_size.value(), self.threshold_value.value()) + if self.ptype == 'radar': + plot_properties['y_name'] = "array(" + ", ".join([f'"{field_name}"' for field_name in self.y_fields_combo.checkedItems()]) + ")" + plot_properties['x_name'] = "array(" + ", ".join([f"'{field_name}'" for field_name in self.y_fields_combo.checkedItems()]) + ")" if self.in_color_defined_button.isActive(): plot_properties['color_scale_data_defined_in_check'] = self.color_scale_data_defined_in_check.isChecked() @@ -1236,6 +1265,7 @@ def set_settings(self, settings: PlotSettings): # pylint: disable=too-many-stat self.filter_by_atlas_check.setChecked( settings.properties.get('layout_filter_by_atlas', False)) self.x_combo.setExpression(settings.properties.get('x_name', '')) + # self.y_fields_combo.setExpression(settings.properties.get('y_name', '')) self.y_combo.setExpression(settings.properties.get('y_name', '')) self.z_combo.setExpression(settings.properties.get('z_name', '')) self.in_color_combo.setColor( @@ -1358,6 +1388,11 @@ def set_settings(self, settings: PlotSettings): # pylint: disable=too-many-stat QColor(settings.layout.get('gridcolor') or '#bdbfc0')) self.pie_hole.setValue(settings.properties.get('pie_hole', 0)) + self.radar_fill.setChecked( + settings.properties.get('radar_fill', True)) + self.radar_threshold.setChecked( + settings.properties.get('radar_fill', True)) + def create_plot_factory(self) -> PlotFactory: """ Creates a PlotFactory based on the settings defined in the dialog @@ -1424,17 +1459,16 @@ 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) or self.ptype == 'radar' <= 1: 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]) - + print(pl) self.plot_path = plot_factory.build_figures(self.ptype, pl) # choice to draw subplots instead depending on the combobox diff --git a/DataPlotly/ui/dataplotly_dockwidget_base.ui b/DataPlotly/ui/dataplotly_dockwidget_base.ui index 2cfd3f03..b9371580 100644 --- a/DataPlotly/ui/dataplotly_dockwidget_base.ui +++ b/DataPlotly/ui/dataplotly_dockwidget_base.ui @@ -320,9 +320,9 @@ QListWidget::item::selected { 0 - -270 + -191 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,380 +509,414 @@ 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 + Hover tooltip - - + + - Line type + Contour type - - + + - - + + + + + + + - Marker color + Show lines + + + true - - - - Color scale - - + - + + + + - + ... - - - - - + + - - + + - Point type + Label text position - - + + - Show mean line + threshold - - true + + + + + + + + + Marker size - - - - - - - + + + + + + + + 0 + 0 + + + + + + - Visible + Bar orientation - - true + + + + + + Threshold value - - + + - Invert color + 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 - - - 0.000000000000000 - - - false - - + + + + + @@ -906,8 +960,8 @@ QListWidget::item::selected { 0 0 - 414 - 583 + 687 + 742 @@ -1499,6 +1553,11 @@ QListWidget::item::selected { + + QgsCheckableComboBox + QComboBox +
qgscheckablecombobox.h
+
QgsCollapsibleGroupBox QGroupBox @@ -1558,22 +1617,6 @@ QListWidget::item::selected {
- - x_combo - fieldChanged(QString) - x_axis_title - setText(QString) - - - 903 - -14 - - - 364 - 3 - - - y_combo fieldChanged(QString) @@ -1622,5 +1665,21 @@ QListWidget::item::selected { + + x_combo + fieldChanged(QString) + x_axis_title + setText(QString) + + + 903 + -14 + + + 364 + 3 + + + From 510e826a83ed03613ae4a2e0eec42eeb1f03ceb0 Mon Sep 17 00:00:00 2001 From: Sophie Aubier Date: Mon, 10 Mar 2025 11:19:14 +0100 Subject: [PATCH 02/24] Clean up: remove print(), improve variable names ... --- DataPlotly/core/plot_settings.py | 2 +- DataPlotly/core/plot_types/radar.py | 37 +++++++++--------- DataPlotly/gui/plot_settings_widget.py | 42 ++++++++------------- DataPlotly/ui/dataplotly_dockwidget_base.ui | 4 +- 4 files changed, 38 insertions(+), 47 deletions(-) diff --git a/DataPlotly/core/plot_settings.py b/DataPlotly/core/plot_settings.py index d51ffcfe..e695297c 100644 --- a/DataPlotly/core/plot_settings.py +++ b/DataPlotly/core/plot_settings.py @@ -136,7 +136,7 @@ def __init__(self, plot_type: str = 'scatter', properties: dict = None, layout: 'layout_filter_by_map': False, 'layout_filter_by_atlas': False, 'pie_hole': 0, - 'radar_fill' : None + 'fill' : None } diff --git a/DataPlotly/core/plot_types/radar.py b/DataPlotly/core/plot_types/radar.py index b55b5a8f..ecc789d3 100644 --- a/DataPlotly/core/plot_types/radar.py +++ b/DataPlotly/core/plot_types/radar.py @@ -35,33 +35,34 @@ def icon(): @staticmethod def create_trace(settings): radar_plot_list = [] - x =settings.x[0] + x = settings.x[0] + # Sample colors from the color scale based on the length of settings.y + colors_list = pc.sample_colorscale(settings.properties['color_scale'], np.linspace(0, 1, len(settings.y))) - # Change plot colors - colors = pc.sample_colorscale(settings.properties['color_scale'], np.linspace(0, 1, len(settings.y))) - - # change type line for threshold - line = [settings.properties['line_dash']] *len(settings.y) + # List repeating the line type for each element in settings.y + line_type_list = [settings.properties['line_dash']] * len(settings.y[0]) - if settings.properties['radar_threshold'] is True : - colors.append('#000000') - settings.y.append([settings.properties['threshold_value']] * len(settings.y)) - settings.y_radar_labels.append('seuil') - line.append(settings.properties['line_type_threshold']) + # Add a black color and a threshold line to the data + if settings.properties['threshold'] is True : + colors_list.append('#000000') + settings.y.append([settings.properties['threshold_value']] * len(settings.y[0])) + settings.y_radar_labels.append('threshold') + line_type_list.append(settings.properties['line_type_threshold']) - for (y, name, color,line) in zip(settings.y, settings.y_radar_labels, colors,line): + for (y, name, colors_list, line_type_list) in zip(settings.y, settings.y_radar_labels, colors_list, line_type_list): - # Close circle, create fictif points + # 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= x+[x[0]] - y= y+ y+[y[0]] + y = y+[y[0]] + radar_plot_list.append(graph_objs.Scatterpolar( r=y, theta=x, mode=settings.properties['marker'], name=name, marker={ - "color": colors, + "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": { @@ -70,13 +71,13 @@ def create_trace(settings): } }, line={ - "color": color, + "color": colors_list, "width": settings.data_defined_stroke_widths if settings.data_defined_stroke_widths else settings.properties['marker_width'], - "dash": line + "dash": line_type_list }, opacity=settings.properties['opacity'], - fill = "toself" if settings.properties['radar_fill'] else None + fill="toself" if settings.properties['fill'] else None )) return radar_plot_list diff --git a/DataPlotly/gui/plot_settings_widget.py b/DataPlotly/gui/plot_settings_widget.py index f69b62ec..621f874f 100644 --- a/DataPlotly/gui/plot_settings_widget.py +++ b/DataPlotly/gui/plot_settings_widget.py @@ -771,8 +771,8 @@ 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'} @@ -875,9 +875,9 @@ def refreshWidgets(self): # pylint: disable=too-many-statements,too-many-branch self.widgetType = { # plot properties self.layer_combo: ['all'], - self.feature_subset_defined_button: ['all'], - self.x_label: ['scatter', 'bar', 'box', 'pie', '2dhistogram', 'polar','ternary', 'contour', 'violin'], - self.x_combo: ['scatter', 'bar', 'box', 'pie', '2dhistogram', 'polar', 'ternary', 'contour', 'violin'], + self.feature_subset_defined_button: ['scatter', 'bar', 'box', 'pie', '2dhistogram','histogram', 'polar','ternary', 'contour', 'violin'], + 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'], @@ -890,14 +890,14 @@ def refreshWidgets(self): # pylint: disable=too-many-statements,too-many-branch self.info_combo: ['scatter'], self.in_color_lab: ['scatter', 'bar', 'box', 'pie', 'histogram', 'polar', 'ternary', 'violin'], self.in_color_combo: ['scatter', 'bar', 'box', 'pie', 'histogram', 'polar', 'ternary', 'violin'], - self.in_color_defined_button: ['scatter', 'bar', 'box', 'pie', 'histogram', 'polar', 'ternary'], + self.in_color_defined_button: ['scatter', 'bar', 'box', 'pie', 'histogram', 'polar', 'ternary'], self.color_scale_data_defined_in: ['scatter', 'bar', 'pie', 'histogram', 'ternary'], self.color_scale_data_defined_in_label: ['scatter', 'bar', 'ternary'], self.color_scale_data_defined_in_check: ['scatter', 'bar', 'ternary'], self.color_scale_data_defined_in_invert_check: ['bar', 'ternary'], self.out_color_lab: ['scatter', 'bar', 'box', 'pie', 'histogram', 'polar', 'ternary', 'violin'], self.out_color_combo: ['scatter', 'bar', 'box', 'pie', 'histogram', 'polar', 'ternary', 'violin'], - self.out_color_defined_button: ['scatter', 'bar', 'box', 'pie', 'histogram', 'polar', 'ternary', 'violin'], + self.out_color_defined_button: ['scatter', 'bar', 'box', 'pie', 'histogram', 'polar', 'ternary', 'violin'], 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'], @@ -915,7 +915,7 @@ def refreshWidgets(self): # pylint: disable=too-many-statements,too-many-branch self.legend_label: ['all'], self.legend_title: ['all'], self.legend_title_defined_button: ['all'], - self.point_lab: ['scatter', 'ternary', 'polar',], + self.point_lab: ['scatter', 'ternary', 'polar'], self.point_combo: ['scatter', 'ternary', 'polar'], self.line_lab: ['scatter', 'polar','radar',], self.line_combo: ['scatter', 'polar', 'radar'], @@ -1000,8 +1000,8 @@ def refreshWidgets(self): # pylint: disable=too-many-statements,too-many-branch self.violinBox: ['violin'], self.pie_hole_label : ['pie'], self.pie_hole : ['pie'], - self.radar_fill : ['radar'], - self.radar_threshold: ['radar'], + self.fill : ['radar'], + self.threshold: ['radar'], self.threshold_value: ['radar'], self.line_threshold_value: ['radar'], self.line_type_threshold: ['radar'], @@ -1146,16 +1146,13 @@ def get_settings(self) -> PlotSettings: # pylint: disable=R0915 '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(), - 'radar_fill': self.radar_fill.isChecked(), - 'radar_threshold': self.radar_threshold.isChecked(), + 'fill': self.fill.isChecked(), + 'threshold': self.threshold.isChecked(), 'y_combo_radar_label': self.y_combo_radar_label.currentText(), - 'line_type_threshold' : self.line_types2[self.line_type_threshold.currentText()], - 'threshold_value' : self.threshold_value.value() - - + 'line_type_threshold': self.line_types2[self.line_type_threshold.currentText()], + 'threshold_value': self.threshold_value.value() } - print(self.radar_fill.isChecked()) - print(self.marker_size.value(), self.threshold_value.value()) + if self.ptype == 'radar': plot_properties['y_name'] = "array(" + ", ".join([f'"{field_name}"' for field_name in self.y_fields_combo.checkedItems()]) + ")" plot_properties['x_name'] = "array(" + ", ".join([f"'{field_name}'" for field_name in self.y_fields_combo.checkedItems()]) + ")" @@ -1265,7 +1262,6 @@ def set_settings(self, settings: PlotSettings): # pylint: disable=too-many-stat self.filter_by_atlas_check.setChecked( settings.properties.get('layout_filter_by_atlas', False)) self.x_combo.setExpression(settings.properties.get('x_name', '')) - # self.y_fields_combo.setExpression(settings.properties.get('y_name', '')) self.y_combo.setExpression(settings.properties.get('y_name', '')) self.z_combo.setExpression(settings.properties.get('z_name', '')) self.in_color_combo.setColor( @@ -1388,11 +1384,6 @@ def set_settings(self, settings: PlotSettings): # pylint: disable=too-many-stat QColor(settings.layout.get('gridcolor') or '#bdbfc0')) self.pie_hole.setValue(settings.properties.get('pie_hole', 0)) - self.radar_fill.setChecked( - settings.properties.get('radar_fill', True)) - self.radar_threshold.setChecked( - settings.properties.get('radar_fill', True)) - def create_plot_factory(self) -> PlotFactory: """ Creates a PlotFactory based on the settings defined in the dialog @@ -1459,7 +1450,7 @@ def create_plot(self): if self.subcombo.currentData() == 'single': # plot single plot, check the object dictionary length - if len(self.plot_factories) or self.ptype == 'radar' <= 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 @@ -1468,7 +1459,6 @@ def create_plot(self): pl = [] for _, v in self.plot_factories.items(): pl.append(v.trace[0]) - print(pl) self.plot_path = plot_factory.build_figures(self.ptype, pl) # choice to draw subplots instead depending on the combobox diff --git a/DataPlotly/ui/dataplotly_dockwidget_base.ui b/DataPlotly/ui/dataplotly_dockwidget_base.ui index b9371580..4a0bc9ce 100644 --- a/DataPlotly/ui/dataplotly_dockwidget_base.ui +++ b/DataPlotly/ui/dataplotly_dockwidget_base.ui @@ -636,7 +636,7 @@ QListWidget::item::selected { - + threshold @@ -774,7 +774,7 @@ QListWidget::item::selected { - + Fill From cd32d5468adf822dabbc9d61fec332cc77f8478f Mon Sep 17 00:00:00 2001 From: Sophie Aubier Date: Wed, 12 Mar 2025 11:35:12 +0100 Subject: [PATCH 03/24] Set max threshold value & adjust QDoubleSpinBox size --- DataPlotly/ui/dataplotly_dockwidget_base.ui | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/DataPlotly/ui/dataplotly_dockwidget_base.ui b/DataPlotly/ui/dataplotly_dockwidget_base.ui index 4a0bc9ce..8fdd948f 100644 --- a/DataPlotly/ui/dataplotly_dockwidget_base.ui +++ b/DataPlotly/ui/dataplotly_dockwidget_base.ui @@ -320,7 +320,7 @@ QListWidget::item::selected { 0 - -191 + 0 673 1200 @@ -638,7 +638,7 @@ QListWidget::item::selected { - threshold + Threshold @@ -915,8 +915,12 @@ QListWidget::item::selected { - - + + + + 99990000.000000000000000 + +
@@ -960,8 +964,8 @@ QListWidget::item::selected { 0 0 - 687 - 742 + 449 + 791 From 9779ee86621c303dffce9228106774928e93c93f Mon Sep 17 00:00:00 2001 From: Sophie Aubier Date: Wed, 12 Mar 2025 12:17:42 +0100 Subject: [PATCH 04/24] add radar icons --- DataPlotly/core/plot_types/icons/radar.svg | 1686 ++++++++++++++++++++ DataPlotly/core/plot_types/radar.py | 4 +- 2 files changed, 1689 insertions(+), 1 deletion(-) create mode 100644 DataPlotly/core/plot_types/icons/radar.svg diff --git a/DataPlotly/core/plot_types/icons/radar.svg b/DataPlotly/core/plot_types/icons/radar.svg new file mode 100644 index 00000000..a579f55d --- /dev/null +++ b/DataPlotly/core/plot_types/icons/radar.svg @@ -0,0 +1,1686 @@ + + + +image/svg+xml diff --git a/DataPlotly/core/plot_types/radar.py b/DataPlotly/core/plot_types/radar.py index ecc789d3..1b7cc4e6 100644 --- a/DataPlotly/core/plot_types/radar.py +++ b/DataPlotly/core/plot_types/radar.py @@ -30,12 +30,14 @@ def name(): @staticmethod def icon(): - return QIcon(os.path.join(os.path.dirname(__file__), 'icons/polar.svg')) + return QIcon(os.path.join(os.path.dirname(__file__), 'icons/radar.svg')) @staticmethod def create_trace(settings): + radar_plot_list = [] x = settings.x[0] + # Sample colors from the color scale based on the length of settings.y colors_list = pc.sample_colorscale(settings.properties['color_scale'], np.linspace(0, 1, len(settings.y))) From 03936164344ff272787ca3da1da87c8846b0f1c2 Mon Sep 17 00:00:00 2001 From: Sophie Aubier Date: Thu, 13 Mar 2025 09:44:22 +0100 Subject: [PATCH 05/24] Load configuration settings added --- DataPlotly/core/plot_settings.py | 5 ++- DataPlotly/gui/plot_settings_widget.py | 43 ++++++++++++++------------ 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/DataPlotly/core/plot_settings.py b/DataPlotly/core/plot_settings.py index e695297c..40f56da5 100644 --- a/DataPlotly/core/plot_settings.py +++ b/DataPlotly/core/plot_settings.py @@ -101,6 +101,7 @@ def __init__(self, plot_type: str = 'scatter', properties: dict = None, layout: 'x_name': '', 'y_name': '', 'z_name': '', + 'y_combo_radar_label': '', 'in_color': '#8ebad9', 'out_color': '#1f77b4', 'marker_width': 1, @@ -136,7 +137,9 @@ def __init__(self, plot_type: str = 'scatter', properties: dict = None, layout: 'layout_filter_by_map': False, 'layout_filter_by_atlas': False, 'pie_hole': 0, - 'fill' : None + 'fill' : None, + 'line_type_threshold': '', + 'threshold_value': '', } diff --git a/DataPlotly/gui/plot_settings_widget.py b/DataPlotly/gui/plot_settings_widget.py index 621f874f..0ee67f58 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') @@ -493,17 +492,16 @@ 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 : field_names = [field.name() for field in layer.fields()] self.y_fields_combo.addItems(field_names) - buttons = self.findChildren(QgsPropertyOverrideButton) for button in buttons: button.setVectorLayer(layer) @@ -644,7 +642,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') @@ -931,20 +928,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'], @@ -1149,10 +1146,10 @@ def get_settings(self) -> PlotSettings: # pylint: disable=R0915 'fill': self.fill.isChecked(), 'threshold': self.threshold.isChecked(), 'y_combo_radar_label': self.y_combo_radar_label.currentText(), - 'line_type_threshold': self.line_types2[self.line_type_threshold.currentText()], - 'threshold_value': self.threshold_value.value() + 'line_type_threshold': self.line_type_threshold.currentText(), + 'threshold_value': self.threshold_value.value(), + 'y_fields_combo': self.y_fields_combo.currentText() } - if self.ptype == 'radar': plot_properties['y_name'] = "array(" + ", ".join([f'"{field_name}"' for field_name in self.y_fields_combo.checkedItems()]) + ")" plot_properties['x_name'] = "array(" + ", ".join([f"'{field_name}'" for field_name in self.y_fields_combo.checkedItems()]) + ")" @@ -1172,6 +1169,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(), @@ -1216,7 +1214,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, @@ -1383,13 +1380,22 @@ 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)) + self.y_fields_combo.setCurrentText(settings.properties.get('y_fields_combo', '')) + + for name in self.y_fields_combo.currentText().split(self.y_fields_combo.separator()): + self.y_fields_combo.setItemCheckState(self.y_fields_combo.findText(name), Qt.CheckState.Checked) + + self.y_combo_radar_label.setExpression(settings.properties.get('y_combo_radar_label', '')) + self.line_type_threshold.setCurrentText(settings.properties.get('line_type_threshold', 'Solid Line')) + self.threshold_value.setValue(settings.properties.get('threshold_value', 1)) + self.fill.setChecked(settings.properties.get('fill', False)) + self.threshold.setChecked(settings.properties.get('threshold', 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(), @@ -1397,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}' @@ -1630,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"]: @@ -1645,7 +1649,6 @@ def showPlotFromDic(self, plot_input_dic): 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) From 90790db6889fc0d08b88d89cafd75257c773e1f0 Mon Sep 17 00:00:00 2001 From: Sophie Aubier Date: Thu, 13 Mar 2025 14:48:10 +0100 Subject: [PATCH 06/24] Add font style management --- DataPlotly/core/plot_settings.py | 1 - DataPlotly/core/plot_types/radar.py | 19 +++++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/DataPlotly/core/plot_settings.py b/DataPlotly/core/plot_settings.py index 40f56da5..74ccac13 100644 --- a/DataPlotly/core/plot_settings.py +++ b/DataPlotly/core/plot_settings.py @@ -180,7 +180,6 @@ def __init__(self, plot_type: str = 'scatter', properties: dict = None, layout: 'range_slider': {'borderwidth': 1, 'visible': False}, 'bargaps': 0, 'polar': {'angularaxis': {'direction': 'clockwise'}}, - 'radar': {'angularaxis': {'direction': 'clockwise'}}, 'additional_info_expression': '', 'bins_check': False, 'gridcolor': '#bdbfc0' diff --git a/DataPlotly/core/plot_types/radar.py b/DataPlotly/core/plot_types/radar.py index 1b7cc4e6..85e2c607 100644 --- a/DataPlotly/core/plot_types/radar.py +++ b/DataPlotly/core/plot_types/radar.py @@ -88,6 +88,21 @@ def create_trace(settings): def create_layout(settings): layout = super(RadarChartFactory, RadarChartFactory).create_layout(settings) - layout['polar'] = settings.layout['radar'] - + 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 From eddb2d680bde8ce634f51f7c67643e659658b6ee Mon Sep 17 00:00:00 2001 From: Sophie Aubier Date: Thu, 13 Mar 2025 15:28:17 +0100 Subject: [PATCH 07/24] Adjust widget size for threshold --- DataPlotly/ui/dataplotly_dockwidget_base.ui | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/DataPlotly/ui/dataplotly_dockwidget_base.ui b/DataPlotly/ui/dataplotly_dockwidget_base.ui index 8fdd948f..e522bb3e 100644 --- a/DataPlotly/ui/dataplotly_dockwidget_base.ui +++ b/DataPlotly/ui/dataplotly_dockwidget_base.ui @@ -598,9 +598,6 @@ QListWidget::item::selected { - - - @@ -672,13 +669,6 @@ QListWidget::item::selected { - - - - Threshold value - - - @@ -922,6 +912,16 @@ QListWidget::item::selected { + + + + + + + Threshold value + + + @@ -965,7 +965,7 @@ QListWidget::item::selected { 0 0 449 - 791 + 820 From 566eb6f2792c69039d71ccf75d6cac2c0d1c6fe0 Mon Sep 17 00:00:00 2001 From: Sophie Aubier Date: Thu, 13 Mar 2025 17:45:03 +0100 Subject: [PATCH 08/24] manage CLI radar option --- DataPlotly/core/plot_types/radar.py | 12 ++++++------ DataPlotly/gui/plot_settings_widget.py | 8 +++++++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/DataPlotly/core/plot_types/radar.py b/DataPlotly/core/plot_types/radar.py index 85e2c607..8a77da13 100644 --- a/DataPlotly/core/plot_types/radar.py +++ b/DataPlotly/core/plot_types/radar.py @@ -12,8 +12,7 @@ from qgis.PyQt.QtGui import QIcon from DataPlotly.core.plot_types.plot_type import PlotType import plotly.colors as pc -import matplotlib.cm as cm -import matplotlib.colors as mcolors + import numpy as np class RadarChartFactory(PlotType): """ @@ -35,7 +34,9 @@ def icon(): @staticmethod def create_trace(settings): - radar_plot_list = [] + if len(settings.x) == 0: + return [] + radar_plot_list = [] x = settings.x[0] # Sample colors from the color scale based on the length of settings.y @@ -52,7 +53,6 @@ def create_trace(settings): line_type_list.append(settings.properties['line_type_threshold']) for (y, name, colors_list, line_type_list) in zip(settings.y, 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= x+[x[0]] @@ -75,13 +75,13 @@ def create_trace(settings): 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 + "dash": line_type_list }, opacity=settings.properties['opacity'], fill="toself" if settings.properties['fill'] else None )) - + return radar_plot_list @staticmethod diff --git a/DataPlotly/gui/plot_settings_widget.py b/DataPlotly/gui/plot_settings_widget.py index 0ee67f58..35f2a1d6 100644 --- a/DataPlotly/gui/plot_settings_widget.py +++ b/DataPlotly/gui/plot_settings_widget.py @@ -1386,7 +1386,7 @@ def set_settings(self, settings: PlotSettings): # pylint: disable=too-many-stat self.y_fields_combo.setItemCheckState(self.y_fields_combo.findText(name), Qt.CheckState.Checked) self.y_combo_radar_label.setExpression(settings.properties.get('y_combo_radar_label', '')) - self.line_type_threshold.setCurrentText(settings.properties.get('line_type_threshold', 'Solid Line')) + self.line_type_threshold.setCurrentText(settings.properties.get('line_type_threshold', 'Dash Line')) self.threshold_value.setValue(settings.properties.get('threshold_value', 1)) self.fill.setChecked(settings.properties.get('fill', False)) self.threshold.setChecked(settings.properties.get('threshold', False)) @@ -1643,6 +1643,12 @@ 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"]: + #self.y_fields_combo.setCurrentText(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 From f2e54a8ba4cc8325a65334ba381f610811157fbc Mon Sep 17 00:00:00 2001 From: Sophie Aubier Date: Fri, 14 Mar 2025 15:31:31 +0100 Subject: [PATCH 09/24] fixup! Load configuration settings added --- DataPlotly/core/plot_factory.py | 2 -- DataPlotly/core/plot_settings.py | 7 ++++--- DataPlotly/core/plot_types/radar.py | 7 +++---- DataPlotly/gui/plot_settings_widget.py | 15 +++++++++------ 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/DataPlotly/core/plot_factory.py b/DataPlotly/core/plot_factory.py index 3f2b7961..5bac4b79 100644 --- a/DataPlotly/core/plot_factory.py +++ b/DataPlotly/core/plot_factory.py @@ -717,7 +717,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: @@ -760,7 +759,6 @@ def build_figures(self, plot_type, ptrace, config=None) -> str: figures = go.Figure(data=ptrace, layout=self.layout) else: figures = go.Figure(data=ptrace, layout=self.layout) - print(ptrace) # set some configurations if config is None: diff --git a/DataPlotly/core/plot_settings.py b/DataPlotly/core/plot_settings.py index 74ccac13..34cb9fb6 100644 --- a/DataPlotly/core/plot_settings.py +++ b/DataPlotly/core/plot_settings.py @@ -137,9 +137,10 @@ def __init__(self, plot_type: str = 'scatter', properties: dict = None, layout: 'layout_filter_by_map': False, 'layout_filter_by_atlas': False, 'pie_hole': 0, - 'fill' : None, - 'line_type_threshold': '', - 'threshold_value': '', + 'fill': None, + 'line_type_threshold': 'Dot Line', + 'threshold_value': '1', + 'threshold': True } diff --git a/DataPlotly/core/plot_types/radar.py b/DataPlotly/core/plot_types/radar.py index 8a77da13..20ad96d4 100644 --- a/DataPlotly/core/plot_types/radar.py +++ b/DataPlotly/core/plot_types/radar.py @@ -39,11 +39,10 @@ def create_trace(settings): radar_plot_list = [] x = settings.x[0] - # Sample colors from the color scale based on the length of settings.y - colors_list = pc.sample_colorscale(settings.properties['color_scale'], np.linspace(0, 1, len(settings.y))) - + # Sample colors from the color scale based on the length of settings.y + colors_list = pc.sample_colorscale(settings.properties['color_scale'], np.linspace(0, 1, len(settings.y[0]))) # List repeating the line type for each element in settings.y - line_type_list = [settings.properties['line_dash']] * len(settings.y[0]) + line_type_list = [settings.properties['line_dash']] * len(settings.y) # Add a black color and a threshold line to the data if settings.properties['threshold'] is True : diff --git a/DataPlotly/gui/plot_settings_widget.py b/DataPlotly/gui/plot_settings_widget.py index 35f2a1d6..aeb36c00 100644 --- a/DataPlotly/gui/plot_settings_widget.py +++ b/DataPlotly/gui/plot_settings_widget.py @@ -727,7 +727,8 @@ def refreshWidgets(self): # pylint: disable=too-many-statements,too-many-branch ]) self.line_combo.clear() - for k, v in self.line_types.items(): + self.line_type_threshold.clear() + for k, v in self.line_types2.items(): self.line_combo.addItem(k, v) self.line_type_threshold.addItem(k,v) @@ -1146,7 +1147,7 @@ def get_settings(self) -> PlotSettings: # pylint: disable=R0915 'fill': self.fill.isChecked(), 'threshold': self.threshold.isChecked(), 'y_combo_radar_label': self.y_combo_radar_label.currentText(), - 'line_type_threshold': self.line_type_threshold.currentText(), + 'line_type_threshold': self.line_types2[self.line_type_threshold.currentText()], 'threshold_value': self.threshold_value.value(), 'y_fields_combo': self.y_fields_combo.currentText() } @@ -1385,11 +1386,14 @@ def set_settings(self, settings: PlotSettings): # pylint: disable=too-many-stat for name in self.y_fields_combo.currentText().split(self.y_fields_combo.separator()): self.y_fields_combo.setItemCheckState(self.y_fields_combo.findText(name), Qt.CheckState.Checked) + self.line_type_threshold.setCurrentText( + settings.properties.get('line_type_threshold', 'Dash Line')) + self.threshold.setChecked( + settings.properties.get('threshold',True)) self.y_combo_radar_label.setExpression(settings.properties.get('y_combo_radar_label', '')) - self.line_type_threshold.setCurrentText(settings.properties.get('line_type_threshold', 'Dash Line')) + 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)) - self.threshold.setChecked(settings.properties.get('threshold', False)) def create_plot_factory(self) -> PlotFactory: """ @@ -1455,7 +1459,7 @@ def create_plot(self): if self.subcombo.currentData() == 'single': # plot single plot, check the object dictionary length - if len(self.plot_factories) <= 1 or self.ptype == 'radar' : + 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 @@ -1646,7 +1650,6 @@ def showPlotFromDic(self, plot_input_dic): 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"]: - #self.y_fields_combo.setCurrentText(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 From f70d68a5cfe13388df84406b2831efea7baab409 Mon Sep 17 00:00:00 2001 From: Jacky Volpes Date: Fri, 28 Mar 2025 15:59:16 +0100 Subject: [PATCH 10/24] minor refacto for a better y_radar_values management --- DataPlotly/core/plot_factory.py | 18 +++++++++++++++++- DataPlotly/core/plot_settings.py | 1 + DataPlotly/core/plot_types/radar.py | 19 ++++++++++--------- DataPlotly/gui/plot_settings_widget.py | 12 +++--------- 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/DataPlotly/core/plot_factory.py b/DataPlotly/core/plot_factory.py index 5bac4b79..604277ad 100644 --- a/DataPlotly/core/plot_factory.py +++ b/DataPlotly/core/plot_factory.py @@ -163,9 +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_needs_geom, y_label_attrs = add_source_field_or_expression(self.settings.properties['y_combo_radar_label']) if \ + 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()) @@ -174,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() @@ -234,6 +240,7 @@ def add_source_field_or_expression(field_or_expression): 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()): @@ -282,6 +289,12 @@ def add_source_field_or_expression(field_or_expression): 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)) @@ -297,6 +310,8 @@ def add_source_field_or_expression(field_or_expression): 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'] @@ -356,6 +371,7 @@ def add_source_field_or_expression(field_or_expression): 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: diff --git a/DataPlotly/core/plot_settings.py b/DataPlotly/core/plot_settings.py index 34cb9fb6..55d13c7d 100644 --- a/DataPlotly/core/plot_settings.py +++ b/DataPlotly/core/plot_settings.py @@ -212,6 +212,7 @@ def __init__(self, plot_type: str = 'scatter', properties: dict = None, layout: 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/radar.py b/DataPlotly/core/plot_types/radar.py index 20ad96d4..352465ba 100644 --- a/DataPlotly/core/plot_types/radar.py +++ b/DataPlotly/core/plot_types/radar.py @@ -34,28 +34,29 @@ def icon(): @staticmethod def create_trace(settings): - if len(settings.x) == 0: + if len(settings.y_radar_values) == 0: return [] - radar_plot_list = [] - x = settings.x[0] + + x = settings.properties["y_fields_combo"].split(", ") # Sample colors from the color scale based on the length of settings.y - colors_list = pc.sample_colorscale(settings.properties['color_scale'], np.linspace(0, 1, len(settings.y[0]))) + 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 - line_type_list = [settings.properties['line_dash']] * len(settings.y) + 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'] is True : colors_list.append('#000000') - settings.y.append([settings.properties['threshold_value']] * len(settings.y[0])) + settings.y.append([settings.properties['threshold_value']] * len(settings.y_radar_values[0])) settings.y_radar_labels.append('threshold') line_type_list.append(settings.properties['line_type_threshold']) - for (y, name, colors_list, line_type_list) in zip(settings.y, settings.y_radar_labels, colors_list, line_type_list): + 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= x+[x[0]] - y = y+[y[0]] + x.append(x[0]) + y.append(y[0]) radar_plot_list.append(graph_objs.Scatterpolar( r=y, diff --git a/DataPlotly/gui/plot_settings_widget.py b/DataPlotly/gui/plot_settings_widget.py index aeb36c00..2a0c761f 100644 --- a/DataPlotly/gui/plot_settings_widget.py +++ b/DataPlotly/gui/plot_settings_widget.py @@ -500,8 +500,7 @@ def selected_layer_changed(self, layer): self.additional_info_combo.setLayer(layer) if layer is not None : - field_names = [field.name() for field in layer.fields()] - self.y_fields_combo.addItems(field_names) + self.y_fields_combo.addItems([field.name() for field in layer.fields()]) buttons = self.findChildren(QgsPropertyOverrideButton) for button in buttons: button.setVectorLayer(layer) @@ -1149,11 +1148,8 @@ def get_settings(self) -> PlotSettings: # pylint: disable=R0915 'y_combo_radar_label': self.y_combo_radar_label.currentText(), 'line_type_threshold': self.line_types2[self.line_type_threshold.currentText()], 'threshold_value': self.threshold_value.value(), - 'y_fields_combo': self.y_fields_combo.currentText() + 'y_fields_combo': ', '.join(self.y_fields_combo.checkedItems()) } - if self.ptype == 'radar': - plot_properties['y_name'] = "array(" + ", ".join([f'"{field_name}"' for field_name in self.y_fields_combo.checkedItems()]) + ")" - plot_properties['x_name'] = "array(" + ", ".join([f"'{field_name}'" for field_name in self.y_fields_combo.checkedItems()]) + ")" if self.in_color_defined_button.isActive(): plot_properties['color_scale_data_defined_in_check'] = self.color_scale_data_defined_in_check.isChecked() @@ -1382,10 +1378,8 @@ def set_settings(self, settings: PlotSettings): # pylint: disable=too-many-stat QColor(settings.layout.get('gridcolor') or '#bdbfc0')) self.pie_hole.setValue(settings.properties.get('pie_hole', 0)) self.y_fields_combo.setCurrentText(settings.properties.get('y_fields_combo', '')) - - for name in self.y_fields_combo.currentText().split(self.y_fields_combo.separator()): + for name in self.y_fields_combo.currentText().split(', '): self.y_fields_combo.setItemCheckState(self.y_fields_combo.findText(name), Qt.CheckState.Checked) - self.line_type_threshold.setCurrentText( settings.properties.get('line_type_threshold', 'Dash Line')) self.threshold.setChecked( From 05d0d039530fa8e28c7c02ad5f0abada01718ac9 Mon Sep 17 00:00:00 2001 From: Jacky Volpes Date: Fri, 28 Mar 2025 19:20:56 +0100 Subject: [PATCH 11/24] correct default settings --- DataPlotly/core/plot_settings.py | 10 +++++----- DataPlotly/gui/plot_settings_widget.py | 5 +++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/DataPlotly/core/plot_settings.py b/DataPlotly/core/plot_settings.py index 55d13c7d..90856f9e 100644 --- a/DataPlotly/core/plot_settings.py +++ b/DataPlotly/core/plot_settings.py @@ -102,6 +102,7 @@ def __init__(self, plot_type: str = 'scatter', properties: dict = None, layout: 'y_name': '', 'z_name': '', 'y_combo_radar_label': '', + 'y_fields_combo': '', 'in_color': '#8ebad9', 'out_color': '#1f77b4', 'marker_width': 1, @@ -137,11 +138,10 @@ def __init__(self, plot_type: str = 'scatter', properties: dict = None, layout: 'layout_filter_by_map': False, 'layout_filter_by_atlas': False, 'pie_hole': 0, - 'fill': None, - 'line_type_threshold': 'Dot Line', - 'threshold_value': '1', - 'threshold': True - + 'fill': False, + 'line_type_threshold': 'dot', + 'threshold_value': 1, + 'threshold': False } # layout nested dictionary diff --git a/DataPlotly/gui/plot_settings_widget.py b/DataPlotly/gui/plot_settings_widget.py index 2a0c761f..63d5878b 100644 --- a/DataPlotly/gui/plot_settings_widget.py +++ b/DataPlotly/gui/plot_settings_widget.py @@ -1380,8 +1380,9 @@ def set_settings(self, settings: PlotSettings): # pylint: disable=too-many-stat self.y_fields_combo.setCurrentText(settings.properties.get('y_fields_combo', '')) for name in self.y_fields_combo.currentText().split(', '): self.y_fields_combo.setItemCheckState(self.y_fields_combo.findText(name), Qt.CheckState.Checked) - self.line_type_threshold.setCurrentText( - settings.properties.get('line_type_threshold', 'Dash Line')) + self.line_type_threshold.setCurrentIndex(self.line_type_threshold.findData( + settings.properties.get('line_type_threshold', 'dot') + )) self.threshold.setChecked( settings.properties.get('threshold',True)) self.y_combo_radar_label.setExpression(settings.properties.get('y_combo_radar_label', '')) From 6869ed3639fe127fa34c0f89540e693f2d432688 Mon Sep 17 00:00:00 2001 From: Jacky Volpes Date: Fri, 28 Mar 2025 19:49:01 +0100 Subject: [PATCH 12/24] fix bad variable usage --- DataPlotly/core/plot_types/radar.py | 6 +++--- DataPlotly/gui/plot_settings_widget.py | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/DataPlotly/core/plot_types/radar.py b/DataPlotly/core/plot_types/radar.py index 352465ba..0eca5f02 100644 --- a/DataPlotly/core/plot_types/radar.py +++ b/DataPlotly/core/plot_types/radar.py @@ -39,15 +39,15 @@ def create_trace(settings): x = settings.properties["y_fields_combo"].split(", ") - # Sample colors from the color scale based on the length of settings.y + # 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 + # 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'] is True : colors_list.append('#000000') - settings.y.append([settings.properties['threshold_value']] * len(settings.y_radar_values[0])) + settings.y_radar_values.append([settings.properties['threshold_value']] * len(settings.y_radar_values[0])) settings.y_radar_labels.append('threshold') line_type_list.append(settings.properties['line_type_threshold']) diff --git a/DataPlotly/gui/plot_settings_widget.py b/DataPlotly/gui/plot_settings_widget.py index 63d5878b..f48b5b75 100644 --- a/DataPlotly/gui/plot_settings_widget.py +++ b/DataPlotly/gui/plot_settings_widget.py @@ -1377,14 +1377,13 @@ 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)) - self.y_fields_combo.setCurrentText(settings.properties.get('y_fields_combo', '')) - for name in self.y_fields_combo.currentText().split(', '): + 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_type_threshold.setCurrentIndex(self.line_type_threshold.findData( settings.properties.get('line_type_threshold', 'dot') )) self.threshold.setChecked( - settings.properties.get('threshold',True)) + settings.properties.get('threshold', True)) 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)) From cea195a13382cc9405b0d05dba4e1d36a2c9fee4 Mon Sep 17 00:00:00 2001 From: soaubier <117665766+soaubier@users.noreply.github.com> Date: Tue, 15 Apr 2025 10:20:35 +0200 Subject: [PATCH 13/24] Update DataPlotly/core/plot_types/radar.py Co-authored-by: Jacky Volpes <34267385+Djedouas@users.noreply.github.com> --- DataPlotly/core/plot_types/radar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DataPlotly/core/plot_types/radar.py b/DataPlotly/core/plot_types/radar.py index 0eca5f02..31acc864 100644 --- a/DataPlotly/core/plot_types/radar.py +++ b/DataPlotly/core/plot_types/radar.py @@ -45,7 +45,7 @@ def create_trace(settings): 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'] is True : + 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('threshold') From 7344c5adf17fcb16aff15a360c2286b5d351945a Mon Sep 17 00:00:00 2001 From: soaubier <117665766+soaubier@users.noreply.github.com> Date: Tue, 15 Apr 2025 10:40:21 +0200 Subject: [PATCH 14/24] Update DataPlotly/gui/plot_settings_widget.py --- DataPlotly/gui/plot_settings_widget.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DataPlotly/gui/plot_settings_widget.py b/DataPlotly/gui/plot_settings_widget.py index f48b5b75..890e8630 100644 --- a/DataPlotly/gui/plot_settings_widget.py +++ b/DataPlotly/gui/plot_settings_widget.py @@ -458,7 +458,7 @@ def data_defined_color_updated(self): # if data defined button is active if self.in_color_defined_button.isActive(): # if plot is type for which using an expression for the color selection makes sense - if self.ptype in ['scatter', 'bar', 'pie', 'ternary', 'histogram', 'radar']: + if self.ptype in ['scatter', 'bar', 'pie', 'ternary', 'histogram']: self.in_color_combo.setEnabled(False) self.color_scale_data_defined_in.setVisible(True) self.color_scale_data_defined_in.setEnabled(True) From cdb9578dcb25ffabe61c9111025eeffd9c727e76 Mon Sep 17 00:00:00 2001 From: Sophie Aubier Date: Tue, 15 Apr 2025 11:13:57 +0200 Subject: [PATCH 15/24] review --- DataPlotly/gui/plot_settings_widget.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/DataPlotly/gui/plot_settings_widget.py b/DataPlotly/gui/plot_settings_widget.py index 890e8630..6f708bae 100644 --- a/DataPlotly/gui/plot_settings_widget.py +++ b/DataPlotly/gui/plot_settings_widget.py @@ -672,8 +672,8 @@ def refreshWidgets(self): # pylint: disable=too-many-statements,too-many-branch # ScatterPlot marker types self.marker_types = OrderedDict([ - (self.tr('Lines'), 'lines'), (self.tr('Points'), 'markers'), + (self.tr('Lines'), 'lines'), (self.tr('Points and Lines'), 'lines+markers') ]) self.marker_type_combo.clear() @@ -727,10 +727,12 @@ def refreshWidgets(self): # pylint: disable=too-many-statements,too-many-branch self.line_combo.clear() self.line_type_threshold.clear() - for k, v in self.line_types2.items(): + for k, v in self.line_types.items(): self.line_combo.addItem(k, v) self.line_type_threshold.addItem(k,v) + + # BarPlot bar mode self.bar_mode_combo.clear() self.bar_mode_combo.addItem(self.tr('Grouped'), 'group') From 4518d1d4ba0900725e3c4e07fb610377a66c56af Mon Sep 17 00:00:00 2001 From: Sophie Aubier Date: Tue, 15 Apr 2025 14:25:02 +0200 Subject: [PATCH 16/24] add traduction to radar.py --- DataPlotly/core/plot_types/radar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DataPlotly/core/plot_types/radar.py b/DataPlotly/core/plot_types/radar.py index 31acc864..51be4af6 100644 --- a/DataPlotly/core/plot_types/radar.py +++ b/DataPlotly/core/plot_types/radar.py @@ -48,7 +48,7 @@ def create_trace(settings): 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('threshold') + settings.y_radar_labels.append(QCoreApplication.translate('DataPlotly', 'threshold')) line_type_list.append(settings.properties['line_type_threshold']) radar_plot_list = [] From af9f51fddad622c83b8616677e014b2bb9c4674b Mon Sep 17 00:00:00 2001 From: Sophie Aubier Date: Tue, 15 Apr 2025 14:35:50 +0200 Subject: [PATCH 17/24] radar svg update --- DataPlotly/core/plot_types/icons/radar.svg | 156 ++++++++++++++++----- 1 file changed, 120 insertions(+), 36 deletions(-) diff --git a/DataPlotly/core/plot_types/icons/radar.svg b/DataPlotly/core/plot_types/icons/radar.svg index a579f55d..6261c28a 100644 --- a/DataPlotly/core/plot_types/icons/radar.svg +++ b/DataPlotly/core/plot_types/icons/radar.svg @@ -433,7 +433,9 @@ in="result10" mode="normal" in2="result6" - id="feBlend4865" />