QGIS API Documentation 4.3.0-Master (7c7bd4d7018)
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 std::unique_ptr<QgsProcessingFeatureSource> source( parameterAsSource( parameters, u"INPUT"_s, context ) );
137 if ( !source )
138 throw QgsProcessingException( invalidSourceError( parameters, u"INPUT"_s ) );
139
140 const double radius = parameterAsDouble( parameters, u"RADIUS"_s, context );
141 const int kernelShape = parameterAsEnum( parameters, u"KERNEL"_s, context );
142 const double pixelSize = parameterAsDouble( parameters, u"PIXEL_SIZE"_s, context );
143 const double decay = parameterAsDouble( parameters, u"DECAY"_s, context );
144 const int outputValues = parameterAsEnum( parameters, u"OUTPUT_VALUE"_s, context );
145 const QString outputFile = parameterAsOutputLayer( parameters, u"OUTPUT"_s, context );
146 const QString weightField = parameterAsString( parameters, u"WEIGHT_FIELD"_s, context );
147 const QString radiusField = parameterAsString( parameters, u"RADIUS_FIELD"_s, context );
148
149 const QString outputFormat = parameterAsOutputRasterFormat( parameters, u"OUTPUT"_s, context );
150
151 QList<int> attrs;
153 kdeParams.source = source.get();
154 kdeParams.radius = radius;
155 kdeParams.pixelSize = pixelSize;
156
157 if ( !radiusField.isEmpty() )
158 {
159 const int fieldIndex = source->fields().lookupField( radiusField );
160 if ( fieldIndex < 0 )
161 {
162 throw QgsProcessingException( QObject::tr( "Invalid radius field: “%1” does not exist" ).arg( radiusField ) );
163 }
164 kdeParams.radiusField = radiusField;
165 attrs.append( fieldIndex );
166 }
167
168 if ( !weightField.isEmpty() )
169 {
170 const int fieldIndex = source->fields().lookupField( weightField );
171 if ( fieldIndex < 0 )
172 {
173 throw QgsProcessingException( QObject::tr( "Invalid weight field: “%1” does not exist" ).arg( weightField ) );
174 }
175
176 kdeParams.weightField = weightField;
177 attrs.append( fieldIndex );
178 }
179
180 kdeParams.shape = static_cast<QgsKernelDensityEstimation::KernelShape>( kernelShape );
181 kdeParams.decayRatio = decay;
182 kdeParams.outputValues = static_cast<QgsKernelDensityEstimation::OutputValues>( outputValues );
183
184 QgsKernelDensityEstimation kde( kdeParams, outputFile, outputFormat );
185 if ( kde.prepare() != QgsKernelDensityEstimation::Result::Success )
186 throw QgsProcessingException( QObject::tr( "Could not create destination layer" ) );
187
188 QgsFeatureRequest request;
189 request.setSubsetOfAttributes( attrs );
190 QgsFeatureIterator features = source->getFeatures( request );
191 QgsFeature f;
192 const double total = source->featureCount() > 0 ? 100.0 / source->featureCount() : 0;
193 int current = 0;
194 while ( features.nextFeature( f ) )
195 {
196 if ( feedback->isCanceled() )
197 break;
198
199 if ( kde.addFeature( f ) != QgsKernelDensityEstimation::Result::Success )
200 feedback->reportError( QObject::tr( "Error adding feature with ID %1 to heatmap" ).arg( f.id() ) );
201
202 feedback->setProgress( current * total );
203 current++;
204 }
205
206 if ( kde.finalise() != QgsKernelDensityEstimation::Result::Success )
207 throw QgsProcessingException( QObject::tr( "Could not save destination layer" ) );
208
209 QVariantMap outputs;
210 outputs.insert( u"OUTPUT"_s, outputFile );
211 return outputs;
212}
213
@ VectorPoint
Vector point layers.
Definition qgis.h:3716
@ Numeric
Accepts numeric fields.
Definition qgis.h:4003
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
Definition qgis.h:3948
@ Double
Double/float values.
Definition qgis.h:3989
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