QGIS API Documentation 3.99.0-Master (c22de0620c0)
Loading...
Searching...
No Matches
qgsvectorlayerplotdatagatherer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsvectorlayerplotdatagatherer.cpp
3 -----------------
4 begin : August 2025
5 copyright : (C) 2025 by Mathieu
6 email : mathieu at opengis dot ch
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19
20#include "qgsexpression.h"
21
22#include "moc_qgsvectorlayerplotdatagatherer.cpp"
23
28
29void QgsVectorLayerXyPlotDataGatherer::setSeriesDetails( const QList<QgsVectorLayerXyPlotDataGatherer::XySeriesDetails> &seriesDetails )
30{
31 mSeriesDetails = seriesDetails;
32}
33
34void QgsVectorLayerXyPlotDataGatherer::setPredefinedCategories( const QStringList &predefinedCategories )
35{
36 mPredefinedCategories = predefinedCategories;
37}
38
40{
41 QStringList gatheredCategories;
42 QList<QMap<QString, double>> gatheredSeriesCategoriesSum;
43 gatheredSeriesCategoriesSum.reserve( mSeriesDetails.size() );
44 std::vector<std::unique_ptr<QgsXyPlotSeries>> gatheredSeries;
45 gatheredSeries.reserve( mSeriesDetails.size() );
46 for ( int i = 0; i < mSeriesDetails.size(); i++ )
47 {
48 auto series = std::make_unique<QgsXyPlotSeries>();
49 gatheredSeries.emplace_back( std::move( series ) );
50 gatheredSeriesCategoriesSum << QMap<QString, double>();
51 }
52
53 QMap<QString, QgsExpression> preparedExpressions;
54 QgsFeature feature;
55 while ( mIterator.nextFeature( feature ) )
56 {
57 mExpressionContext.setFeature( feature );
58
59 int seriesIndex = -1;
60 for ( const XySeriesDetails &seriesDetails : mSeriesDetails )
61 {
62 seriesIndex++;
63 if ( !seriesDetails.filterExpression.isEmpty() )
64 {
65 auto filterExpressionIt = preparedExpressions.find( seriesDetails.filterExpression );
66 if ( filterExpressionIt == preparedExpressions.end() )
67 {
68 filterExpressionIt = preparedExpressions.insert( seriesDetails.filterExpression, QgsExpression( seriesDetails.filterExpression ) );
69 filterExpressionIt->prepare( &mExpressionContext );
70 }
71
72 if ( !filterExpressionIt->evaluate( &mExpressionContext ).toBool() )
73 {
74 continue;
75 }
76 }
77
78 auto xExpressionIt = preparedExpressions.find( seriesDetails.xExpression );
79 if ( xExpressionIt == preparedExpressions.end() )
80 {
81 xExpressionIt = preparedExpressions.insert( seriesDetails.xExpression, QgsExpression( seriesDetails.xExpression ) );
82 xExpressionIt->prepare( &mExpressionContext );
83 }
84
85 auto yExpressionIt = preparedExpressions.find( seriesDetails.yExpression );
86 if ( yExpressionIt == preparedExpressions.end() )
87 {
88 yExpressionIt = preparedExpressions.insert( seriesDetails.yExpression, QgsExpression( seriesDetails.yExpression ) );
89 yExpressionIt->prepare( &mExpressionContext );
90 }
91
92 bool ok = false;
93 const double y = yExpressionIt->evaluate( &mExpressionContext ).toDouble( &ok );
94 if ( !ok )
95 {
96 continue;
97 }
98 switch ( mXAxisType )
99 {
101 {
102 const double x = xExpressionIt->evaluate( &mExpressionContext ).toDouble( &ok );
103 if ( !ok )
104 {
105 continue;
106 }
107
108 gatheredSeries[seriesIndex]->append( x, y );
109 break;
110 }
111
113 {
114 const QString category = xExpressionIt->evaluate( &mExpressionContext ).toString();
115 if ( category.isEmpty() )
116 {
117 continue;
118 }
119
120 double x = -1;
121 if ( !mPredefinedCategories.isEmpty() )
122 {
123 x = mPredefinedCategories.indexOf( category );
124 }
125 else
126 {
127 if ( !gatheredCategories.contains( category ) )
128 {
129 gatheredCategories << category;
130 }
131 x = gatheredCategories.indexOf( category );
132 }
133
134 if ( x == -1 )
135 {
136 continue;
137 }
138
139 auto gatheredSeriesCategoriesSumIt = gatheredSeriesCategoriesSum[seriesIndex].find( category );
140 if ( gatheredSeriesCategoriesSumIt == gatheredSeriesCategoriesSum[seriesIndex].end() )
141 {
142 gatheredSeriesCategoriesSumIt = gatheredSeriesCategoriesSum[seriesIndex].insert( category, y );
143 *gatheredSeriesCategoriesSumIt = y;
144 }
145 else
146 {
147 *gatheredSeriesCategoriesSumIt += y;
148 }
149 }
150 }
151
152 if ( isCanceled() )
153 return false;
154 }
155 }
156
157 switch ( mXAxisType )
158 {
160 {
161 int seriesIndex = -1;
162 for ( QMap<QString, double> &gatheredCategoriesSum : gatheredSeriesCategoriesSum )
163 {
164 seriesIndex++;
165 if ( !mPredefinedCategories.isEmpty() )
166 {
167 for ( int i = 0; i < mPredefinedCategories.size(); i++ )
168 {
169 auto gatheredCategoriesSumIt = gatheredCategoriesSum.find( mPredefinedCategories[i] );
170 if ( gatheredCategoriesSumIt != gatheredCategoriesSum.end() )
171 {
172 gatheredSeries[seriesIndex]->append( i, *gatheredCategoriesSumIt );
173 }
174 }
175 }
176 else if ( !gatheredCategories.isEmpty() )
177 {
178 for ( int i = 0; i < gatheredCategories.size(); i++ )
179 {
180 auto gatheredCategoriesSumIt = gatheredCategoriesSum.find( gatheredCategories[i] );
181 if ( gatheredCategoriesSumIt != gatheredCategoriesSum.end() )
182 {
183 gatheredSeries[seriesIndex]->append( i, *gatheredCategoriesSumIt );
184 }
185 }
186 }
187 }
188
189 mData.setCategories( !mPredefinedCategories.isEmpty() ? mPredefinedCategories : gatheredCategories );
190 break;
191 }
192
194 break;
195 }
196
197 int seriesIndex = 0;
198 for ( std::unique_ptr<QgsXyPlotSeries> &series : gatheredSeries )
199 {
200 series->setName( mSeriesDetails[seriesIndex++].name );
201 mData.addSeries( series.release() );
202 }
203
204 return true;
205}
206
PlotAxisType
Plots axis types.
Definition qgis.h:3420
@ Categorical
The axis represents categories.
Definition qgis.h:3422
@ Interval
The axis represents a range of values.
Definition qgis.h:3421
Handles parsing and evaluation of expressions (formerly called "search strings").
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:60
Encapsulates one or more plot series.
Definition qgsplot.h:300
bool isCanceled() const
Will return true if task should terminate ASAP.
QgsPlotData data() const override
Returns the plot data.
void setPredefinedCategories(const QStringList &categories)
Sets the predefined categories list that will be used to restrict the categories used when gathering ...
bool run() override
Performs the task's operation.
void setSeriesDetails(const QList< QgsVectorLayerXyPlotDataGatherer::XySeriesDetails > &details)
Sets the series details list that will be used to prepare the data being gathered.
QgsVectorLayerXyPlotDataGatherer(Qgis::PlotAxisType xAxisType=Qgis::PlotAxisType::Interval)
The vector layer XY plot data gatherer constructor.