QGIS API Documentation 4.1.0-Master (376402f9aeb)
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
27
28void QgsVectorLayerXyPlotDataGatherer::setSeriesDetails( const QList<QgsVectorLayerXyPlotDataGatherer::XySeriesDetails> &seriesDetails )
29{
30 mSeriesDetails = seriesDetails;
31}
32
33void QgsVectorLayerXyPlotDataGatherer::setPredefinedCategories( const QStringList &predefinedCategories )
34{
35 mPredefinedCategories = predefinedCategories;
36}
37
39{
40 mXAxisType = xAxisType;
41}
42
44{
45 QStringList gatheredCategories;
46 QList<QMap<QString, double>> gatheredSeriesCategoriesSum;
47 gatheredSeriesCategoriesSum.reserve( mSeriesDetails.size() );
48 std::vector<std::unique_ptr<QgsXyPlotSeries>> gatheredSeries;
49 gatheredSeries.reserve( mSeriesDetails.size() );
50 for ( int i = 0; i < mSeriesDetails.size(); i++ )
51 {
52 auto series = std::make_unique<QgsXyPlotSeries>();
53 gatheredSeries.emplace_back( std::move( series ) );
54 gatheredSeriesCategoriesSum << QMap<QString, double>();
55 }
56
57 QMap<QString, QgsExpression> preparedExpressions;
58 QgsFeature feature;
59 while ( mIterator.nextFeature( feature ) )
60 {
61 mExpressionContext.setFeature( feature );
62
63 int seriesIndex = -1;
64 for ( const XySeriesDetails &seriesDetails : mSeriesDetails )
65 {
66 seriesIndex++;
67 if ( !seriesDetails.filterExpression.isEmpty() )
68 {
69 auto filterExpressionIt = preparedExpressions.find( seriesDetails.filterExpression );
70 if ( filterExpressionIt == preparedExpressions.end() )
71 {
72 filterExpressionIt = preparedExpressions.insert( seriesDetails.filterExpression, QgsExpression( seriesDetails.filterExpression ) );
73 filterExpressionIt->prepare( &mExpressionContext );
74 }
75
76 if ( !filterExpressionIt->evaluate( &mExpressionContext ).toBool() )
77 {
78 continue;
79 }
80 }
81
82 auto xExpressionIt = preparedExpressions.find( seriesDetails.xExpression );
83 if ( xExpressionIt == preparedExpressions.end() )
84 {
85 xExpressionIt = preparedExpressions.insert( seriesDetails.xExpression, QgsExpression( seriesDetails.xExpression ) );
86 xExpressionIt->prepare( &mExpressionContext );
87 }
88
89 auto yExpressionIt = preparedExpressions.find( seriesDetails.yExpression );
90 if ( yExpressionIt == preparedExpressions.end() )
91 {
92 yExpressionIt = preparedExpressions.insert( seriesDetails.yExpression, QgsExpression( seriesDetails.yExpression ) );
93 yExpressionIt->prepare( &mExpressionContext );
94 }
95
96 bool ok = false;
97 const double y = yExpressionIt->evaluate( &mExpressionContext ).toDouble( &ok );
98 if ( !ok )
99 {
100 continue;
101 }
102 switch ( mXAxisType )
103 {
105 {
106 const double x = xExpressionIt->evaluate( &mExpressionContext ).toDouble( &ok );
107 if ( !ok )
108 {
109 continue;
110 }
111
112 gatheredSeries[seriesIndex]->append( x, y );
113 break;
114 }
115
117 {
118 const QString category = xExpressionIt->evaluate( &mExpressionContext ).toString();
119 if ( category.isEmpty() )
120 {
121 continue;
122 }
123
124 double x = -1;
125 if ( !mPredefinedCategories.isEmpty() )
126 {
127 x = mPredefinedCategories.indexOf( category );
128 }
129 else
130 {
131 if ( !gatheredCategories.contains( category ) )
132 {
133 gatheredCategories << category;
134 }
135 x = gatheredCategories.indexOf( category );
136 }
137
138 if ( x == -1 )
139 {
140 continue;
141 }
142
143 auto gatheredSeriesCategoriesSumIt = gatheredSeriesCategoriesSum[seriesIndex].find( category );
144 if ( gatheredSeriesCategoriesSumIt == gatheredSeriesCategoriesSum[seriesIndex].end() )
145 {
146 gatheredSeriesCategoriesSumIt = gatheredSeriesCategoriesSum[seriesIndex].insert( category, y );
147 *gatheredSeriesCategoriesSumIt = y;
148 }
149 else
150 {
151 *gatheredSeriesCategoriesSumIt += y;
152 }
153 }
154 }
155
156 if ( isCanceled() )
157 return false;
158 }
159 }
160
161 switch ( mXAxisType )
162 {
164 {
165 int seriesIndex = -1;
166 for ( QMap<QString, double> &gatheredCategoriesSum : gatheredSeriesCategoriesSum )
167 {
168 seriesIndex++;
169 if ( !mPredefinedCategories.isEmpty() )
170 {
171 for ( int i = 0; i < mPredefinedCategories.size(); i++ )
172 {
173 auto gatheredCategoriesSumIt = gatheredCategoriesSum.find( mPredefinedCategories[i] );
174 if ( gatheredCategoriesSumIt != gatheredCategoriesSum.end() )
175 {
176 gatheredSeries[seriesIndex]->append( i, *gatheredCategoriesSumIt );
177 }
178 }
179 }
180 else if ( !gatheredCategories.isEmpty() )
181 {
182 for ( int i = 0; i < gatheredCategories.size(); i++ )
183 {
184 auto gatheredCategoriesSumIt = gatheredCategoriesSum.find( gatheredCategories[i] );
185 if ( gatheredCategoriesSumIt != gatheredCategoriesSum.end() )
186 {
187 gatheredSeries[seriesIndex]->append( i, *gatheredCategoriesSumIt );
188 }
189 }
190 }
191 }
192
193 mData.setCategories( !mPredefinedCategories.isEmpty() ? mPredefinedCategories : gatheredCategories );
194 break;
195 }
196
198 break;
199 }
200
201 int seriesIndex = 0;
202 for ( std::unique_ptr<QgsXyPlotSeries> &series : gatheredSeries )
203 {
204 series->setName( mSeriesDetails[seriesIndex++].name );
205 mData.addSeries( series.release() );
206 }
207
208 return true;
209}
210
PlotAxisType
Plots axis types.
Definition qgis.h:3515
@ Categorical
The axis represents categories.
Definition qgis.h:3517
@ Interval
The axis represents a range of values.
Definition qgis.h:3516
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:303
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 ...
void setXAxisType(Qgis::PlotAxisType xAxisType)
Sets the X-axis type that will defined what type of X values to gather.
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.