static QList<double> _calcStdDevBreaks( QList<double> values, int classes, QList<int> &labels ) { // C++ implementation of the standard deviation class interval algorithm // as implemented in the 'classInt' package available for the R statistical // prgramming language. // Returns breaks based on '_calcPrettyBreaks' of the centred and scaled // values of 'values', and may have a number of classes different from 'classes'. // If there are no values to process: bail out if ( !values.count() ) return QList<double>(); double mean = 0.0; double stdDev = 0.0; int n = values.count(); double minimum = values[0]; double maximum = values[0]; for ( int i = 0; i < n; i++ ) { mean += values[i]; minimum = qMin( values[i], minimum ); // could use precomputed max and min maximum = qMax( values[i], maximum ); // but have to go through entire list anyway } mean = mean / ( double ) n; double sd = 0.0; for ( int i = 0; i < n; i++ ) { sd = values[i] - mean; stdDev += sd * sd; } stdDev = sqrt( stdDev / n ); QList<double> breaks = _calcPrettyBreaks(( minimum - mean ) / stdDev, ( maximum - mean ) / stdDev, classes ); for ( int i = 0; i < breaks.count(); i++ ) { labels.append(( int ) breaks[i] ); breaks[i] = ( breaks[i] * stdDev ) + mean; } return breaks; } // _calcStdDevBreaks
QgsGraduatedSymbolRendererV2* QgsGraduatedSymbolRendererV2::createRenderer( QgsVectorLayer* vlayer, QString attrName, int classes, Mode mode, QgsSymbolV2* symbol, QgsVectorColorRampV2* ramp, bool inverted ) { if ( classes < 1 ) return NULL; int attrNum = vlayer->fieldNameIndex( attrName ); double minimum; double maximum; QScopedPointer<QgsExpression> expression; if ( attrNum == -1 ) { // try to use expression expression.reset( new QgsExpression( attrName ) ); if ( expression->hasParserError() || !expression->prepare( vlayer->pendingFields() ) ) return 0; // should have a means to report errors QList<double> values; QgsFeatureIterator fit = vlayer->getFeatures(); QgsFeature feature; while ( fit.nextFeature( feature ) ) { values << expression->evaluate( feature ).toDouble(); } qSort( values ); minimum = values.first(); maximum = values.last(); } else { minimum = vlayer->minimumValue( attrNum ).toDouble(); maximum = vlayer->maximumValue( attrNum ).toDouble(); } QgsDebugMsg( QString( "min %1 // max %2" ).arg( minimum ).arg( maximum ) ); QList<double> breaks; QList<int> labels; if ( mode == EqualInterval ) { breaks = _calcEqualIntervalBreaks( minimum, maximum, classes ); } else if ( mode == Pretty ) { breaks = _calcPrettyBreaks( minimum, maximum, classes ); } else if ( mode == Quantile || mode == Jenks || mode == StdDev ) { // get values from layer QList<double> values; QgsFeature f; QStringList lst; if ( expression.isNull() ) lst.append( attrName ); else lst = expression->referencedColumns(); QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ).setSubsetOfAttributes( lst, vlayer->pendingFields() ) ); // create list of non-null attribute values while ( fit.nextFeature( f ) ) { QVariant v = expression.isNull() ? f.attribute( attrNum ) : expression->evaluate( f ); if ( !v.isNull() ) values.append( v.toDouble() ); } // calculate the breaks if ( mode == Quantile ) { breaks = _calcQuantileBreaks( values, classes ); } else if ( mode == Jenks ) { breaks = _calcJenksBreaks( values, classes, minimum, maximum ); } else if ( mode == StdDev ) { breaks = _calcStdDevBreaks( values, classes, labels ); } } else { Q_ASSERT( false ); } QgsRangeList ranges; double lower, upper = minimum; QString label; // "breaks" list contains all values at class breaks plus maximum as last break int i = 0; for ( QList<double>::iterator it = breaks.begin(); it != breaks.end(); ++it, ++i ) { lower = upper; // upper border from last interval upper = *it; if ( mode == StdDev ) { if ( i == 0 ) { label = "< " + QString::number( labels[i], 'i', 0 ) + " Std Dev"; } else if ( i == labels.count() - 1 ) { label = ">= " + QString::number( labels[i-1], 'i', 0 ) + " Std Dev"; } else { label = QString::number( labels[i-1], 'i', 0 ) + " Std Dev" + " - " + QString::number( labels[i], 'i', 0 ) + " Std Dev"; } } else { label = QString::number( lower, 'f', 4 ) + " - " + QString::number( upper, 'f', 4 ); } QgsSymbolV2* newSymbol = symbol->clone(); double colorValue; if ( inverted ) colorValue = ( breaks.count() > 1 ? ( double )( breaks.count() - i - 1 ) / ( breaks.count() - 1 ) : 0 ); else colorValue = ( breaks.count() > 1 ? ( double ) i / ( breaks.count() - 1 ) : 0 ); newSymbol->setColor( ramp->color( colorValue ) ); // color from (0 / cl-1) to (cl-1 / cl-1) ranges.append( QgsRendererRangeV2( lower, upper, newSymbol, label ) ); } QgsGraduatedSymbolRendererV2* r = new QgsGraduatedSymbolRendererV2( attrName, ranges ); r->setSourceSymbol( symbol->clone() ); r->setSourceColorRamp( ramp->clone() ); r->setInvertedColorRamp( inverted ); r->setMode( mode ); return r; }
QgsGraduatedSymbolRendererV2* QgsGraduatedSymbolRendererV2::createRenderer( QgsVectorLayer* vlayer, QString attrName, int classes, Mode mode, QgsSymbolV2* symbol, QgsVectorColorRampV2* ramp ) { if ( classes < 1 ) return NULL; int attrNum = vlayer->fieldNameIndex( attrName ); double minimum = vlayer->minimumValue( attrNum ).toDouble(); double maximum = vlayer->maximumValue( attrNum ).toDouble(); QgsDebugMsg( QString( "min %1 // max %2" ).arg( minimum ).arg( maximum ) ); QList<double> breaks; QList<int> labels; if ( mode == EqualInterval ) { breaks = _calcEqualIntervalBreaks( minimum, maximum, classes ); } else if ( mode == Pretty ) { breaks = _calcPrettyBreaks( minimum, maximum, classes ); } else if ( mode == Quantile || mode == Jenks || mode == StdDev ) { // get values from layer QList<double> values; QgsFeature f; QgsAttributeList lst; lst.append( attrNum ); QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ).setSubsetOfAttributes( lst ) ); // create list of non-null attribute values while ( fit.nextFeature( f ) ) if ( !f.attribute( attrNum ).isNull() ) values.append( f.attribute( attrNum ).toDouble() ); // calculate the breaks if ( mode == Quantile ) { breaks = _calcQuantileBreaks( values, classes ); } else if ( mode == Jenks ) { breaks = _calcJenksBreaks( values, classes, minimum, maximum ); } else if ( mode == StdDev ) { breaks = _calcStdDevBreaks( values, classes, labels ); } } else { Q_ASSERT( false ); } QgsRangeList ranges; double lower, upper = minimum; QString label; // "breaks" list contains all values at class breaks plus maximum as last break int i = 0; for ( QList<double>::iterator it = breaks.begin(); it != breaks.end(); ++it, ++i ) { lower = upper; // upper border from last interval upper = *it; if ( mode == StdDev ) { if ( i == 0 ) { label = "< " + QString::number( labels[i], 'i', 0 ) + " Std Dev"; } else if ( i == labels.count() - 1 ) { label = ">= " + QString::number( labels[i-1], 'i', 0 ) + " Std Dev"; } else { label = QString::number( labels[i-1], 'i', 0 ) + " Std Dev" + " - " + QString::number( labels[i], 'i', 0 ) + " Std Dev"; } } else { label = QString::number( lower, 'f', 4 ) + " - " + QString::number( upper, 'f', 4 ); } QgsSymbolV2* newSymbol = symbol->clone(); double colorValue = ( breaks.count() > 1 ? ( double ) i / ( breaks.count() - 1 ) : 0 ); newSymbol->setColor( ramp->color( colorValue ) ); // color from (0 / cl-1) to (cl-1 / cl-1) ranges.append( QgsRendererRangeV2( lower, upper, newSymbol, label ) ); } QgsGraduatedSymbolRendererV2* r = new QgsGraduatedSymbolRendererV2( attrName, ranges ); r->setSourceSymbol( symbol->clone() ); r->setSourceColorRamp( ramp->clone() ); r->setMode( mode ); return r; }
void QgsGraduatedSymbolRendererV2::updateClasses( QgsVectorLayer *vlayer, Mode mode, int nclasses ) { if ( mAttrName.isEmpty() ) return; setMode( mode ); // Custom classes are not recalculated if ( mode == Custom ) return; if ( nclasses < 1 ) nclasses = 1; QList<double> values; bool valuesLoaded = false; double minimum; double maximum; int attrNum = vlayer->fieldNameIndex( mAttrName ); if ( attrNum == -1 ) { values = getDataValues( vlayer ); if ( values.isEmpty() ) return; qSort( values ); minimum = values.first(); maximum = values.last(); valuesLoaded = true; } else { minimum = vlayer->minimumValue( attrNum ).toDouble(); maximum = vlayer->maximumValue( attrNum ).toDouble(); } QgsDebugMsg( QString( "min %1 // max %2" ).arg( minimum ).arg( maximum ) ); QList<double> breaks; QList<double> labels; if ( mode == EqualInterval ) { breaks = _calcEqualIntervalBreaks( minimum, maximum, nclasses ); } else if ( mode == Pretty ) { breaks = _calcPrettyBreaks( minimum, maximum, nclasses ); } else if ( mode == Quantile || mode == Jenks || mode == StdDev ) { // get values from layer if ( !valuesLoaded ) { values = getDataValues( vlayer ); } // calculate the breaks if ( mode == Quantile ) { breaks = _calcQuantileBreaks( values, nclasses ); } else if ( mode == Jenks ) { breaks = _calcJenksBreaks( values, nclasses, minimum, maximum ); } else if ( mode == StdDev ) { breaks = _calcStdDevBreaks( values, nclasses, labels ); } } else { Q_ASSERT( false ); } double lower, upper = minimum; QString label; deleteAllClasses(); // "breaks" list contains all values at class breaks plus maximum as last break int i = 0; for ( QList<double>::iterator it = breaks.begin(); it != breaks.end(); ++it, ++i ) { lower = upper; // upper border from last interval upper = *it; // Label - either StdDev label or default label for a range if ( mode == StdDev ) { if ( i == 0 ) { label = "< " + QString::number( labels[i], 'f', 2 ) + " Std Dev"; } else if ( i == labels.count() - 1 ) { label = ">= " + QString::number( labels[i-1], 'f', 2 ) + " Std Dev"; } else { label = QString::number( labels[i-1], 'f', 2 ) + " Std Dev" + " - " + QString::number( labels[i], 'f', 2 ) + " Std Dev"; } } else { label = mLabelFormat.labelForRange( lower, upper ); } QgsSymbolV2* newSymbol = mSourceSymbol ? mSourceSymbol->clone() : QgsSymbolV2::defaultSymbol( vlayer->geometryType() ); addClass( QgsRendererRangeV2( lower, upper, newSymbol, label ) ); } updateColorRamp( 0, mInvertedColorRamp ); }