QGIS API Documentation 4.3.0-Master (ffcfc20b9b4)
Loading...
Searching...
No Matches
qgsalgorithmheatmap.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmheatmap.cpp
3 ---------------------
4 begin : June 2026
5 copyright : (C) 2026 by Nyall Dawson
6 email : nyall dot dawson 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
18#include "qgsalgorithmheatmap.h"
19
20#include "qgsapplication.h"
21#include "qgskde.h"
23
24#include <QString>
25
26using namespace Qt::StringLiterals;
27
29
30
31QString QgsHeatmapAlgorithm::name() const
32{
33 return u"heatmapkerneldensityestimation"_s;
34}
35
36QString QgsHeatmapAlgorithm::displayName() const
37{
38 return QObject::tr( "Heatmap (Kernel Density Estimation)" );
39}
40
41QStringList QgsHeatmapAlgorithm::tags() const
42{
43 return QObject::tr( "heatmap,kde,hotspot" ).split( ',' );
44}
45
46QString QgsHeatmapAlgorithm::group() const
47{
48 return QObject::tr( "Interpolation" );
49}
50
51QString QgsHeatmapAlgorithm::groupId() const
52{
53 return u"interpolation"_s;
54}
55
56QIcon QgsHeatmapAlgorithm::icon() const
57{
58 return QgsApplication::getThemeIcon( u"/heatmap.svg"_s );
59}
60
61QgsHeatmapAlgorithm::~QgsHeatmapAlgorithm() = default;
62
63void QgsHeatmapAlgorithm::initAlgorithm( const QVariantMap & )
64{
65 auto inputParam = std::make_unique<QgsProcessingParameterFeatureSource>( u"INPUT"_s, QObject::tr( "Point layer" ), QList<int>() << static_cast<int>( Qgis::ProcessingSourceType::VectorPoint ) );
66 inputParam->setHelp( QObject::tr( "The point vector layer to calculate the heatmap from." ) );
67 addParameter( inputParam.release() );
68
69 auto radiusParam = std::make_unique<QgsProcessingParameterDistance>( u"RADIUS"_s, QObject::tr( "Radius" ), 100.0, u"INPUT"_s, false, 0.0 );
70 radiusParam->setHelp( QObject::tr( "The search radius to use for calculating the heatmap. This represents the distance around each point that will be considered when calculating the density." ) );
71 addParameter( radiusParam.release() );
72
73 auto radiusFieldParam
74 = std::make_unique<QgsProcessingParameterField>( u"RADIUS_FIELD"_s, QObject::tr( "Radius from field" ), QVariant(), u"INPUT"_s, Qgis::ProcessingFieldParameterDataType::Numeric, false, true );
75 radiusFieldParam->setFlags( radiusFieldParam->flags() | Qgis::ProcessingParameterFlag::Advanced );
76 radiusFieldParam->setHelp( QObject::tr( "An optional numeric field from the input layer which specifies a per-feature radius to use instead of the global radius parameter." ) );
77 addParameter( radiusFieldParam.release() );
78
79 auto pixelSizeParam = std::make_unique<QgsProcessingParameterHeatmapPixelSize>( u"PIXEL_SIZE"_s, QObject::tr( "Output raster size" ), u"INPUT"_s, u"RADIUS"_s, u"RADIUS_FIELD"_s, 0.1 );
80 pixelSizeParam->setHelp( QObject::tr( "The size of pixels in the output raster. This will determine the spatial resolution of the generated heatmap." ) );
81 addParameter( pixelSizeParam.release() );
82
83 auto weightFieldParam
84 = std::make_unique<QgsProcessingParameterField>( u"WEIGHT_FIELD"_s, QObject::tr( "Weight from field" ), QVariant(), u"INPUT"_s, Qgis::ProcessingFieldParameterDataType::Numeric, false, true );
85 weightFieldParam->setFlags( weightFieldParam->flags() | Qgis::ProcessingParameterFlag::Advanced );
86 weightFieldParam->setHelp(
87 QObject::tr( "An optional numeric field from the input layer to use for weighting the points. If specified, the density will be calculated using this weight instead of simply counting the points." )
88 );
89 addParameter( weightFieldParam.release() );
90
91 const QStringList kernels = { QObject::tr( "Quartic" ), QObject::tr( "Triangular" ), QObject::tr( "Uniform" ), QObject::tr( "Triweight" ), QObject::tr( "Epanechnikov" ) };
92 auto kernelShapeParam = std::make_unique<QgsProcessingParameterEnum>( u"KERNEL"_s, QObject::tr( "Kernel shape" ), kernels, false, 0 );
93 kernelShapeParam->setFlags( kernelShapeParam->flags() | Qgis::ProcessingParameterFlag::Advanced );
94 kernelShapeParam->setHelp( QObject::tr( "The shape of the kernel to use for density estimation. Different kernel shapes affect the influence of points at varying distances from the center." ) );
95 addParameter( kernelShapeParam.release() );
96
97 auto decayRatio
98 = std::make_unique<QgsProcessingParameterNumber>( u"DECAY"_s, QObject::tr( "Decay ratio (Triangular kernels only)" ), Qgis::ProcessingNumberParameterType::Double, 0.0, true, -100.0, 100.0 );
99 decayRatio->setFlags( decayRatio->flags() | Qgis::ProcessingParameterFlag::Advanced );
100 decayRatio->setHelp( QObject::tr( "The decay ratio for triangular kernels. This controls how the weight of a point decreases as the distance from the point increases." ) );
101 addParameter( decayRatio.release() );
102
103 const QStringList outputScalings = { QObject::tr( "Raw" ), QObject::tr( "Scaled" ) };
104 auto outputScaling = std::make_unique<QgsProcessingParameterEnum>( u"OUTPUT_VALUE"_s, QObject::tr( "Output value scaling" ), outputScalings, false, 0 );
105 outputScaling->setFlags( outputScaling->flags() | Qgis::ProcessingParameterFlag::Advanced );
106 outputScaling->setHelp( QObject::tr( "The scaling to apply to output values. 'Raw' will output the raw density values, while 'Scaled' will scale the values to represent an overall density." ) );
107 addParameter( outputScaling.release() );
108
109 auto outputParam = std::make_unique<QgsProcessingParameterRasterDestination>( u"OUTPUT"_s, QObject::tr( "Heatmap" ) );
110 outputParam->setHelp( QObject::tr( "The output heatmap raster layer." ) );
111 addParameter( outputParam.release() );
112}
113
114QString QgsHeatmapAlgorithm::shortHelpString() const
115{
116 return QObject::tr(
117 "This algorithm creates a density (heatmap) raster of an input point vector layer using kernel density estimation. "
118 "Heatmaps allow easy identification of hotspots and clustering of points.\n\n"
119 "The density is calculated based on the number of points in a location, "
120 "with larger numbers of clustered points resulting in larger values."
121 );
122}
123
124QString QgsHeatmapAlgorithm::shortDescription() const
125{
126 return QObject::tr( "Creates a heatmap from points using kernel density estimation." );
127}
128
129QgsHeatmapAlgorithm *QgsHeatmapAlgorithm::createInstance() const
130{
131 return new QgsHeatmapAlgorithm();
132}
133
134QVariantMap QgsHeatmapAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
135{
136 QGS_MARK_ALGORITHM_SOURCE
137
138 std::unique_ptr<QgsProcessingFeatureSource> source( parameterAsSource( parameters, u"INPUT"_s, context ) );
139 if ( !source )
140 throw QgsProcessingException( invalidSourceError( parameters, u"INPUT"_s ) );
141
142 const double radius = parameterAsDouble( parameters, u"RADIUS"_s, context );
143 const int kernelShape = parameterAsEnum( parameters, u"KERNEL"_s, context );
144 const double pixelSize = parameterAsDouble( parameters, u"PIXEL_SIZE"_s, context );
145 const double decay = parameterAsDouble( parameters, u"DECAY"_s, context );
146 const int outputValues = parameterAsEnum( parameters, u"OUTPUT_VALUE"_s, context );
147 const QString outputFile = parameterAsOutputLayer( parameters, u"OUTPUT"_s, context );
148 const QString weightField = parameterAsString( parameters, u"WEIGHT_FIELD"_s, context );
149 const QString radiusField = parameterAsString( parameters, u"RADIUS_FIELD"_s, context );
150
151 const QString outputFormat = parameterAsOutputRasterFormat( parameters, u"OUTPUT"_s, context );
152
153 QList<int> attrs;
155 kdeParams.source = source.get();
156 kdeParams.radius = radius;
157 kdeParams.pixelSize = pixelSize;
158
159 if ( !radiusField.isEmpty() )
160 {
161 const int fieldIndex = source->fields().lookupField( radiusField );
162 if ( fieldIndex < 0 )
163 {
164 throw QgsProcessingException( QObject::tr( "Invalid radius field: “%1” does not exist" ).arg( radiusField ) );
165 }
166 kdeParams.radiusField = radiusField;
167 attrs.append( fieldIndex );
168 }
169
170 if ( !weightField.isEmpty() )
171 {
172 const int fieldIndex = source->fields().lookupField( weightField );
173 if ( fieldIndex < 0 )
174 {
175 throw QgsProcessingException( QObject::tr( "Invalid weight field: “%1” does not exist" ).arg( weightField ) );
176 }
177
178 kdeParams.weightField = weightField;
179 attrs.append( fieldIndex );
180 }
181
182 kdeParams.shape = static_cast<QgsKernelDensityEstimation::KernelShape>( kernelShape );
183 kdeParams.decayRatio = decay;
184 kdeParams.outputValues = static_cast<QgsKernelDensityEstimation::OutputValues>( outputValues );
185
186 QgsKernelDensityEstimation kde( kdeParams, outputFile, outputFormat );
187 if ( kde.prepare() != QgsKernelDensityEstimation::Result::Success )
188 throw QgsProcessingException( QObject::tr( "Could not create destination layer" ) );
189
190 QgsFeatureRequest request;
191 request.setSubsetOfAttributes( attrs );
192 QgsFeatureIterator features = source->getFeatures( request );
193 QgsFeature f;
194 const double total = source->featureCount() > 0 ? 100.0 / source->featureCount() : 0;
195 int current = 0;
196 while ( features.nextFeature( f ) )
197 {
198 if ( feedback->isCanceled() )
199 break;
200
201 if ( kde.addFeature( f ) != QgsKernelDensityEstimation::Result::Success )
202 feedback->reportError( QObject::tr( "Error adding feature with ID %1 to heatmap" ).arg( f.id() ) );
203
204 feedback->setProgress( current * total );
205 current++;
206 }
207
208 if ( kde.finalise() != QgsKernelDensityEstimation::Result::Success )
209 throw QgsProcessingException( QObject::tr( "Could not save destination layer" ) );
210
211 QVariantMap outputs;
212 outputs.insert( u"OUTPUT"_s, outputFile );
213 return outputs;
214}
215
@ VectorPoint
Vector point layers.
Definition qgis.h:3750
@ Numeric
Accepts numeric fields.
Definition qgis.h:4037
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
Definition qgis.h:3982
@ Double
Double/float values.
Definition qgis.h:4023
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
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 & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:60
QgsFeatureId id
Definition qgsfeature.h:63
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:56
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:65
Performs Kernel Density Estimation ("heatmap") calculations on a vector layer.
Definition qgskde.h:40
KernelShape
Kernel shape type.
Definition qgskde.h:44
OutputValues
Output values type.
Definition qgskde.h:54
@ Success
Operation completed successfully.
Definition qgskde.h:62
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.
QgsKernelDensityEstimation::OutputValues outputValues
Type of output value.
Definition qgskde.h:94
QString radiusField
Field for radius, or empty if using a fixed radius.
Definition qgskde.h:79
double radius
Fixed radius, in map units.
Definition qgskde.h:76
QgsFeatureSource * source
Point feature source.
Definition qgskde.h:73
double decayRatio
Decay ratio (Triangular kernels only).
Definition qgskde.h:91
QgsKernelDensityEstimation::KernelShape shape
Kernel shape.
Definition qgskde.h:88
QString weightField
Field name for weighting field, or empty if not using weights.
Definition qgskde.h:82
double pixelSize
Size of pixel in output file.
Definition qgskde.h:85