QGIS API Documentation 3.99.0-Master (09f76ad7019)
Loading...
Searching...
No Matches
qgsalgorithmuniquevalues.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmuniquevalues.cpp
3 ---------------------
4 begin : May 2025
5 copyright : (C) 2025 by Alexander Bruy
6 email : alexander dot bruy at gmail dot com
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 <QString>
21
22using namespace Qt::StringLiterals;
23
25
26QString QgsUniqueValuesAlgorithm::name() const
27{
28 return u"listuniquevalues"_s;
29}
30
31QString QgsUniqueValuesAlgorithm::displayName() const
32{
33 return QObject::tr( "List unique values" );
34}
35
36QStringList QgsUniqueValuesAlgorithm::tags() const
37{
38 return QObject::tr( "count,unique,values" ).split( ',' );
39}
40
41QString QgsUniqueValuesAlgorithm::group() const
42{
43 return QObject::tr( "Vector analysis" );
44}
45
46QString QgsUniqueValuesAlgorithm::groupId() const
47{
48 return u"vectoranalysis"_s;
49}
50
51QString QgsUniqueValuesAlgorithm::shortHelpString() const
52{
53 return QObject::tr( "This algorithm generates a report with information about the unique values found in a given attribute (or attributes) of a vector layer." );
54}
55
56QString QgsUniqueValuesAlgorithm::shortDescription() const
57{
58 return QObject::tr( "Returns list of unique values in given field(s) of a vector layer." );
59}
60
61QgsUniqueValuesAlgorithm *QgsUniqueValuesAlgorithm::createInstance() const
62{
63 return new QgsUniqueValuesAlgorithm();
64}
65
66void QgsUniqueValuesAlgorithm::initAlgorithm( const QVariantMap & )
67{
68 addParameter( new QgsProcessingParameterFeatureSource( u"INPUT"_s, QObject::tr( "Input layer" ), QList<int>() << static_cast<int>( Qgis::ProcessingSourceType::Vector ) ) );
69 addParameter( new QgsProcessingParameterField( u"FIELDS"_s, QObject::tr( "Target field(s)" ), QVariant(), u"INPUT"_s, Qgis::ProcessingFieldParameterDataType::Any, true ) );
70 addParameter( new QgsProcessingParameterFeatureSink( u"OUTPUT"_s, QObject::tr( "Unique values" ), Qgis::ProcessingSourceType::Vector, QVariant(), true ) );
71 addParameter( new QgsProcessingParameterFileDestination( u"OUTPUT_HTML_FILE"_s, QObject::tr( "HTML report" ), QObject::tr( "HTML files (*.html *.htm)" ), QVariant(), true ) );
72 addOutput( new QgsProcessingOutputNumber( u"TOTAL_VALUES"_s, QObject::tr( "Total unique values" ) ) );
73 addOutput( new QgsProcessingOutputString( u"UNIQUE_VALUES"_s, QObject::tr( "Unique values" ) ) );
74}
75
76QVariantMap QgsUniqueValuesAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
77{
78 std::unique_ptr<QgsProcessingFeatureSource> source( parameterAsSource( parameters, u"INPUT"_s, context ) );
79 if ( !source )
80 throw QgsProcessingException( invalidSourceError( parameters, u"INPUT"_s ) );
81
82 const QStringList fieldNames = parameterAsStrings( parameters, u"FIELDS"_s, context );
83 const QString outputHtml = parameterAsFileOutput( parameters, u"OUTPUT_HTML_FILE"_s, context );
84
85 QgsFields fields;
86 QList<int> fieldIndices;
87
88 for ( const QString &fieldName : fieldNames )
89 {
90 int fieldIndex = source->fields().lookupField( fieldName );
91 if ( fieldIndex < 0 )
92 {
93 feedback->reportError( QObject::tr( "Invalid field name %1" ).arg( fieldName ) );
94 continue;
95 }
96 fields.append( source->fields().at( fieldIndex ) );
97 fieldIndices << fieldIndex;
98 }
99
100 QString dest;
101 std::unique_ptr<QgsFeatureSink> sink( parameterAsSink( parameters, u"OUTPUT"_s, context, dest, fields, Qgis::WkbType::NoGeometry, QgsCoordinateReferenceSystem() ) );
102 if ( !sink )
103 {
104 throw QgsProcessingException( invalidSinkError( parameters, u"OUTPUT"_s ) );
105 }
106
107 QSet<QgsAttributes> values;
108 if ( fieldIndices.size() == 1 )
109 {
110 const QSet<QVariant> unique = source->uniqueValues( fieldIndices.at( 0 ) );
111 for ( const QVariant &v : unique )
112 {
113 values.insert( QgsAttributes() << v );
114 }
115 }
116 else
117 {
118 // we have to scan whole table
119 // TODO: add this support to QgsVectorDataProvider, so we can run it on the backend
120 QgsFeatureRequest request;
122 request.setSubsetOfAttributes( fieldIndices );
123
124 const double step = source->featureCount() > 0 ? 100.0 / source->featureCount() : 0;
125 QgsFeatureIterator features = source->getFeatures( request );
126 QgsFeature f;
127 long long i = 0;
128 while ( features.nextFeature( f ) )
129 {
130 if ( feedback->isCanceled() )
131 break;
132
133 QgsAttributes attrs;
134 for ( auto &i : std::as_const( fieldIndices ) )
135 {
136 attrs << f.attribute( i );
137 }
138 values.insert( attrs );
139
140 i++;
141 feedback->setProgress( i * step );
142 }
143 }
144
145 QVariantMap outputs;
146 outputs.insert( u"TOTAL_VALUES"_s, values.size() );
147
148 QStringList valueList;
149 for ( auto it = values.constBegin(); it != values.constEnd(); ++it )
150 {
151 QStringList s;
152 for ( const QVariant &v : std::as_const( *it ) )
153 {
154 s.append( v.toString() );
155 }
156 valueList.append( s.join( ',' ) );
157 }
158 outputs.insert( u"UNIQUE_VALUES"_s, valueList.join( ';' ) );
159
160 if ( sink )
161 {
162 for ( auto it = values.constBegin(); it != values.constEnd(); ++it )
163 {
164 if ( feedback->isCanceled() )
165 break;
166
167 QgsFeature f;
168 f.setAttributes( *it );
169 if ( !sink->addFeature( f, QgsFeatureSink::Flag::FastInsert ) )
170 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, u"OUTPUT"_s ) );
171 }
172 sink->finalize();
173 outputs.insert( u"OUTPUT"_s, dest );
174 }
175
176 if ( !outputHtml.isEmpty() )
177 {
178 QFile file( outputHtml );
179 if ( file.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
180 {
181 QTextStream out( &file );
182 out << u"<html><head><meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"/></head><body>\n"_s;
183 out << QObject::tr( "<p>Total unique values: %1</p>" ).arg( values.size() );
184 out << QObject::tr( "<p>Unique values:</p>" );
185 out << u"<ul>"_s;
186 for ( auto &v : std::as_const( valueList ) )
187 {
188 out << u"<li>%1</li>"_s.arg( v );
189 }
190 out << u"</ul></body></html>"_s;
191
192 outputs.insert( u"OUTPUT_HTML_FILE"_s, outputHtml );
193 }
194 }
195
196 return outputs;
197}
198
@ Vector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition qgis.h:3610
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Definition qgis.h:2254
@ NoGeometry
No geometry.
Definition qgis.h:298
A vector of attributes.
Represents a coordinate reference system (CRS).
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:60
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:55
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:63
Container of fields for a vector layer.
Definition qgsfields.h:46
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
Definition qgsfields.cpp:76
Contains information about the context in which a processing algorithm is executed.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
A numeric output for processing algorithms.
A string output for processing algorithms.
A feature sink output for processing algorithms.
An input feature source (such as vector layers) parameter for processing algorithms.
A vector layer or feature source field parameter for processing algorithms.
A generic file based destination parameter, for specifying the destination path for a file (non-map l...