QGIS API Documentation 3.99.0-Master (21b3aa880ba)
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 = 0;
60 for ( const XySeriesDetails &seriesDetails : mSeriesDetails )
61 {
62 if ( !seriesDetails.filterExpression.isEmpty() )
63 {
64 auto filterExpressionIt = preparedExpressions.find( seriesDetails.filterExpression );
65 if ( filterExpressionIt == preparedExpressions.end() )
66 {
67 filterExpressionIt = preparedExpressions.insert( seriesDetails.filterExpression, QgsExpression( seriesDetails.filterExpression ) );
68 filterExpressionIt->prepare( &mExpressionContext );
69 }
70
71 if ( !filterExpressionIt->evaluate( &mExpressionContext ).toBool() )
72 {
73 continue;
74 }
75 }
76
77 auto xExpressionIt = preparedExpressions.find( seriesDetails.xExpression );
78 if ( xExpressionIt == preparedExpressions.end() )
79 {
80 xExpressionIt = preparedExpressions.insert( seriesDetails.xExpression, QgsExpression( seriesDetails.xExpression ) );
81 xExpressionIt->prepare( &mExpressionContext );
82 }
83
84 auto yExpressionIt = preparedExpressions.find( seriesDetails.yExpression );
85 if ( yExpressionIt == preparedExpressions.end() )
86 {
87 yExpressionIt = preparedExpressions.insert( seriesDetails.yExpression, QgsExpression( seriesDetails.yExpression ) );
88 yExpressionIt->prepare( &mExpressionContext );
89 }
90
91 bool ok = false;
92 const double y = yExpressionIt->evaluate( &mExpressionContext ).toDouble( &ok );
93 if ( !ok )
94 {
95 continue;
96 }
97 switch ( mXAxisType )
98 {
100 {
101 const double x = xExpressionIt->evaluate( &mExpressionContext ).toDouble( &ok );
102 if ( !ok )
103 {
104 continue;
105 }
106
107 gatheredSeries[seriesIndex]->append( x, y );
108 break;
109 }
110
112 {
113 const QString category = xExpressionIt->evaluate( &mExpressionContext ).toString();
114 if ( category.isEmpty() )
115 {
116 continue;
117 }
118
119 double x = -1;
120 if ( !mPredefinedCategories.isEmpty() )
121 {
122 x = mPredefinedCategories.indexOf( category );
123 }
124 else
125 {
126 if ( !gatheredCategories.contains( category ) )
127 {
128 gatheredCategories << category;
129 }
130 x = gatheredCategories.indexOf( category );
131 }
132
133 if ( x == -1 )
134 {
135 continue;
136 }
137
138 auto gatheredSeriesCategoriesSumIt = gatheredSeriesCategoriesSum[seriesIndex].find( category );
139 if ( gatheredSeriesCategoriesSumIt == gatheredSeriesCategoriesSum[seriesIndex].end() )
140 {
141 gatheredSeriesCategoriesSumIt = gatheredSeriesCategoriesSum[seriesIndex].insert( category, y );
142 *gatheredSeriesCategoriesSumIt = y;
143 }
144 else
145 {
146 *gatheredSeriesCategoriesSumIt += y;
147 }
148 }
149 }
150
151 seriesIndex++;
152 if ( isCanceled() )
153 return false;
154 }
155 }
156
157 switch ( mXAxisType )
158 {
160 {
161 int seriesIndex = 0;
162 for ( QMap<QString, double> &gatheredCategoriesSum : gatheredSeriesCategoriesSum )
163 {
164 if ( !mPredefinedCategories.isEmpty() )
165 {
166 for ( int i = 0; i < mPredefinedCategories.size(); i++ )
167 {
168 auto gatheredCategoriesSumIt = gatheredCategoriesSum.find( mPredefinedCategories[i] );
169 if ( gatheredCategoriesSumIt != gatheredCategoriesSum.end() )
170 {
171 gatheredSeries[seriesIndex]->append( i, *gatheredCategoriesSumIt );
172 }
173 }
174 }
175 else if ( !gatheredCategories.isEmpty() )
176 {
177 for ( int i = 0; i < gatheredCategories.size(); i++ )
178 {
179 auto gatheredCategoriesSumIt = gatheredCategoriesSum.find( gatheredCategories[i] );
180 if ( gatheredCategoriesSumIt != gatheredCategoriesSum.end() )
181 {
182 gatheredSeries[seriesIndex]->append( i, *gatheredCategoriesSumIt );
183 }
184 }
185 }
186 seriesIndex++;
187 }
188
189 mData.setCategories( !mPredefinedCategories.isEmpty() ? mPredefinedCategories : gatheredCategories );
190 break;
191 }
192
194 break;
195 }
196
197 for ( std::unique_ptr<QgsXyPlotSeries> &series : gatheredSeries )
198 {
199 mData.addSeries( series.release() );
200 }
201
202 return true;
203}
204
PlotAxisType
Plots axis types.
Definition qgis.h:3334
@ Categorical
The axis represents categories.
Definition qgis.h:3336
@ Interval
The axis represents a range of values.
Definition qgis.h:3335
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:58
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.