mirror of
https://github.com/qgis/QGIS.git
synced 2025-03-08 00:02:35 -05:00
refactor QgsGraduatedSymbolRenderer (core)
This commit is contained in:
parent
68e24ad27e
commit
38f62f2276
@ -13,6 +13,10 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include <QDomDocument>
|
||||
#include <QDomElement>
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#include "qgsgraduatedsymbolrenderer.h"
|
||||
|
||||
@ -35,12 +39,11 @@
|
||||
#include "qgsvectorlayerutils.h"
|
||||
#include "qgsexpressioncontextutils.h"
|
||||
#include "qgsstyleentityvisitor.h"
|
||||
|
||||
#include <QDomDocument>
|
||||
#include <QDomElement>
|
||||
#include <QSettings> // for legend
|
||||
#include <limits> // for jenks classification
|
||||
#include <ctime>
|
||||
#include "qgsclassificationmethod.h"
|
||||
#include "qgsclassificationequalinterval.h"
|
||||
#include "qgsapplication.h"
|
||||
#include "qgsclassificationmethodregistry.h"
|
||||
#include "qgsclassificationcustom.h"
|
||||
|
||||
|
||||
QgsGraduatedSymbolRenderer::QgsGraduatedSymbolRenderer( const QString &attrName, const QgsRangeList &ranges )
|
||||
@ -57,6 +60,8 @@ QgsGraduatedSymbolRenderer::QgsGraduatedSymbolRenderer( const QString &attrName,
|
||||
{
|
||||
mRanges << range;
|
||||
}
|
||||
|
||||
mClassificationMethod.reset( new QgsClassificationCustom() );
|
||||
}
|
||||
|
||||
QgsGraduatedSymbolRenderer::~QgsGraduatedSymbolRenderer()
|
||||
@ -232,9 +237,17 @@ bool QgsGraduatedSymbolRenderer::updateRangeUpperValue( int rangeIndex, double v
|
||||
if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
|
||||
return false;
|
||||
QgsRendererRange &range = mRanges[rangeIndex];
|
||||
bool isDefaultLabel = range.label() == mLabelFormat.labelForRange( range );
|
||||
QgsClassificationMethod::ClassPosition pos = QgsClassificationMethod::Inner;
|
||||
if ( rangeIndex == 0 )
|
||||
pos = QgsClassificationMethod::LowerBound;
|
||||
else if ( rangeIndex == mRanges.count() )
|
||||
pos = QgsClassificationMethod::UpperBound;
|
||||
|
||||
bool isDefaultLabel = mClassificationMethod->labelForRange( range, pos ) == range.label();
|
||||
range.setUpperValue( value );
|
||||
if ( isDefaultLabel ) range.setLabel( mLabelFormat.labelForRange( range ) );
|
||||
if ( isDefaultLabel )
|
||||
range.setLabel( mClassificationMethod->labelForRange( range, pos ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -242,10 +255,19 @@ bool QgsGraduatedSymbolRenderer::updateRangeLowerValue( int rangeIndex, double v
|
||||
{
|
||||
if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
|
||||
return false;
|
||||
|
||||
QgsRendererRange &range = mRanges[rangeIndex];
|
||||
bool isDefaultLabel = range.label() == mLabelFormat.labelForRange( range );
|
||||
QgsClassificationMethod::ClassPosition pos = QgsClassificationMethod::Inner;
|
||||
if ( rangeIndex == 0 )
|
||||
pos = QgsClassificationMethod::LowerBound;
|
||||
else if ( rangeIndex == mRanges.count() )
|
||||
pos = QgsClassificationMethod::UpperBound;
|
||||
|
||||
bool isDefaultLabel = mClassificationMethod->labelForRange( range, pos ) == range.label();
|
||||
range.setLowerValue( value );
|
||||
if ( isDefaultLabel ) range.setLabel( mLabelFormat.labelForRange( range ) );
|
||||
if ( isDefaultLabel )
|
||||
range.setLabel( mClassificationMethod->labelForRange( range, pos ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -268,11 +290,8 @@ QString QgsGraduatedSymbolRenderer::dump() const
|
||||
QgsGraduatedSymbolRenderer *QgsGraduatedSymbolRenderer::clone() const
|
||||
{
|
||||
QgsGraduatedSymbolRenderer *r = new QgsGraduatedSymbolRenderer( mAttrName, mRanges );
|
||||
r->setMode( mMode );
|
||||
r->setUseSymmetricMode( mUseSymmetricMode );
|
||||
r->setSymmetryPoint( mSymmetryPoint );
|
||||
r->setListForCboPrettyBreaks( mListForCboPrettyBreaks );
|
||||
r->setAstride( mAstride );
|
||||
|
||||
r->setClassificationMethod( mClassificationMethod->clone() );
|
||||
|
||||
if ( mSourceSymbol )
|
||||
r->setSourceSymbol( mSourceSymbol->clone() );
|
||||
@ -282,7 +301,6 @@ QgsGraduatedSymbolRenderer *QgsGraduatedSymbolRenderer::clone() const
|
||||
}
|
||||
r->setUsingSymbolLevels( usingSymbolLevels() );
|
||||
r->setDataDefinedSizeLegend( mDataDefinedSizeLegend ? new QgsDataDefinedSizeLegend( *mDataDefinedSizeLegend ) : nullptr );
|
||||
r->setLabelFormat( labelFormat() );
|
||||
r->setGraduatedMethod( graduatedMethod() );
|
||||
copyRendererData( r );
|
||||
return r;
|
||||
@ -337,317 +355,16 @@ bool QgsGraduatedSymbolRenderer::accept( QgsStyleEntityVisitorInterface *visitor
|
||||
|
||||
void QgsGraduatedSymbolRenderer::makeBreaksSymmetric( QList<double> &breaks, double symmetryPoint, bool astride )
|
||||
{
|
||||
// remove the breaks that are above the existing opposite sign classes
|
||||
// to keep colors symmetrically balanced around symmetryPoint
|
||||
// if astride is true, remove the symmetryPoint break so that
|
||||
// the 2 classes form only one
|
||||
|
||||
if ( breaks.size() > 1 ) //to avoid crash when only 1 class
|
||||
{
|
||||
std::sort( breaks.begin(), breaks.end() );
|
||||
// breaks contain the maximum of the distrib but not the minimum
|
||||
double distBelowSymmetricValue = std::fabs( breaks[0] - symmetryPoint );
|
||||
double distAboveSymmetricValue = std::fabs( breaks[ breaks.size() - 2 ] - symmetryPoint ) ;
|
||||
double absMin = std::min( distAboveSymmetricValue, distBelowSymmetricValue );
|
||||
|
||||
// make symmetric
|
||||
for ( int i = 0; i <= breaks.size() - 2; ++i )
|
||||
{
|
||||
// part after "absMin" is for doubles rounding issues
|
||||
if ( std::fabs( breaks.at( i ) - symmetryPoint ) >= ( absMin - std::fabs( breaks[0] - breaks[1] ) / 100. ) )
|
||||
{
|
||||
breaks.removeAt( i );
|
||||
--i;
|
||||
}
|
||||
}
|
||||
// remove symmetry point
|
||||
if ( astride ) // && breaks.indexOf( symmetryPoint ) != -1) // if symmetryPoint is found
|
||||
{
|
||||
breaks.removeAt( breaks.indexOf( symmetryPoint ) );
|
||||
}
|
||||
}
|
||||
return QgsClassificationMethod::makeBreaksSymmetric( breaks, symmetryPoint, astride );
|
||||
}
|
||||
|
||||
QList<double> QgsGraduatedSymbolRenderer::calcEqualIntervalBreaks( double minimum, double maximum, int classes, bool useSymmetricMode, double symmetryPoint, bool astride )
|
||||
{
|
||||
// Equal interval algorithm
|
||||
// Returns breaks based on dividing the range ('minimum' to 'maximum') into 'classes' parts.
|
||||
QList<double> breaks;
|
||||
if ( !useSymmetricMode ) // nomal mode
|
||||
{
|
||||
double step = ( maximum - minimum ) / classes;
|
||||
|
||||
double value = minimum;
|
||||
breaks.reserve( classes );
|
||||
for ( int i = 0; i < classes; i++ )
|
||||
{
|
||||
value += step;
|
||||
breaks.append( value );
|
||||
}
|
||||
// floating point arithmetics is not precise:
|
||||
// set the last break to be exactly maximum so we do not miss it
|
||||
breaks[classes - 1] = maximum;
|
||||
}
|
||||
else if ( useSymmetricMode ) // symmetric mode
|
||||
{
|
||||
double distBelowSymmetricValue = std::abs( minimum - symmetryPoint );
|
||||
double distAboveSymmetricValue = std::abs( maximum - symmetryPoint ) ;
|
||||
|
||||
if ( astride )
|
||||
{
|
||||
if ( classes % 2 == 0 ) // we want odd number of classes
|
||||
++classes;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( classes % 2 == 1 ) // we want even number of classes
|
||||
++classes;
|
||||
}
|
||||
double step = 2 * std::min( distBelowSymmetricValue, distAboveSymmetricValue ) / classes;
|
||||
|
||||
breaks.reserve( classes );
|
||||
double value = ( distBelowSymmetricValue < distAboveSymmetricValue ) ? minimum : maximum - classes * step;
|
||||
|
||||
for ( int i = 0; i < classes; i++ )
|
||||
{
|
||||
value += step;
|
||||
breaks.append( value );
|
||||
}
|
||||
breaks[classes - 1] = maximum;
|
||||
}
|
||||
return breaks;
|
||||
}
|
||||
|
||||
static QList<double> _calcQuantileBreaks( QList<double> values, int classes )
|
||||
{
|
||||
// q-th quantile of a data set:
|
||||
// value where q fraction of data is below and (1-q) fraction is above this value
|
||||
// Xq = (1 - r) * X_NI1 + r * X_NI2
|
||||
// NI1 = (int) (q * (n+1))
|
||||
// NI2 = NI1 + 1
|
||||
// r = q * (n+1) - (int) (q * (n+1))
|
||||
// (indices of X: 1...n)
|
||||
|
||||
// sort the values first
|
||||
std::sort( values.begin(), values.end() );
|
||||
|
||||
QList<double> breaks;
|
||||
|
||||
// If there are no values to process: bail out
|
||||
if ( values.isEmpty() )
|
||||
return breaks;
|
||||
|
||||
int n = values.count();
|
||||
double Xq = n > 0 ? values[0] : 0.0;
|
||||
|
||||
breaks.reserve( classes );
|
||||
for ( int i = 1; i < classes; i++ )
|
||||
{
|
||||
if ( n > 1 )
|
||||
{
|
||||
double q = i / static_cast< double >( classes );
|
||||
double a = q * ( n - 1 );
|
||||
int aa = static_cast< int >( a );
|
||||
|
||||
double r = a - aa;
|
||||
Xq = ( 1 - r ) * values[aa] + r * values[aa + 1];
|
||||
}
|
||||
breaks.append( Xq );
|
||||
}
|
||||
|
||||
breaks.append( values[ n - 1 ] );
|
||||
|
||||
return breaks;
|
||||
}
|
||||
|
||||
static QList<double> _calcStdDevBreaks( QList<double> values, int classes, QList<double> &labels, bool useSymmetricMode, double symmetryPoint, bool astride )
|
||||
{
|
||||
|
||||
// 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 'prettyBreaks' 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.isEmpty() )
|
||||
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 = std::min( values[i], minimum ); // could use precomputed max and min
|
||||
maximum = std::max( values[i], maximum ); // but have to go through entire list anyway
|
||||
}
|
||||
mean = mean / static_cast< double >( n );
|
||||
|
||||
double sd = 0.0;
|
||||
for ( int i = 0; i < n; i++ )
|
||||
{
|
||||
sd = values[i] - mean;
|
||||
stdDev += sd * sd;
|
||||
}
|
||||
stdDev = std::sqrt( stdDev / n );
|
||||
|
||||
if ( !useSymmetricMode )
|
||||
symmetryPoint = mean; // otherwise symmetryPoint = symmetryPoint
|
||||
|
||||
QList<double> breaks = QgsSymbolLayerUtils::prettyBreaks( ( minimum - symmetryPoint ) / stdDev, ( maximum - symmetryPoint ) / stdDev, classes );
|
||||
QgsGraduatedSymbolRenderer::makeBreaksSymmetric( breaks, 0.0, astride ); //0.0 because breaks where computed on a centered distribution
|
||||
|
||||
for ( int i = 0; i < breaks.count(); i++ ) //unNormalize breaks and put labels
|
||||
{
|
||||
labels.append( breaks[i] );
|
||||
breaks[i] = ( breaks[i] * stdDev ) + symmetryPoint;
|
||||
}
|
||||
return breaks;
|
||||
} // _calcStdDevBreaks
|
||||
|
||||
static QList<double> _calcJenksBreaks( QList<double> values, int classes,
|
||||
double minimum, double maximum,
|
||||
int maximumSize = 3000 )
|
||||
{
|
||||
// Jenks Optimal (Natural Breaks) algorithm
|
||||
// Based on the Jenks algorithm from the 'classInt' package available for
|
||||
// the R statistical prgramming language, and from Python code from here:
|
||||
// http://danieljlewis.org/2010/06/07/jenks-natural-breaks-algorithm-in-python/
|
||||
// and is based on a JAVA and Fortran code available here:
|
||||
// https://stat.ethz.ch/pipermail/r-sig-geo/2006-March/000811.html
|
||||
|
||||
// Returns class breaks such that classes are internally homogeneous while
|
||||
// assuring heterogeneity among classes.
|
||||
|
||||
if ( values.isEmpty() )
|
||||
return QList<double>();
|
||||
|
||||
if ( classes <= 1 )
|
||||
{
|
||||
return QList<double>() << maximum;
|
||||
}
|
||||
|
||||
if ( classes >= values.size() )
|
||||
{
|
||||
return values;
|
||||
}
|
||||
|
||||
QVector<double> sample;
|
||||
|
||||
// if we have lots of values, we need to take a random sample
|
||||
if ( values.size() > maximumSize )
|
||||
{
|
||||
// for now, sample at least maximumSize values or a 10% sample, whichever
|
||||
// is larger. This will produce a more representative sample for very large
|
||||
// layers, but could end up being computationally intensive...
|
||||
|
||||
sample.resize( std::max( maximumSize, values.size() / 10 ) );
|
||||
|
||||
QgsDebugMsg( QStringLiteral( "natural breaks (jenks) sample size: %1" ).arg( sample.size() ) );
|
||||
QgsDebugMsg( QStringLiteral( "values:%1" ).arg( values.size() ) );
|
||||
|
||||
sample[ 0 ] = minimum;
|
||||
sample[ 1 ] = maximum;
|
||||
for ( int i = 2; i < sample.size(); i++ )
|
||||
{
|
||||
// pick a random integer from 0 to n
|
||||
double r = qrand();
|
||||
int j = std::floor( r / RAND_MAX * ( values.size() - 1 ) );
|
||||
sample[ i ] = values[ j ];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sample = values.toVector();
|
||||
}
|
||||
|
||||
int n = sample.size();
|
||||
|
||||
// sort the sample values
|
||||
std::sort( sample.begin(), sample.end() );
|
||||
|
||||
QVector< QVector<int> > matrixOne( n + 1 );
|
||||
QVector< QVector<double> > matrixTwo( n + 1 );
|
||||
|
||||
for ( int i = 0; i <= n; i++ )
|
||||
{
|
||||
matrixOne[i].resize( classes + 1 );
|
||||
matrixTwo[i].resize( classes + 1 );
|
||||
}
|
||||
|
||||
for ( int i = 1; i <= classes; i++ )
|
||||
{
|
||||
matrixOne[0][i] = 1;
|
||||
matrixOne[1][i] = 1;
|
||||
matrixTwo[0][i] = 0.0;
|
||||
for ( int j = 2; j <= n; j++ )
|
||||
{
|
||||
matrixTwo[j][i] = std::numeric_limits<double>::max();
|
||||
}
|
||||
}
|
||||
|
||||
for ( int l = 2; l <= n; l++ )
|
||||
{
|
||||
double s1 = 0.0;
|
||||
double s2 = 0.0;
|
||||
int w = 0;
|
||||
|
||||
double v = 0.0;
|
||||
|
||||
for ( int m = 1; m <= l; m++ )
|
||||
{
|
||||
int i3 = l - m + 1;
|
||||
|
||||
double val = sample[ i3 - 1 ];
|
||||
|
||||
s2 += val * val;
|
||||
s1 += val;
|
||||
w++;
|
||||
|
||||
v = s2 - ( s1 * s1 ) / static_cast< double >( w );
|
||||
int i4 = i3 - 1;
|
||||
if ( i4 != 0 )
|
||||
{
|
||||
for ( int j = 2; j <= classes; j++ )
|
||||
{
|
||||
if ( matrixTwo[l][j] >= v + matrixTwo[i4][j - 1] )
|
||||
{
|
||||
matrixOne[l][j] = i4;
|
||||
matrixTwo[l][j] = v + matrixTwo[i4][j - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
matrixOne[l][1] = 1;
|
||||
matrixTwo[l][1] = v;
|
||||
}
|
||||
|
||||
QVector<double> breaks( classes );
|
||||
breaks[classes - 1] = sample[n - 1];
|
||||
|
||||
for ( int j = classes, k = n; j >= 2; j-- )
|
||||
{
|
||||
int id = matrixOne[k][j] - 1;
|
||||
breaks[j - 2] = sample[id];
|
||||
k = matrixOne[k][j] - 1;
|
||||
}
|
||||
|
||||
return breaks.toList();
|
||||
} //_calcJenksBreaks
|
||||
|
||||
static QStringList _breaksAsStrings( const QList<double> &breaks ) // get QStringList from QList<double> without maxi break (min is not in)
|
||||
{
|
||||
QStringList breaksAsStrings;
|
||||
for ( int i = 0; i < breaks.count() - 1; i++ )
|
||||
{
|
||||
breaksAsStrings << QString::number( breaks.at( i ), 'f', 2 );
|
||||
}
|
||||
return breaksAsStrings;
|
||||
QgsClassificationEqualInterval *method = new QgsClassificationEqualInterval();
|
||||
method->setSymmetricMode( useSymmetricMode, symmetryPoint, astride );
|
||||
QList<QgsClassificationRange> _classes = method->classes( minimum, maximum, classes );
|
||||
delete method;
|
||||
return QgsClassificationMethod::listToValues( _classes );
|
||||
}
|
||||
|
||||
QgsGraduatedSymbolRenderer *QgsGraduatedSymbolRenderer::createRenderer(
|
||||
@ -664,17 +381,26 @@ QgsGraduatedSymbolRenderer *QgsGraduatedSymbolRenderer::createRenderer(
|
||||
bool astride
|
||||
)
|
||||
{
|
||||
Q_UNUSED( listForCboPrettyBreaks )
|
||||
|
||||
QgsRangeList ranges;
|
||||
QgsGraduatedSymbolRenderer *r = new QgsGraduatedSymbolRenderer( attrName, ranges );
|
||||
r->setSourceSymbol( symbol->clone() );
|
||||
r->setSourceColorRamp( ramp->clone() );
|
||||
r->setMode( mode );
|
||||
r->setUseSymmetricMode( useSymmetricMode );
|
||||
r->setSymmetryPoint( symmetryPoint );
|
||||
r->setListForCboPrettyBreaks( listForCboPrettyBreaks );
|
||||
r->setAstride( astride );
|
||||
r->setLabelFormat( labelFormat );
|
||||
r->updateClasses( vlayer, mode, classes, useSymmetricMode, symmetryPoint, astride );
|
||||
|
||||
QString methodId = methodIdFromMode( mode );
|
||||
QgsClassificationMethod *method = QgsApplication::classificationMethodRegistry()->method( methodId );
|
||||
|
||||
if ( method )
|
||||
{
|
||||
method->setSymmetricMode( useSymmetricMode, symmetryPoint, astride );
|
||||
method->setLabelFormat( labelFormat.format() );
|
||||
method->setLabelTrimTrailingZeroes( labelFormat.trimTrailingZeroes() );
|
||||
method->setLabelPrecision( labelFormat.precision() );
|
||||
}
|
||||
r->setClassificationMethod( method );
|
||||
|
||||
r->updateClasses( vlayer, classes );
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -683,122 +409,30 @@ void QgsGraduatedSymbolRenderer::updateClasses( QgsVectorLayer *vlayer, Mode mod
|
||||
{
|
||||
if ( mAttrName.isEmpty() )
|
||||
return;
|
||||
setMode( mode );
|
||||
setSymmetryPoint( symmetryPoint );
|
||||
setUseSymmetricMode( useSymmetricMode );
|
||||
setAstride( astride );
|
||||
|
||||
// Custom classes are not recalculated
|
||||
if ( mode == Custom )
|
||||
QString methodId = methodIdFromMode( mode );
|
||||
QgsClassificationMethod *method = QgsApplication::classificationMethodRegistry()->method( methodId );
|
||||
if ( method )
|
||||
{
|
||||
method->setSymmetricMode( useSymmetricMode, symmetryPoint, astride );
|
||||
}
|
||||
|
||||
updateClasses( vlayer, nclasses );
|
||||
}
|
||||
|
||||
void QgsGraduatedSymbolRenderer::updateClasses( const QgsVectorLayer *vl, int numberOfClasses )
|
||||
{
|
||||
if ( mClassificationMethod->id() == QgsClassificationCustom::METHOD_ID )
|
||||
return;
|
||||
|
||||
if ( nclasses < 1 )
|
||||
nclasses = 1;
|
||||
QList<QgsClassificationRange> classes = mClassificationMethod->classes( vl, mAttrName, numberOfClasses );
|
||||
|
||||
QList<double> values;
|
||||
bool valuesLoaded = false;
|
||||
double minimum;
|
||||
double maximum;
|
||||
|
||||
int attrNum = vlayer->fields().lookupField( mAttrName );
|
||||
|
||||
bool ok;
|
||||
if ( attrNum == -1 )
|
||||
{
|
||||
values = QgsVectorLayerUtils::getDoubleValues( vlayer, mAttrName, ok );
|
||||
if ( !ok || values.isEmpty() )
|
||||
return;
|
||||
|
||||
auto result = std::minmax_element( values.begin(), values.end() );
|
||||
minimum = *result.first;
|
||||
maximum = *result.second;
|
||||
valuesLoaded = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
minimum = vlayer->minimumValue( attrNum ).toDouble();
|
||||
maximum = vlayer->maximumValue( attrNum ).toDouble();
|
||||
}
|
||||
|
||||
QgsDebugMsg( QStringLiteral( "min %1 // max %2" ).arg( minimum ).arg( maximum ) );
|
||||
QList<double> breaks;
|
||||
QList<double> labels;
|
||||
|
||||
switch ( mode )
|
||||
{
|
||||
case EqualInterval:
|
||||
{
|
||||
breaks = QgsGraduatedSymbolRenderer::calcEqualIntervalBreaks( minimum, maximum, nclasses, mUseSymmetricMode, symmetryPoint, astride );
|
||||
break;
|
||||
}
|
||||
|
||||
case Pretty:
|
||||
{
|
||||
breaks = QgsSymbolLayerUtils::prettyBreaks( minimum, maximum, nclasses );
|
||||
setListForCboPrettyBreaks( _breaksAsStrings( breaks ) );
|
||||
|
||||
if ( useSymmetricMode )
|
||||
QgsGraduatedSymbolRenderer::makeBreaksSymmetric( breaks, symmetryPoint, astride );
|
||||
break;
|
||||
}
|
||||
|
||||
case Quantile:
|
||||
case Jenks:
|
||||
case StdDev:
|
||||
{
|
||||
// get values from layer
|
||||
if ( !valuesLoaded )
|
||||
{
|
||||
values = QgsVectorLayerUtils::getDoubleValues( vlayer, mAttrName, ok );
|
||||
}
|
||||
// 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, mUseSymmetricMode, symmetryPoint, astride );
|
||||
break;
|
||||
}
|
||||
|
||||
case Custom:
|
||||
Q_ASSERT( false );
|
||||
break;
|
||||
}
|
||||
|
||||
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 )
|
||||
for ( QList<QgsClassificationRange>::iterator it = classes.begin(); it != classes.end(); ++it )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
QgsSymbol *newSymbol = mSourceSymbol ? mSourceSymbol->clone() : QgsSymbol::defaultSymbol( vlayer->geometryType() );
|
||||
addClass( QgsRendererRange( lower, upper, newSymbol, label ) );
|
||||
QgsSymbol *newSymbol = mSourceSymbol ? mSourceSymbol->clone() : QgsSymbol::defaultSymbol( vl->geometryType() );
|
||||
addClass( QgsRendererRange( *it, newSymbol ) );
|
||||
}
|
||||
updateColorRamp( nullptr );
|
||||
}
|
||||
@ -873,37 +507,62 @@ QgsFeatureRenderer *QgsGraduatedSymbolRenderer::create( QDomElement &element, co
|
||||
}
|
||||
|
||||
// try to load mode
|
||||
QDomElement modeElem = element.firstChildElement( QStringLiteral( "mode" ) );
|
||||
|
||||
QDomElement modeElem = element.firstChildElement( QStringLiteral( "mode" ) ); // old format, backward compatibility
|
||||
QDomElement methodElem = element.firstChildElement( QStringLiteral( "classificationMethod" ) );
|
||||
QgsClassificationMethod *method = nullptr;
|
||||
|
||||
// TODO QGIS 4 Remove
|
||||
// backward compatibility for QGIS project < 3.10
|
||||
if ( !modeElem.isNull() )
|
||||
{
|
||||
QString modeString = modeElem.attribute( QStringLiteral( "name" ) );
|
||||
QString methodId;
|
||||
if ( modeString == QLatin1String( "equal" ) )
|
||||
r->setMode( EqualInterval );
|
||||
methodId = QLatin1String( "EqualInterval" );
|
||||
else if ( modeString == QLatin1String( "quantile" ) )
|
||||
r->setMode( Quantile );
|
||||
methodId = QLatin1String( "Quantile" );
|
||||
else if ( modeString == QLatin1String( "jenks" ) )
|
||||
r->setMode( Jenks );
|
||||
methodId = QLatin1String( "Jenks" );
|
||||
else if ( modeString == QLatin1String( "stddev" ) )
|
||||
r->setMode( StdDev );
|
||||
methodId = QLatin1String( "StdDev" );
|
||||
else if ( modeString == QLatin1String( "pretty" ) )
|
||||
r->setMode( Pretty );
|
||||
}
|
||||
methodId = QLatin1String( "Pretty" );
|
||||
|
||||
// symmetric mode
|
||||
QDomElement symmetricModeElem = element.firstChildElement( QStringLiteral( "symmetricMode" ) );
|
||||
if ( !symmetricModeElem.isNull() )
|
||||
method = QgsApplication::classificationMethodRegistry()->method( methodId );
|
||||
|
||||
// symmetric mode
|
||||
QDomElement symmetricModeElem = element.firstChildElement( QStringLiteral( "symmetricMode" ) );
|
||||
if ( !symmetricModeElem.isNull() )
|
||||
{
|
||||
// symmetry
|
||||
QString symmetricEnabled = symmetricModeElem.attribute( QStringLiteral( "enabled" ) );
|
||||
QString symmetricPointString = symmetricModeElem.attribute( QStringLiteral( "symmetryPoint" ) );
|
||||
QString astrideEnabled = symmetricModeElem.attribute( QStringLiteral( "astride" ) );
|
||||
method->setSymmetricMode( symmetricEnabled == QLatin1String( "true" ), symmetricPointString.toDouble(), astrideEnabled == QLatin1String( "true" ) );
|
||||
}
|
||||
QDomElement labelFormatElem = element.firstChildElement( QStringLiteral( "labelformat" ) );
|
||||
if ( !labelFormatElem.isNull() )
|
||||
{
|
||||
// label format
|
||||
QString format = labelFormatElem.attribute( QStringLiteral( "format" ), "%1" + QStringLiteral( " - " ) + "%2" );
|
||||
int precision = labelFormatElem.attribute( QStringLiteral( "decimalplaces" ), QStringLiteral( "4" ) ).toInt();
|
||||
bool trimTrailingZeroes = labelFormatElem.attribute( QStringLiteral( "trimtrailingzeroes" ), QStringLiteral( "false" ) ) == QLatin1String( "true" );
|
||||
method->setLabelFormat( format );
|
||||
method->setLabelPrecision( precision );
|
||||
method->setLabelTrimTrailingZeroes( trimTrailingZeroes );
|
||||
}
|
||||
// End of backward compatibility
|
||||
}
|
||||
else
|
||||
{
|
||||
QString symmetricEnabled = symmetricModeElem.attribute( QStringLiteral( "enabled" ) );
|
||||
symmetricEnabled == QLatin1String( "true" ) ? r->setUseSymmetricMode( true ) : r->setUseSymmetricMode( false );
|
||||
|
||||
QString symmetricPointString = symmetricModeElem.attribute( QStringLiteral( "symmetryPoint" ) );
|
||||
r->setSymmetryPoint( symmetricPointString.toDouble() );
|
||||
QString breaksForPretty = symmetricModeElem.attribute( QStringLiteral( "valueForCboPrettyBreaks" ) );
|
||||
r->setListForCboPrettyBreaks( breaksForPretty.split( '/' ) );
|
||||
|
||||
QString astrideEnabled = symmetricModeElem.attribute( QStringLiteral( "astride" ) );
|
||||
astrideEnabled == QLatin1String( "true" ) ? r->setAstride( true ) : r->setAstride( false );
|
||||
// QGIS project 3.10+
|
||||
method = QgsClassificationMethod::create( methodElem, context );
|
||||
}
|
||||
|
||||
// apply the method
|
||||
r->setClassificationMethod( method );
|
||||
|
||||
QDomElement rotationElem = element.firstChildElement( QStringLiteral( "rotation" ) );
|
||||
if ( !rotationElem.isNull() && !rotationElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
|
||||
{
|
||||
@ -933,20 +592,12 @@ QgsFeatureRenderer *QgsGraduatedSymbolRenderer::create( QDomElement &element, co
|
||||
}
|
||||
}
|
||||
|
||||
QDomElement labelFormatElem = element.firstChildElement( QStringLiteral( "labelformat" ) );
|
||||
if ( ! labelFormatElem.isNull() )
|
||||
{
|
||||
QgsRendererRangeLabelFormat labelFormat;
|
||||
labelFormat.setFromDomElement( labelFormatElem );
|
||||
r->setLabelFormat( labelFormat );
|
||||
}
|
||||
|
||||
QDomElement ddsLegendSizeElem = element.firstChildElement( QStringLiteral( "data-defined-size-legend" ) );
|
||||
if ( !ddsLegendSizeElem.isNull() )
|
||||
{
|
||||
r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) );
|
||||
}
|
||||
// TODO: symbol levels
|
||||
// TODO: symbol levels
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -1002,54 +653,9 @@ QDomElement QgsGraduatedSymbolRenderer::save( QDomDocument &doc, const QgsReadWr
|
||||
rendererElem.appendChild( colorRampElem );
|
||||
}
|
||||
|
||||
// save mode
|
||||
QString modeString;
|
||||
switch ( mMode )
|
||||
{
|
||||
case EqualInterval:
|
||||
modeString = QStringLiteral( "equal" );
|
||||
break;
|
||||
case Quantile:
|
||||
modeString = QStringLiteral( "quantile" );
|
||||
break;
|
||||
case Jenks:
|
||||
modeString = QStringLiteral( "jenks" );
|
||||
break;
|
||||
case StdDev:
|
||||
modeString = QStringLiteral( "stddev" );
|
||||
break;
|
||||
case Pretty:
|
||||
modeString = QStringLiteral( "pretty" );
|
||||
break;
|
||||
case Custom:
|
||||
break;
|
||||
}
|
||||
if ( !modeString.isEmpty() )
|
||||
{
|
||||
QDomElement modeElem = doc.createElement( QStringLiteral( "mode" ) );
|
||||
modeElem.setAttribute( QStringLiteral( "name" ), modeString );
|
||||
rendererElem.appendChild( modeElem );
|
||||
}
|
||||
|
||||
// symmetry
|
||||
QDomElement symmetricModeElem = doc.createElement( QStringLiteral( "symmetricMode" ) );
|
||||
symmetricModeElem.setAttribute( QStringLiteral( "enabled" ), mUseSymmetricMode ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
|
||||
symmetricModeElem.setAttribute( QStringLiteral( "symmetryPoint" ), mSymmetryPoint );
|
||||
symmetricModeElem.setAttribute( QStringLiteral( "astride" ), mAstride ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
|
||||
if ( Pretty == mMode )
|
||||
{
|
||||
QString breaks;
|
||||
for ( int i = 0; i < mListForCboPrettyBreaks.size() - 1; i++ ) // -1 to write 1/2/3 instead of 1/2/3/
|
||||
{
|
||||
breaks.append( mListForCboPrettyBreaks.at( i ) );
|
||||
breaks.append( '/' );
|
||||
}
|
||||
if ( mListForCboPrettyBreaks.size() > 0 ) //make sure we can go at size-1
|
||||
breaks.append( mListForCboPrettyBreaks.at( mListForCboPrettyBreaks.size() - 1 ) ); //add the last break
|
||||
symmetricModeElem.setAttribute( QStringLiteral( "valueForCboPrettyBreaks" ), breaks );
|
||||
}
|
||||
|
||||
rendererElem.appendChild( symmetricModeElem );
|
||||
// save classification method
|
||||
QDomElement classificationMethodElem = mClassificationMethod->save( doc, context );
|
||||
rendererElem.appendChild( classificationMethodElem );
|
||||
|
||||
QDomElement rotationElem = doc.createElement( QStringLiteral( "rotation" ) );
|
||||
rendererElem.appendChild( rotationElem );
|
||||
@ -1057,10 +663,6 @@ QDomElement QgsGraduatedSymbolRenderer::save( QDomDocument &doc, const QgsReadWr
|
||||
QDomElement sizeScaleElem = doc.createElement( QStringLiteral( "sizescale" ) );
|
||||
rendererElem.appendChild( sizeScaleElem );
|
||||
|
||||
QDomElement labelFormatElem = doc.createElement( QStringLiteral( "labelformat" ) );
|
||||
mLabelFormat.saveToDomElement( labelFormatElem );
|
||||
rendererElem.appendChild( labelFormatElem );
|
||||
|
||||
if ( mPaintEffect && !QgsPaintEffectRegistry::isDefaultStack( mPaintEffect ) )
|
||||
mPaintEffect->saveProperties( doc, rendererElem );
|
||||
|
||||
@ -1094,6 +696,27 @@ QgsLegendSymbolList QgsGraduatedSymbolRenderer::baseLegendSymbolItems() const
|
||||
return lst;
|
||||
}
|
||||
|
||||
Q_NOWARN_DEPRECATED_PUSH
|
||||
QString QgsGraduatedSymbolRenderer::methodIdFromMode( QgsGraduatedSymbolRenderer::Mode mode )
|
||||
{
|
||||
switch ( mode )
|
||||
{
|
||||
case EqualInterval:
|
||||
return QLatin1String( "EqualInterval" );
|
||||
case Quantile:
|
||||
return QLatin1String( "Quantile" );
|
||||
case Jenks:
|
||||
return QLatin1String( "Jenks" );
|
||||
case StdDev:
|
||||
return QLatin1String( "StdDev" );
|
||||
case Pretty:
|
||||
return QLatin1String( "Pretty" );
|
||||
case Custom:
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
Q_NOWARN_DEPRECATED_POP
|
||||
|
||||
QgsLegendSymbolList QgsGraduatedSymbolRenderer::legendSymbolItems() const
|
||||
{
|
||||
if ( mDataDefinedSizeLegend && mSourceSymbol && mSourceSymbol->type() == QgsSymbol::Marker )
|
||||
@ -1318,7 +941,7 @@ void QgsGraduatedSymbolRenderer::addClass( QgsSymbol *symbol )
|
||||
void QgsGraduatedSymbolRenderer::addClass( double lower, double upper )
|
||||
{
|
||||
QgsSymbol *newSymbol = mSourceSymbol->clone();
|
||||
QString label = mLabelFormat.labelForRange( lower, upper );
|
||||
QString label = mClassificationMethod->labelForRange( lower, upper );
|
||||
mRanges.append( QgsRendererRange( lower, upper, newSymbol, label ) );
|
||||
}
|
||||
|
||||
@ -1333,13 +956,14 @@ void QgsGraduatedSymbolRenderer::addBreak( double breakValue, bool updateSymbols
|
||||
QgsRendererRange newRange = QgsRendererRange();
|
||||
newRange.setLowerValue( breakValue );
|
||||
newRange.setUpperValue( range.upperValue() );
|
||||
newRange.setLabel( mLabelFormat.labelForRange( newRange ) );
|
||||
newRange.setLabel( mClassificationMethod->labelForRange( newRange ) );
|
||||
newRange.setSymbol( mSourceSymbol->clone() );
|
||||
|
||||
//update old range
|
||||
bool isDefaultLabel = range.label() == mLabelFormat.labelForRange( range );
|
||||
bool isDefaultLabel = range.label() == mClassificationMethod->labelForRange( range );
|
||||
range.setUpperValue( breakValue );
|
||||
if ( isDefaultLabel ) range.setLabel( mLabelFormat.labelForRange( range.lowerValue(), breakValue ) );
|
||||
if ( isDefaultLabel )
|
||||
range.setLabel( mClassificationMethod->labelForRange( range.lowerValue(), breakValue ) );
|
||||
it.setValue( range );
|
||||
|
||||
it.insert( newRange );
|
||||
@ -1378,14 +1002,28 @@ void QgsGraduatedSymbolRenderer::deleteAllClasses()
|
||||
|
||||
void QgsGraduatedSymbolRenderer::setLabelFormat( const QgsRendererRangeLabelFormat &labelFormat, bool updateRanges )
|
||||
{
|
||||
if ( updateRanges && labelFormat != mLabelFormat )
|
||||
{
|
||||
for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
|
||||
{
|
||||
it->setLabel( labelFormat.labelForRange( *it ) );
|
||||
}
|
||||
}
|
||||
mLabelFormat = labelFormat;
|
||||
mClassificationMethod->setLabelFormat( labelFormat.format() );
|
||||
mClassificationMethod->setLabelPrecision( labelFormat.precision() );
|
||||
mClassificationMethod->setLabelTrimTrailingZeroes( labelFormat.trimTrailingZeroes() );
|
||||
|
||||
if ( updateRanges )
|
||||
{
|
||||
updateRangeLabels();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsGraduatedSymbolRenderer::updateRangeLabels()
|
||||
{
|
||||
for ( int i = 0; i < mRanges.count(); i++ )
|
||||
{
|
||||
QgsClassificationMethod::ClassPosition pos = QgsClassificationMethod::Inner;
|
||||
if ( i == 0 )
|
||||
pos = QgsClassificationMethod::LowerBound;
|
||||
else if ( i == mRanges.count() - 1 )
|
||||
pos = QgsClassificationMethod::UpperBound;
|
||||
mRanges[i].setLabel( mClassificationMethod->labelForRange( mRanges[i], pos ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1416,7 +1054,8 @@ void QgsGraduatedSymbolRenderer::calculateLabelPrecision( bool updateRanges )
|
||||
nextDpMinRange *= 10.0;
|
||||
}
|
||||
mLabelFormat.setPrecision( ndp );
|
||||
if ( updateRanges ) setLabelFormat( mLabelFormat, true );
|
||||
if ( updateRanges )
|
||||
setLabelFormat( mLabelFormat, true );
|
||||
}
|
||||
|
||||
void QgsGraduatedSymbolRenderer::moveClass( int from, int to )
|
||||
@ -1520,6 +1159,16 @@ void QgsGraduatedSymbolRenderer::sortByLabel( Qt::SortOrder order )
|
||||
}
|
||||
}
|
||||
|
||||
QgsClassificationMethod *QgsGraduatedSymbolRenderer::classificationMethod() const
|
||||
{
|
||||
return mClassificationMethod.get();
|
||||
}
|
||||
|
||||
void QgsGraduatedSymbolRenderer::setClassificationMethod( QgsClassificationMethod *method )
|
||||
{
|
||||
mClassificationMethod.reset( method );
|
||||
}
|
||||
|
||||
QgsGraduatedSymbolRenderer *QgsGraduatedSymbolRenderer::convertFromRenderer( const QgsFeatureRenderer *renderer )
|
||||
{
|
||||
QgsGraduatedSymbolRenderer *r = nullptr;
|
||||
@ -1581,3 +1230,5 @@ const char *QgsGraduatedSymbolRenderer::graduatedMethodStr( GraduatedMethod meth
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
|
@ -15,16 +15,19 @@
|
||||
#ifndef QGSGRADUATEDSYMBOLRENDERER_H
|
||||
#define QGSGRADUATEDSYMBOLRENDERER_H
|
||||
|
||||
#include <QRegExp>
|
||||
|
||||
|
||||
#include "qgis_core.h"
|
||||
#include "qgis_sip.h"
|
||||
#include "qgis.h"
|
||||
#include "qgssymbol.h"
|
||||
#include "qgsrenderer.h"
|
||||
#include "qgsrendererrange.h"
|
||||
#include "qgsexpression.h"
|
||||
#include "qgsdatadefinedsizelegend.h"
|
||||
#include "qgsrendererrange.h"
|
||||
#include "qgsclassificationmethod.h"
|
||||
|
||||
#include <QRegExp>
|
||||
|
||||
class QgsVectorLayer;
|
||||
class QgsColorRamp;
|
||||
@ -105,7 +108,21 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer : public QgsFeatureRenderer
|
||||
void sortByValue( Qt::SortOrder order = Qt::AscendingOrder );
|
||||
void sortByLabel( Qt::SortOrder order = Qt::AscendingOrder );
|
||||
|
||||
enum Mode
|
||||
/**
|
||||
* Returns the classification method
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
QgsClassificationMethod *classificationMethod() const;
|
||||
|
||||
/**
|
||||
* Defines the classification method
|
||||
* This will take ownership of the method
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
void setClassificationMethod( QgsClassificationMethod *method SIP_TRANSFER );
|
||||
|
||||
//! \deprecated since QGIS 3.10 use QgsClassificationMethod::MethodId instead
|
||||
enum Q_DECL_DEPRECATED Mode
|
||||
{
|
||||
EqualInterval,
|
||||
Quantile,
|
||||
@ -115,58 +132,68 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer : public QgsFeatureRenderer
|
||||
Custom
|
||||
};
|
||||
|
||||
Mode mode() const { return mMode; }
|
||||
void setMode( Mode mode ) { mMode = mode; }
|
||||
//! \deprecated since QGIS 3.10 use classficationMethod instead
|
||||
Q_DECL_DEPRECATED Mode mode() const SIP_DEPRECATED { return mMode; }
|
||||
//! \deprecated since QGIS 3.10 use classficationMethod instead
|
||||
Q_DECL_DEPRECATED void setMode( Mode mode ) SIP_DEPRECATED { mMode = mode; }
|
||||
|
||||
/**
|
||||
* Returns if we want to classify symmetric around a given value
|
||||
* \since QGIS 3.4
|
||||
* \deprecated since QGIS 3.10 use classficationMethod instead
|
||||
*/
|
||||
bool useSymmetricMode() const { return mUseSymmetricMode; }
|
||||
Q_DECL_DEPRECATED bool useSymmetricMode() const SIP_DEPRECATED { return mUseSymmetricMode; }
|
||||
|
||||
/**
|
||||
* Set if we want to classify symmetric around a given value
|
||||
* \since QGIS 3.4
|
||||
* \deprecated since QGIS 3.10 use classficationMethod instead
|
||||
*/
|
||||
void setUseSymmetricMode( bool useSymmetricMode ) { mUseSymmetricMode = useSymmetricMode; }
|
||||
Q_DECL_DEPRECATED void setUseSymmetricMode( bool useSymmetricMode ) SIP_DEPRECATED { mUseSymmetricMode = useSymmetricMode; }
|
||||
|
||||
/**
|
||||
* Returns the pivot value for symmetric classification
|
||||
* \since QGIS 3.4
|
||||
* \deprecated since QGIS 3.10 use classficationMethod instead
|
||||
*/
|
||||
double symmetryPoint() const { return mSymmetryPoint; }
|
||||
Q_DECL_DEPRECATED double symmetryPoint() const SIP_DEPRECATED { return mSymmetryPoint; }
|
||||
|
||||
/**
|
||||
* Set the pivot point
|
||||
* \since QGIS 3.4
|
||||
* \deprecated since QGIS 3.10 use classficationMethod instead
|
||||
*/
|
||||
void setSymmetryPoint( double symmetryPoint ) { mSymmetryPoint = symmetryPoint; }
|
||||
Q_DECL_DEPRECATED void setSymmetryPoint( double symmetryPoint ) SIP_DEPRECATED { mSymmetryPoint = symmetryPoint; }
|
||||
|
||||
/**
|
||||
* Returns the list of breaks used in the prettybreaks mode. Needed to recover this list in saved configuration, or when property window in closed and reopened
|
||||
* \note Not available in Python bindings, not stable API
|
||||
* \since QGIS 3.4
|
||||
* \deprecated since QGIS 3.10 use classficationMethod instead
|
||||
*/
|
||||
QStringList listForCboPrettyBreaks() const { return mListForCboPrettyBreaks; } SIP_SKIP
|
||||
Q_DECL_DEPRECATED QStringList listForCboPrettyBreaks() const SIP_DEPRECATED { return mListForCboPrettyBreaks; } SIP_SKIP
|
||||
|
||||
/**
|
||||
* Set the list of breaks used in the prettybreaks mode, which is needed to recover this list in saved configuration, or when property window is closed and reopened
|
||||
* \note Not available in Python bindings, not stable API
|
||||
* \since QGIS 3.4
|
||||
* \deprecated since QGIS 3.10 use classficationMethod instead
|
||||
*/
|
||||
void setListForCboPrettyBreaks( const QStringList &listForCboPrettyBreaks ) { mListForCboPrettyBreaks = listForCboPrettyBreaks; } SIP_SKIP
|
||||
Q_DECL_DEPRECATED void setListForCboPrettyBreaks( const QStringList &listForCboPrettyBreaks ) SIP_DEPRECATED { mListForCboPrettyBreaks = listForCboPrettyBreaks; } SIP_SKIP
|
||||
|
||||
/**
|
||||
* Returns if we want to have a central class astride the pivot value
|
||||
* \since QGIS 3.4
|
||||
* \deprecated since QGIS 3.10 use classficationMethod instead
|
||||
*/
|
||||
bool astride() const { return mAstride; }
|
||||
Q_DECL_DEPRECATED bool astride() const SIP_DEPRECATED { return mAstride; }
|
||||
|
||||
/**
|
||||
* Set if we want a central class astride the pivot value
|
||||
* \since QGIS 3.4
|
||||
* \deprecated since QGIS 3.10 use classficationMethod instead
|
||||
*/
|
||||
void setAstride( bool astride ) { mAstride = astride; }
|
||||
Q_DECL_DEPRECATED void setAstride( bool astride ) SIP_DEPRECATED { mAstride = astride; }
|
||||
|
||||
/**
|
||||
* Remove the breaks that are above the existing opposite sign classes to keep colors symmetrically balanced around symmetryPoint
|
||||
@ -175,8 +202,9 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer : public QgsFeatureRenderer
|
||||
* \param symmetryPoint The point around which we want a symmetry
|
||||
* \param astride A bool indicating if the symmetry is made astride the symmetryPoint or not ( [-1,1] vs. [-1,0][0,1] )
|
||||
* \since QGIS 3.4
|
||||
* \deprecated since QGIS 3.10, use QgsClassificationMethod::makeBreaksSymmetric instead
|
||||
*/
|
||||
static void makeBreaksSymmetric( QList<double> &breaks SIP_INOUT, double symmetryPoint, bool astride );
|
||||
Q_DECL_DEPRECATED static void makeBreaksSymmetric( QList<double> &breaks SIP_INOUT, double symmetryPoint, bool astride ) SIP_DEPRECATED;
|
||||
|
||||
/**
|
||||
* Compute the equal interval classification
|
||||
@ -186,8 +214,9 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer : public QgsFeatureRenderer
|
||||
* \param useSymmetricMode A bool indicating if we want to have classes and hence colors ramp symmetric around a value
|
||||
* \param symmetryPoint The point around which we want a symmetry
|
||||
* \param astride A bool indicating if the symmetry is made astride the symmetryPoint or not ( [-1,1] vs. [-1,0][0,1] )
|
||||
* \deprecated since QGIS 3.10 use QgsClassificationEqualInterval class instead
|
||||
*/
|
||||
static QList<double> calcEqualIntervalBreaks( double minimum, double maximum, int classes, bool useSymmetricMode, double symmetryPoint, bool astride );
|
||||
Q_DECL_DEPRECATED static QList<double> calcEqualIntervalBreaks( double minimum, double maximum, int classes, bool useSymmetricMode, double symmetryPoint, bool astride );
|
||||
|
||||
/**
|
||||
* Recalculate classes for a layer
|
||||
@ -198,22 +227,31 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer : public QgsFeatureRenderer
|
||||
* \param symmetryPoint The value around which the classes will be symmetric if useSymmetricMode is checked
|
||||
* \param astride A bool indicating if the symmetry is made astride the symmetryPoint or not ( [-1,1] vs. [-1,0][0,1] )
|
||||
* \since QGIS 2.6 (three first arguments) and 3.4 (three last arguments)
|
||||
* \deprecated since QGIS 3.10
|
||||
*/
|
||||
void updateClasses( QgsVectorLayer *vlayer, Mode mode, int nclasses, bool useSymmetricMode = false, double symmetryPoint = 0.0, bool astride = false );
|
||||
Q_DECL_DEPRECATED void updateClasses( QgsVectorLayer *vlayer, Mode mode, int nclasses, bool useSymmetricMode = false, double symmetryPoint = 0.0, bool astride = false ) SIP_DEPRECATED;
|
||||
|
||||
/**
|
||||
* Recalculate classes for a layer
|
||||
* \param vlayer The layer being rendered (from which data values are calculated)
|
||||
*/
|
||||
void updateClasses( const QgsVectorLayer *vl, int numberOfClasses );
|
||||
|
||||
/**
|
||||
* Returns the label format used to generate default classification labels
|
||||
* \since QGIS 2.6
|
||||
* \deprecated since QGIS 3.10 use classificationMethod() and QgsClassificationMethod::setLabelFormat instead
|
||||
*/
|
||||
const QgsRendererRangeLabelFormat &labelFormat() const { return mLabelFormat; }
|
||||
Q_DECL_DEPRECATED const QgsRendererRangeLabelFormat &labelFormat() const { return mLabelFormat; } SIP_DEPRECATED
|
||||
|
||||
/**
|
||||
* Set the label format used to generate default classification labels
|
||||
* \param labelFormat The string appended to classification labels
|
||||
* \param updateRanges If TRUE then ranges ending with the old unit string are updated to the new.
|
||||
* \since QGIS 2.6
|
||||
* \deprecated since QGIS 3.10 use classificationMethod() and QgsClassificationMethod::setLabelFormat instead
|
||||
*/
|
||||
void setLabelFormat( const QgsRendererRangeLabelFormat &labelFormat, bool updateRanges = false );
|
||||
Q_DECL_DEPRECATED void setLabelFormat( const QgsRendererRangeLabelFormat &labelFormat, bool updateRanges = false ) SIP_DEPRECATED;
|
||||
|
||||
/**
|
||||
* Reset the label decimal places to a numberbased on the minimum class interval
|
||||
@ -222,6 +260,8 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer : public QgsFeatureRenderer
|
||||
*/
|
||||
void calculateLabelPrecision( bool updateRanges = true );
|
||||
|
||||
Q_NOWARN_DEPRECATED_PUSH
|
||||
|
||||
/**
|
||||
* Creates a new graduated renderer.
|
||||
* \param vlayer vector layer
|
||||
@ -236,8 +276,9 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer : public QgsFeatureRenderer
|
||||
* \param listForCboPrettyBreaks The list of potential pivot values for symmetric mode with prettybreaks mode
|
||||
* \param astride A bool indicating if the symmetry is made astride the symmetryPoint or not ( [-1,1] vs. [-1,0][0,1] )
|
||||
* \returns new QgsGraduatedSymbolRenderer object
|
||||
* \deprecated since QGIS 3.10
|
||||
*/
|
||||
static QgsGraduatedSymbolRenderer *createRenderer( QgsVectorLayer *vlayer,
|
||||
Q_DECL_DEPRECATED static QgsGraduatedSymbolRenderer *createRenderer( QgsVectorLayer *vlayer,
|
||||
const QString &attrName,
|
||||
int classes,
|
||||
Mode mode,
|
||||
@ -247,7 +288,8 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer : public QgsFeatureRenderer
|
||||
bool useSymmetricMode = false,
|
||||
double symmetryPoint = 0.0,
|
||||
QStringList listForCboPrettyBreaks = QStringList(),
|
||||
bool astride = false );
|
||||
bool astride = false ) SIP_DEPRECATED;
|
||||
Q_NOWARN_DEPRECATED_POP
|
||||
|
||||
//! create renderer from XML element
|
||||
static QgsFeatureRenderer *create( QDomElement &element, const QgsReadWriteContext &context ) SIP_FACTORY;
|
||||
@ -370,6 +412,12 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer : public QgsFeatureRenderer
|
||||
*/
|
||||
QgsDataDefinedSizeLegend *dataDefinedSizeLegend() const;
|
||||
|
||||
/**
|
||||
* Updates the labels of the ranges
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
void updateRangeLabels();
|
||||
|
||||
protected:
|
||||
QString mAttrName;
|
||||
QgsRangeList mRanges;
|
||||
@ -400,6 +448,8 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer : public QgsFeatureRenderer
|
||||
//! \note not available in Python bindings
|
||||
static const char *graduatedMethodStr( GraduatedMethod method ) SIP_SKIP;
|
||||
|
||||
std::shared_ptr<QgsClassificationMethod> mClassificationMethod;
|
||||
|
||||
bool mUseSymmetricMode = false;
|
||||
double mSymmetryPoint = 0.0;
|
||||
QStringList mListForCboPrettyBreaks = QStringList();
|
||||
@ -415,6 +465,11 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer : public QgsFeatureRenderer
|
||||
//! Returns list of legend symbol items from individual ranges
|
||||
QgsLegendSymbolList baseLegendSymbolItems() const;
|
||||
|
||||
// TODO QGIS 4: remove
|
||||
Q_NOWARN_DEPRECATED_PUSH
|
||||
static QString methodIdFromMode( QgsGraduatedSymbolRenderer::Mode mode );
|
||||
Q_NOWARN_DEPRECATED_POP
|
||||
|
||||
#ifdef SIP_RUN
|
||||
QgsGraduatedSymbolRenderer( const QgsGraduatedSymbolRenderer & );
|
||||
QgsGraduatedSymbolRenderer &operator=( const QgsGraduatedSymbolRenderer & );
|
||||
|
@ -14,6 +14,17 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsrendererrange.h"
|
||||
#include "qgsclassificationmethod.h"
|
||||
|
||||
|
||||
QgsRendererRange::QgsRendererRange( const QgsClassificationRange &range, QgsSymbol *symbol, bool render )
|
||||
: mLowerValue( range.lowerBound() )
|
||||
, mUpperValue( range.upperBound() )
|
||||
, mSymbol( symbol )
|
||||
, mLabel( range.label() )
|
||||
, mRender( render )
|
||||
{
|
||||
}
|
||||
|
||||
QgsRendererRange::QgsRendererRange( double lowerValue, double upperValue, QgsSymbol *symbol, const QString &label, bool render )
|
||||
: mLowerValue( lowerValue )
|
||||
|
@ -26,6 +26,7 @@ class QDomDocument;
|
||||
class QDomElement;
|
||||
|
||||
class QgsSymbol;
|
||||
class QgsClassificationRange;
|
||||
|
||||
|
||||
/**
|
||||
@ -40,6 +41,7 @@ class CORE_EXPORT QgsRendererRange
|
||||
* Constructor for QgsRendererRange.
|
||||
*/
|
||||
QgsRendererRange() = default;
|
||||
QgsRendererRange( const QgsClassificationRange &range, QgsSymbol *symbol SIP_TRANSFER, bool render = true );
|
||||
QgsRendererRange( double lowerValue, double upperValue, QgsSymbol *symbol SIP_TRANSFER, const QString &label, bool render = true );
|
||||
QgsRendererRange( const QgsRendererRange &range );
|
||||
|
||||
@ -88,12 +90,14 @@ class CORE_EXPORT QgsRendererRange
|
||||
|
||||
typedef QList<QgsRendererRange> QgsRangeList;
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* \class QgsRendererRangeLabelFormat
|
||||
* \since QGIS 2.6
|
||||
* \deprecated since QGIS 3.10, use QgsClassificationMethod instead
|
||||
*/
|
||||
class CORE_EXPORT QgsRendererRangeLabelFormat
|
||||
class Q_DECL_DEPRECATED CORE_EXPORT QgsRendererRangeLabelFormat SIP_DEPRECATED
|
||||
{
|
||||
public:
|
||||
QgsRendererRangeLabelFormat();
|
||||
|
Loading…
x
Reference in New Issue
Block a user