Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsclassificationstandarddeviation.h 3 : : --------------------- 4 : : begin : September 2019 5 : : copyright : (C) 2019 by Denis Rouzaud 6 : : email : denis@opengis.ch 7 : : *************************************************************************** 8 : : * * 9 : : * This program is free software; you can redistribute it and/or modify * 10 : : * it under the terms of the GNU General Public License as published by * 11 : : * the Free Software Foundation; either version 2 of the License, or * 12 : : * (at your option) any later version. * 13 : : * * 14 : : ***************************************************************************/ 15 : : 16 : : #include <QObject> 17 : : 18 : : #include "qgsclassificationstandarddeviation.h" 19 : : #include "qgsgraduatedsymbolrenderer.h" 20 : : #include "qgsapplication.h" 21 : : 22 : 10 : const QString QgsClassificationStandardDeviation::METHOD_ID = QStringLiteral( "StdDev" ); 23 : : 24 : : 25 : 5 : QgsClassificationStandardDeviation::QgsClassificationStandardDeviation() 26 : 5 : : QgsClassificationMethod( SymmetricModeAvailable ) 27 : 10 : { 28 : : 29 : 5 : } 30 : : 31 : 0 : QString QgsClassificationStandardDeviation::name() const 32 : : { 33 : 0 : return QObject::tr( "Standard Deviation" ); 34 : : } 35 : : 36 : 10 : QString QgsClassificationStandardDeviation::id() const 37 : : { 38 : 10 : return METHOD_ID; 39 : : } 40 : : 41 : 0 : QgsClassificationMethod *QgsClassificationStandardDeviation::clone() const 42 : : { 43 : 0 : QgsClassificationStandardDeviation *c = new QgsClassificationStandardDeviation(); 44 : 0 : copyBase( c ); 45 : 0 : c->mStdDev = mStdDev; 46 : 0 : return c; 47 : 0 : } 48 : : 49 : 5 : QIcon QgsClassificationStandardDeviation::icon() const 50 : 5 : { 51 : 0 : return QgsApplication::getThemeIcon( "classification_methods/mClassificationStandardDeviation.svg" ); 52 : 0 : } 53 : : 54 : : 55 : 0 : QList<double> QgsClassificationStandardDeviation::calculateBreaks( double &minimum, double &maximum, 56 : : const QList<double> &values, int nclasses ) 57 : : { 58 : : // C++ implementation of the standard deviation class interval algorithm 59 : : // as implemented in the 'classInt' package available for the R statistical 60 : : // prgramming language. 61 : : 62 : : // Returns breaks based on 'prettyBreaks' of the centred and scaled 63 : : // values of 'values', and may have a number of classes different from 'classes'. 64 : : 65 : : // If there are no values to process: bail out 66 : 0 : if ( values.isEmpty() ) 67 : 0 : return QList<double>(); 68 : : 69 : 0 : double mean = 0.0; 70 : 0 : mStdDev = 0.0; 71 : 0 : int n = values.count(); 72 : : 73 : 0 : for ( int i = 0; i < n; i++ ) 74 : : { 75 : 0 : mean += values[i]; 76 : 0 : } 77 : 0 : mean = mean / static_cast< double >( n ); 78 : : 79 : 0 : double sd = 0.0; 80 : 0 : for ( int i = 0; i < n; i++ ) 81 : : { 82 : 0 : sd = values[i] - mean; 83 : 0 : mStdDev += sd * sd; 84 : 0 : } 85 : 0 : mStdDev = std::sqrt( mStdDev / n ); 86 : : 87 : : // if not symmetric, the symmetry point is the mean 88 : 0 : mEffectiveSymmetryPoint = symmetricModeEnabled() ? symmetryPoint() : mean; 89 : : 90 : 0 : QList<double> breaks = QgsSymbolLayerUtils::prettyBreaks( ( minimum - mEffectiveSymmetryPoint ) / mStdDev, ( maximum - mEffectiveSymmetryPoint ) / mStdDev, nclasses ); 91 : 0 : makeBreaksSymmetric( breaks, 0.0, symmetryAstride() ); //0.0 because breaks where computed on a centered distribution 92 : : 93 : 0 : for ( int i = 0; i < breaks.count(); i++ ) 94 : 0 : breaks[i] = ( breaks[i] * mStdDev ) + mEffectiveSymmetryPoint; 95 : : 96 : 0 : return breaks; 97 : 0 : } 98 : : 99 : 0 : QString QgsClassificationStandardDeviation::labelForRange( const double lowerValue, const double upperValue, QgsClassificationMethod::ClassPosition position ) const 100 : : { 101 : 0 : const QString lowerLabel = valueToLabel( lowerValue ); 102 : 0 : const QString upperLabel = valueToLabel( upperValue ); 103 : : 104 : 0 : switch ( position ) 105 : : { 106 : : case LowerBound: 107 : 0 : return QStringLiteral( "< %1" ).arg( upperLabel ); 108 : : case Inner: 109 : : { 110 : 0 : QString label( labelFormat() ); 111 : 0 : label.replace( QLatin1String( "%1" ), lowerLabel ).replace( QLatin1String( "%2" ), upperLabel ); 112 : 0 : return label; 113 : 0 : } 114 : : case UpperBound: 115 : 0 : return QStringLiteral( "≥ %1" ).arg( lowerLabel ); 116 : : } 117 : 0 : return QString(); 118 : 0 : } 119 : : 120 : : 121 : 0 : QString QgsClassificationStandardDeviation::valueToLabel( const double value ) const 122 : : { 123 : 0 : double normalized = ( value - mEffectiveSymmetryPoint ) / mStdDev; 124 : 0 : return QObject::tr( " %1 Std Dev" ).arg( QString::number( normalized, 'f', 2 ) ); 125 : 0 : } 126 : : 127 : : 128 : 0 : void QgsClassificationStandardDeviation::writeXml( QDomElement &element, const QgsReadWriteContext &context ) const 129 : : { 130 : 0 : Q_UNUSED( context ) 131 : : 132 : 0 : element.setAttribute( QStringLiteral( "std_dev" ), QString::number( mStdDev, 'f', 16 ) ); 133 : 0 : element.setAttribute( QStringLiteral( "effective_symmetry_point" ), QString::number( mEffectiveSymmetryPoint, 'f', 16 ) ); 134 : 0 : } 135 : : 136 : 0 : void QgsClassificationStandardDeviation::readXml( const QDomElement &element, const QgsReadWriteContext &context ) 137 : : { 138 : 0 : Q_UNUSED( context ) 139 : : 140 : 0 : mStdDev = element.attribute( QStringLiteral( "std_dev" ), QStringLiteral( "1.0" ) ).toDouble(); 141 : 0 : mEffectiveSymmetryPoint = element.attribute( QStringLiteral( "effective_symmetry_point" ), QStringLiteral( "0.0" ) ).toDouble(); 142 : 0 : }