QGIS API Documentation 3.99.0-Master (21b3aa880ba)
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
21
22QString QgsUniqueValuesAlgorithm::name() const
23{
24 return QStringLiteral( "listuniquevalues" );
25}
26
27QString QgsUniqueValuesAlgorithm::displayName() const
28{
29 return QObject::tr( "List unique values" );
30}
31
32QStringList QgsUniqueValuesAlgorithm::tags() const
33{
34 return QObject::tr( "count,unique,values" ).split( ',' );
35}
36
37QString QgsUniqueValuesAlgorithm::group() const
38{
39 return QObject::tr( "Vector analysis" );
40}
41
42QString QgsUniqueValuesAlgorithm::groupId() const
43{
44 return QStringLiteral( "vectoranalysis" );
45}
46
47QString QgsUniqueValuesAlgorithm::shortHelpString() const
48{
49 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." );
50}
51
52QString QgsUniqueValuesAlgorithm::shortDescription() const
53{
54 return QObject::tr( "Returns list of unique values in given field(s) of a vector layer." );
55}
56
57QgsUniqueValuesAlgorithm *QgsUniqueValuesAlgorithm::createInstance() const
58{
59 return new QgsUniqueValuesAlgorithm();
60}
61
62void QgsUniqueValuesAlgorithm::initAlgorithm( const QVariantMap & )
63{
64 addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ), QList<int>() << static_cast<int>( Qgis::ProcessingSourceType::Vector ) ) );
65 addParameter( new QgsProcessingParameterField( QStringLiteral( "FIELDS" ), QObject::tr( "Target field(s)" ), QVariant(), QStringLiteral( "INPUT" ), Qgis::ProcessingFieldParameterDataType::Any, true ) );
66 addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Unique values" ), Qgis::ProcessingSourceType::Vector, QVariant(), true ) );
67 addParameter( new QgsProcessingParameterFileDestination( QStringLiteral( "OUTPUT_HTML_FILE" ), QObject::tr( "HTML report" ), QObject::tr( "HTML files (*.html *.htm)" ), QVariant(), true ) );
68 addOutput( new QgsProcessingOutputNumber( QStringLiteral( "TOTAL_VALUES" ), QObject::tr( "Total unique values" ) ) );
69 addOutput( new QgsProcessingOutputString( QStringLiteral( "UNIQUE_VALUES" ), QObject::tr( "Unique values" ) ) );
70}
71
72QVariantMap QgsUniqueValuesAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
73{
74 std::unique_ptr<QgsProcessingFeatureSource> source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
75 if ( !source )
76 throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
77
78 const QStringList fieldNames = parameterAsStrings( parameters, QStringLiteral( "FIELDS" ), context );
79 const QString outputHtml = parameterAsFileOutput( parameters, QStringLiteral( "OUTPUT_HTML_FILE" ), context );
80
81 QgsFields fields;
82 QList<int> fieldIndices;
83
84 for ( const QString &fieldName : fieldNames )
85 {
86 int fieldIndex = source->fields().lookupField( fieldName );
87 if ( fieldIndex < 0 )
88 {
89 feedback->reportError( QObject::tr( "Invalid field name %1" ).arg( fieldName ) );
90 continue;
91 }
92 fields.append( source->fields().at( fieldIndex ) );
93 fieldIndices << fieldIndex;
94 }
95
96 QString dest;
97 std::unique_ptr<QgsFeatureSink> sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, Qgis::WkbType::NoGeometry, QgsCoordinateReferenceSystem() ) );
98 if ( !sink )
99 {
100 throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
101 }
102
103 QSet<QgsAttributes> values;
104 if ( fieldIndices.size() == 1 )
105 {
106 const QSet<QVariant> unique = source->uniqueValues( fieldIndices.at( 0 ) );
107 for ( const QVariant &v : unique )
108 {
109 values.insert( QgsAttributes() << v );
110 }
111 }
112 else
113 {
114 // we have to scan whole table
115 // TODO: add this support to QgsVectorDataProvider, so we can run it on the backend
116 QgsFeatureRequest request;
118 request.setSubsetOfAttributes( fieldIndices );
119
120 const double step = source->featureCount() > 0 ? 100.0 / source->featureCount() : 0;
121 QgsFeatureIterator features = source->getFeatures( request );
122 QgsFeature f;
123 long long i = 0;
124 while ( features.nextFeature( f ) )
125 {
126 if ( feedback->isCanceled() )
127 break;
128
129 QgsAttributes attrs;
130 for ( auto &i : std::as_const( fieldIndices ) )
131 {
132 attrs << f.attribute( i );
133 }
134 values.insert( attrs );
135
136 i++;
137 feedback->setProgress( i * step );
138 }
139 }
140
141 QVariantMap outputs;
142 outputs.insert( QStringLiteral( "TOTAL_VALUES" ), values.size() );
143
144 QStringList valueList;
145 for ( auto it = values.constBegin(); it != values.constEnd(); ++it )
146 {
147 QStringList s;
148 for ( const QVariant &v : std::as_const( *it ) )
149 {
150 s.append( v.toString() );
151 }
152 valueList.append( s.join( ',' ) );
153 }
154 outputs.insert( QStringLiteral( "UNIQUE_VALUES" ), valueList.join( ';' ) );
155
156 if ( sink )
157 {
158 for ( auto it = values.constBegin(); it != values.constEnd(); ++it )
159 {
160 if ( feedback->isCanceled() )
161 break;
162
163 QgsFeature f;
164 f.setAttributes( *it );
165 if ( !sink->addFeature( f, QgsFeatureSink::Flag::FastInsert ) )
166 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
167 }
168 sink->finalize();
169 outputs.insert( QStringLiteral( "OUTPUT" ), dest );
170 }
171
172 if ( !outputHtml.isEmpty() )
173 {
174 QFile file( outputHtml );
175 if ( file.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
176 {
177 QTextStream out( &file );
178#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
179 out.setCodec( "UTF-8" );
180#endif
181 out << QStringLiteral( "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"/></head><body>\n" );
182 out << QObject::tr( "<p>Total unique values: %1</p>" ).arg( values.size() );
183 out << QObject::tr( "<p>Unique values:</p>" );
184 out << QStringLiteral( "<ul>" );
185 for ( auto &v : std::as_const( valueList ) )
186 {
187 out << QStringLiteral( "<li>%1</li>" ).arg( v );
188 }
189 out << QStringLiteral( "</ul></body></html>" );
190
191 outputs.insert( QStringLiteral( "OUTPUT_HTML_FILE" ), outputHtml );
192 }
193 }
194
195 return outputs;
196}
197
@ Vector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition qgis.h:3539
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Definition qgis.h:2196
@ NoGeometry
No geometry.
Definition qgis.h:294
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:58
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:53
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:61
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:73
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...