Skip to content

Commit

Permalink
Add option for unscaled values for heatmaps rasters, set as default
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Sep 24, 2014
1 parent 957e791 commit 9cdea17
Show file tree
Hide file tree
Showing 5 changed files with 260 additions and 202 deletions.
125 changes: 83 additions & 42 deletions src/plugins/heatmap/heatmap.cpp
Expand Up @@ -132,7 +132,8 @@ void Heatmap::run()
int rows = d.rows();
double cellsize = d.cellSizeX(); // or d.cellSizeY(); both have the same value
mDecay = d.decayRatio();
int kernelShape = d.kernelShape();
KernelShape kernelShape = d.kernelShape();
OutputValues valueType = d.outputValues();

//is input layer multipoint?
bool isMultiPoint = inputLayer->wkbType() == QGis::WKBMultiPoint || inputLayer->wkbType() == QGis::WKBMultiPoint25D;
Expand Down Expand Up @@ -311,7 +312,7 @@ void Heatmap::run()
continue;
}

double pixelValue = weight * calculateKernelValue( distance, myBuffer, kernelShape );
double pixelValue = weight * calculateKernelValue( distance, myBuffer, kernelShape, valueType );

// clearing anamolies along the axes
if ( xp == 0 && yp == 0 )
Expand Down Expand Up @@ -386,24 +387,24 @@ int Heatmap::bufferSize( double radius, double cellsize )
return buffer;
}

double Heatmap::calculateKernelValue( double distance, int bandwidth, int kernelShape )
double Heatmap::calculateKernelValue( const double distance, const int bandwidth, const KernelShape shape, const OutputValues outputType )
{
switch ( kernelShape )
switch ( shape )
{
case Heatmap::Triangular:
return triangularKernel( distance , bandwidth );
return triangularKernel( distance , bandwidth, outputType );

case Heatmap::Uniform:
return uniformKernel( distance, bandwidth );
return uniformKernel( distance, bandwidth, outputType );

case Heatmap::Quartic:
return quarticKernel( distance, bandwidth );
return quarticKernel( distance, bandwidth, outputType );

case Heatmap::Triweight:
return triweightKernel( distance, bandwidth );
return triweightKernel( distance, bandwidth, outputType );

case Heatmap::Epanechnikov:
return epanechnikovKernel( distance, bandwidth );
return epanechnikovKernel( distance, bandwidth, outputType );
}
return 0;

Expand All @@ -417,59 +418,99 @@ double Heatmap::calculateKernelValue( double distance, int bandwidth, int kernel
* k is calculated by polar double integration of the kernel function
* between a radius of 0 to the specified bandwidth and equating the area to 1. */

double Heatmap::uniformKernel( double distance, int bandwidth )
double Heatmap::uniformKernel( const double distance, const int bandwidth, const OutputValues outputType ) const
{
Q_UNUSED( distance );
// Normalizing constant
double k = 2. / ( M_PI * ( double )bandwidth );
switch ( outputType )
{
case Heatmap::Scaled:
{
// Normalizing constant
double k = 2. / ( M_PI * ( double )bandwidth );

// Derived from Wand and Jones (1995), p. 175
return k * ( 0.5 / ( double )bandwidth );
// Derived from Wand and Jones (1995), p. 175
return k * ( 0.5 / ( double )bandwidth );
}
default:
return 1.0;
}
}

double Heatmap::quarticKernel( double distance, int bandwidth )
double Heatmap::quarticKernel( const double distance, const int bandwidth, const OutputValues outputType ) const
{
// Normalizing constant
double k = 16. / ( 5. * M_PI * pow(( double )bandwidth, 2 ) );
switch ( outputType )
{
case Heatmap::Scaled:
{
// Normalizing constant
double k = outputType == Heatmap::Scaled ? 116. / ( 5. * M_PI * pow(( double )bandwidth, 2 ) ) : 1.0;

// Derived from Wand and Jones (1995), p. 175
return k * ( 15. / 16. ) * pow( 1. - pow( distance / ( double )bandwidth, 2 ), 2 );
// Derived from Wand and Jones (1995), p. 175
return k * ( 15. / 16. ) * pow( 1. - pow( distance / ( double )bandwidth, 2 ), 2 );
}
default:
return pow( 1. - pow( distance / ( double )bandwidth, 2 ), 2 );
}
}

double Heatmap::triweightKernel( double distance, int bandwidth )
double Heatmap::triweightKernel( const double distance, const int bandwidth, const OutputValues outputType ) const
{
// Normalizing constant
double k = 128. / ( 35. * M_PI * pow(( double )bandwidth, 2 ) );
switch ( outputType )
{
case Heatmap::Scaled:
{
// Normalizing constant
double k = outputType == Heatmap::Scaled ? 128. / ( 35. * M_PI * pow(( double )bandwidth, 2 ) ) : 1.0;

// Derived from Wand and Jones (1995), p. 175
return k * ( 35. / 32. ) * pow( 1. - pow( distance / ( double )bandwidth, 2 ), 3 );
// Derived from Wand and Jones (1995), p. 175
return k * ( 35. / 32. ) * pow( 1. - pow( distance / ( double )bandwidth, 2 ), 3 );
}
default:
return pow( 1. - pow( distance / ( double )bandwidth, 2 ), 3 );
}
}

double Heatmap::epanechnikovKernel( double distance, int bandwidth )
double Heatmap::epanechnikovKernel( const double distance, const int bandwidth, const OutputValues outputType ) const
{
// Normalizing constant
double k = 8. / ( 3. * M_PI * pow(( double )bandwidth, 2 ) );
switch ( outputType )
{
case Heatmap::Scaled:
{
// Normalizing constant
double k = outputType == Heatmap::Scaled ? 8. / ( 3. * M_PI * pow(( double )bandwidth, 2 ) ) : 1.0;

// Derived from Wand and Jones (1995), p. 175
return k * ( 3. / 4. ) * ( 1. - pow( distance / ( double )bandwidth, 2 ) );
// Derived from Wand and Jones (1995), p. 175
return k * ( 3. / 4. ) * ( 1. - pow( distance / ( double )bandwidth, 2 ) );
}
default:
return ( 1. - pow( distance / ( double )bandwidth, 2 ) );
}
}

double Heatmap::triangularKernel( double distance, int bandwidth )
double Heatmap::triangularKernel( const double distance, const int bandwidth, const OutputValues outputType ) const
{
// Normalizing constant. In this case it's calculated a little different
// due to the inclusion of the non-standard "decay" parameter

if ( mDecay >= 0 )
switch ( outputType )
{
double k = 3. / (( 1. + 2. * mDecay ) * M_PI * pow(( double )bandwidth, 2 ) );
case Heatmap::Scaled:
{
// Normalizing constant. In this case it's calculated a little different
// due to the inclusion of the non-standard "decay" parameter

// Derived from Wand and Jones (1995), p. 175 (with addition of decay parameter)
return k * ( 1. - ( 1. - mDecay ) * ( distance / ( double )bandwidth ) );
}
else
{
// Non-standard or mathematically valid negative decay ("coolmap")
return ( 1. - ( 1. - mDecay ) * ( distance / ( double )bandwidth ) );
if ( mDecay >= 0 )
{
double k = 3. / (( 1. + 2. * mDecay ) * M_PI * pow(( double )bandwidth, 2 ) );

// Derived from Wand and Jones (1995), p. 175 (with addition of decay parameter)
return k * ( 1. - ( 1. - mDecay ) * ( distance / ( double )bandwidth ) );
}
else
{
// Non-standard or mathematically valid negative decay ("coolmap")
return ( 1. - ( 1. - mDecay ) * ( distance / ( double )bandwidth ) );
}
}
default:
return ( 1. - ( 1. - mDecay ) * ( distance / ( double )bandwidth ) );
}
}

Expand Down
21 changes: 14 additions & 7 deletions src/plugins/heatmap/heatmap.h
Expand Up @@ -71,7 +71,7 @@ class Heatmap: public QObject, public QgisPlugin
virtual ~Heatmap();

// Kernel shape type
enum kernelShape
enum KernelShape
{
Quartic,
Triangular,
Expand All @@ -80,6 +80,13 @@ class Heatmap: public QObject, public QgisPlugin
Epanechnikov
};

// Output values type
enum OutputValues
{
Raw,
Scaled
};

QMap<QString, QVariant> mSessionSettings;

public slots:
Expand All @@ -100,17 +107,17 @@ class Heatmap: public QObject, public QgisPlugin
//! Worker to calculate buffer size in pixels
int bufferSize( double radius, double cellsize );
//! Calculate the value given to a point width a given distance for a specified kernel shape
double calculateKernelValue( double distance, int bandwidth, int kernelShape );
double calculateKernelValue( const double distance, const int bandwidth, const KernelShape shape, const OutputValues outputType );
//! Uniform kernel function
double uniformKernel( double distance, int bandwidth );
double uniformKernel( const double distance, const int bandwidth , const OutputValues outputType ) const;
//! Quartic kernel function
double quarticKernel( double distance, int bandwidth );
double quarticKernel( const double distance, const int bandwidth , const OutputValues outputType ) const;
//! Triweight kernel function
double triweightKernel( double distance, int bandwidth );
double triweightKernel( const double distance, const int bandwidth , const OutputValues outputType ) const;
//! Epanechnikov kernel function
double epanechnikovKernel( double distance, int bandwidth );
double epanechnikovKernel( const double distance, const int bandwidth, const OutputValues outputType ) const;
//! Triangular kernel function
double triangularKernel( double distance, int bandwidth );
double triangularKernel( const double distance, const int bandwidth , const OutputValues outputType ) const;

// MANDATORY PLUGIN PROPERTY DECLARATIONS .....

Expand Down
56 changes: 39 additions & 17 deletions src/plugins/heatmap/heatmapgui.cpp
Expand Up @@ -46,6 +46,15 @@ HeatmapGui::HeatmapGui( QWidget* parent, Qt::WindowFlags fl, QMap<QString, QVari

blockAllSignals( true );

mKernelShapeCombo->addItem( tr( "Quartic (biweight)" ), Heatmap::Quartic );
mKernelShapeCombo->addItem( tr( "Triangular" ), Heatmap::Triangular );
mKernelShapeCombo->addItem( tr( "Uniform" ), Heatmap::Uniform );
mKernelShapeCombo->addItem( tr( "Triweight" ), Heatmap::Triweight );
mKernelShapeCombo->addItem( tr( "Epanechnikov" ), Heatmap::Epanechnikov );

mOutputValuesComboBox->addItem( tr( "Raw values" ), Heatmap::Raw );
mOutputValuesComboBox->addItem( tr( "Scaled by kernel size" ), Heatmap::Scaled );

mHeatmapSessionSettings = temporarySettings;

// Adding point layers to the inputLayerCombo
Expand Down Expand Up @@ -124,6 +133,7 @@ void HeatmapGui::blockAllSignals( bool b )
mColumnsSpinBox->blockSignals( b );
mCellXLineEdit->blockSignals( b );
mCellYLineEdit->blockSignals( b );
mOutputValuesComboBox->blockSignals( b );
}

/*
Expand Down Expand Up @@ -184,10 +194,15 @@ void HeatmapGui::restoreSettings( bool usingLastInputLayer )
// Kernel setting - not layer specific
if ( mHeatmapSessionSettings->value( QString( "lastKernel" ) ).toInt() )
{
mKernelShapeCombo->setCurrentIndex( mHeatmapSessionSettings->value( QString( "lastKernel" ) ).toInt() );
mKernelShapeCombo->setCurrentIndex( mKernelShapeCombo->findData(
( Heatmap::KernelShape )( mHeatmapSessionSettings->value( QString( "lastKernel" ) ).toInt() ) ) );
mDecayLineEdit->setText( mHeatmapSessionSettings->value( QString( "decayRatio" ) ).toString() );
mDecayLineEdit->setEnabled( mAdvancedGroupBox->isChecked() && mKernelShapeCombo->currentIndex() == Heatmap::Triangular );
mDecayLineEdit->setEnabled( mAdvancedGroupBox->isChecked() &&
( Heatmap::KernelShape )( mKernelShapeCombo->itemData( mKernelShapeCombo->currentIndex() ).toInt() ) == Heatmap::Triangular );
}
mOutputValuesComboBox->setCurrentIndex( mOutputValuesComboBox->findData(
( Heatmap::OutputValues )( mHeatmapSessionSettings->value( QString( "lastOutputValues" ), "0" ).toInt() ) ) );

}

void HeatmapGui::saveSettings()
Expand All @@ -203,13 +218,14 @@ void HeatmapGui::saveSettings()
mHeatmapSessionSettings->insert( QString( "lastRadiusUnit" ), QVariant( mBufferUnitCombo->currentIndex() ) );
mHeatmapSessionSettings->insert( QString( "advancedEnabled" ), QVariant( mAdvancedGroupBox->isChecked() ) );
mHeatmapSessionSettings->insert( QString( "lastRows" ), QVariant( mRowsSpinBox->value() ) );
mHeatmapSessionSettings->insert( QString( "lastKernel" ), QVariant( mKernelShapeCombo->currentIndex() ) );
mHeatmapSessionSettings->insert( QString( "lastKernel" ), QVariant( mKernelShapeCombo->itemData( mKernelShapeCombo->currentIndex() ).toInt() ) );
mHeatmapSessionSettings->insert( QString( "useRadius" ), QVariant( mRadiusFieldCheckBox->isChecked() ) );
mHeatmapSessionSettings->insert( QString( "radiusField" ), QVariant( mRadiusFieldCombo->currentField() ) );
mHeatmapSessionSettings->insert( QString( "radiusFieldUnit" ), QVariant( mRadiusFieldUnitCombo->currentIndex() ) );
mHeatmapSessionSettings->insert( QString( "useWeight" ), QVariant( mWeightFieldCheckBox->isChecked() ) );
mHeatmapSessionSettings->insert( QString( "weightField" ), QVariant( mWeightFieldCombo->currentField() ) );
mHeatmapSessionSettings->insert( QString( "decayRatio" ), QVariant( mDecayLineEdit->text() ) );
mHeatmapSessionSettings->insert( QString( "lastOutputValues" ), QVariant( mOutputValuesComboBox->itemData( mOutputValuesComboBox->currentIndex() ).toInt() ) );
}

void HeatmapGui::on_mButtonBox_rejected()
Expand Down Expand Up @@ -260,7 +276,8 @@ void HeatmapGui::on_mAdvancedGroupBox_toggled( bool enabled )
}

updateBBox();
mDecayLineEdit->setEnabled( mKernelShapeCombo->currentIndex() == Heatmap::Triangular );
mDecayLineEdit->setEnabled(( Heatmap::KernelShape )( mKernelShapeCombo->itemData( mKernelShapeCombo->currentIndex() ).toInt() ) == Heatmap::Triangular );

}
}

Expand Down Expand Up @@ -464,7 +481,7 @@ void HeatmapGui::updateBBox()
updateSize();
}

double HeatmapGui::mapUnitsOf( double meters, QgsCoordinateReferenceSystem layerCrs )
double HeatmapGui::mapUnitsOf( double meters, QgsCoordinateReferenceSystem layerCrs ) const
{
// converter function to transform metres input to mapunits
// so that bounding box can be updated
Expand All @@ -485,17 +502,17 @@ double HeatmapGui::mapUnitsOf( double meters, QgsCoordinateReferenceSystem layer
*
*/

bool HeatmapGui::weighted()
bool HeatmapGui::weighted() const
{
return mWeightFieldCheckBox->isChecked();
}

bool HeatmapGui::variableRadius()
bool HeatmapGui::variableRadius() const
{
return mRadiusFieldCheckBox->isChecked();
}

double HeatmapGui::radius()
double HeatmapGui::radius() const
{
double radius = mBufferSizeLineEdit->text().toDouble();
if ( mBufferUnitCombo->currentIndex() == HeatmapGui::Meters )
Expand All @@ -505,7 +522,7 @@ double HeatmapGui::radius()
return radius;
}

int HeatmapGui::radiusUnit()
int HeatmapGui::radiusUnit() const
{
if ( mRadiusFieldCheckBox->isChecked() )
{
Expand All @@ -514,17 +531,22 @@ int HeatmapGui::radiusUnit()
return mBufferUnitCombo->currentIndex();
}

int HeatmapGui::kernelShape()
Heatmap::KernelShape HeatmapGui::kernelShape() const
{
return ( Heatmap::KernelShape ) mKernelShapeCombo->itemData( mKernelShapeCombo->currentIndex() ).toInt();
}

Heatmap::OutputValues HeatmapGui::outputValues() const
{
return mKernelShapeCombo->currentIndex();
return ( Heatmap::OutputValues ) mOutputValuesComboBox->itemData( mOutputValuesComboBox->currentIndex() ).toInt();
}

double HeatmapGui::decayRatio()
double HeatmapGui::decayRatio() const
{
return mDecayLineEdit->text().toDouble();
}

int HeatmapGui::radiusField()
int HeatmapGui::radiusField() const
{
QgsVectorLayer *inputLayer = inputVectorLayer();
if ( !inputLayer )
Expand All @@ -533,7 +555,7 @@ int HeatmapGui::radiusField()
return inputLayer->pendingFields().indexFromName( mRadiusFieldCombo->currentField() );
}

int HeatmapGui::weightField()
int HeatmapGui::weightField() const
{
QgsVectorLayer *inputLayer = inputVectorLayer();
if ( !inputLayer )
Expand All @@ -542,12 +564,12 @@ int HeatmapGui::weightField()
return inputLayer->pendingFields().indexFromName( mWeightFieldCombo->currentField() );
}

bool HeatmapGui::addToCanvas()
bool HeatmapGui::addToCanvas() const
{
return mAddToCanvas->isChecked();
}

QString HeatmapGui::outputFilename()
QString HeatmapGui::outputFilename() const
{
QString outputFileName;
QString outputFormat;
Expand Down Expand Up @@ -582,7 +604,7 @@ QString HeatmapGui::outputFilename()
return outputFileName;
}

QString HeatmapGui::outputFormat()
QString HeatmapGui::outputFormat() const
{
return mFormatCombo->itemData( mFormatCombo->currentIndex() ).toString();
}
Expand Down

0 comments on commit 9cdea17

Please sign in to comment.