16 #include <QRegularExpression> 29 static const QRegularExpression RE_TRAILING_ZEROES = QRegularExpression(
"[.,]?0*$" );
30 static const QRegularExpression RE_NEGATIVE_ZERO = QRegularExpression(
"^\\-0(?:[.,]0*)?$" );
35 values.reserve( classes.count() );
36 for (
int i = 0 ; i < classes.count(); i++ )
37 values << classes.at( i ).upperBound();
42 : mFlags( properties )
43 , mCodeComplexity( codeComplexity )
44 , mLabelFormat( QStringLiteral(
"%1 - %2 " ) )
58 const QString methodId = element.attribute( QStringLiteral(
"id" ) );
62 QDomElement symmetricModeElem = element.firstChildElement( QStringLiteral(
"symmetricMode" ) );
63 if ( !symmetricModeElem.isNull() )
65 bool symmetricEnabled = symmetricModeElem.attribute( QStringLiteral(
"enabled" ) ).toInt() == 1;
66 double symmetricPoint = symmetricModeElem.attribute( QStringLiteral(
"symmetrypoint" ) ).toDouble();
67 bool astride = symmetricModeElem.attribute( QStringLiteral(
"astride" ) ).toInt() == 1;
72 QDomElement labelFormatElem = element.firstChildElement( QStringLiteral(
"labelformat" ) );
73 if ( !labelFormatElem.isNull() )
75 QString format = labelFormatElem.attribute( QStringLiteral(
"format" ),
"%1" + QStringLiteral(
" - " ) +
"%2" );
76 int precision = labelFormatElem.attribute( QStringLiteral(
"labelprecision" ), QStringLiteral(
"4" ) ).toInt();
77 bool trimTrailingZeroes = labelFormatElem.attribute( QStringLiteral(
"trimtrailingzeroes" ), QStringLiteral(
"false" ) ) == QLatin1String(
"true" );
84 QDomElement extraElem = element.firstChildElement( QStringLiteral(
"extraInformation" ) );
85 if ( !extraElem.isNull() )
86 method->
readXml( extraElem, context );
93 QDomElement methodElem = doc.createElement( QStringLiteral(
"classificationMethod" ) );
95 methodElem.setAttribute( QStringLiteral(
"id" ),
id() );
98 QDomElement symmetricModeElem = doc.createElement( QStringLiteral(
"symmetricMode" ) );
100 symmetricModeElem.setAttribute( QStringLiteral(
"symmetrypoint" ),
symmetryPoint() );
101 symmetricModeElem.setAttribute( QStringLiteral(
"astride" ), mSymmetryAstride ? 1 : 0 );
102 methodElem.appendChild( symmetricModeElem );
105 QDomElement labelFormatElem = doc.createElement( QStringLiteral(
"labelFormat" ) );
106 labelFormatElem.setAttribute( QStringLiteral(
"format" ),
labelFormat() );
107 labelFormatElem.setAttribute( QStringLiteral(
"labelprecision" ),
labelPrecision() );
109 methodElem.appendChild( labelFormatElem );
112 QDomElement extraElem = doc.createElement( QStringLiteral(
"extraInformation" ) );
114 methodElem.appendChild( extraElem );
122 mSymmetricEnabled = enabled;
124 mSymmetryAstride = astride;
132 mLabelNumberScale = 1.0;
133 mLabelNumberSuffix.clear();
134 while ( precision < 0 )
137 mLabelNumberScale /= 10.0;
138 mLabelNumberSuffix.append(
'0' );
144 if ( mLabelPrecision > 0 )
146 QString valueStr = QLocale().toString( value,
'f', mLabelPrecision );
147 if ( mLabelTrimTrailingZeroes )
148 valueStr = valueStr.remove( RE_TRAILING_ZEROES );
149 if ( RE_NEGATIVE_ZERO.match( valueStr ).hasMatch() )
150 valueStr = valueStr.mid( 1 );
155 QString valueStr = QLocale().toString( value * mLabelNumberScale,
'f', 0 );
156 if ( valueStr == QLatin1String(
"-0" ) )
158 if ( valueStr != QLatin1String(
"0" ) )
159 valueStr = valueStr + mLabelNumberSuffix;
166 if ( expression.isEmpty() )
167 return QList<QgsClassificationRange>();
172 QList<double> values;
182 if ( !ok || values.isEmpty() )
183 return QList<QgsClassificationRange>();
185 auto result = std::minmax_element( values.begin(), values.end() );
186 minimum = *result.first;
187 maximum = *result.second;
196 QList<double> breaks = calculateBreaks( minimum, maximum, values, nclasses );
197 breaks.insert( 0, minimum );
199 return breaksToClasses( breaks );
204 auto result = std::minmax_element( values.begin(), values.end() );
205 double minimum = *result.first;
206 double maximum = *result.second;
209 QList<double> breaks = calculateBreaks( minimum, maximum, values, nclasses );
210 breaks.insert( 0, minimum );
212 return breaksToClasses( breaks );
219 QgsDebugMsg( QStringLiteral(
"The classification method %1 tries to calculate classes without values while they are required." ).arg(
name() ) );
223 QList<double> breaks = calculateBreaks( minimum, maximum, QList<double>(), nclasses );
224 breaks.insert( 0, minimum );
226 return breaksToClasses( breaks );
229 QList<QgsClassificationRange> QgsClassificationMethod::breaksToClasses(
const QList<double> &breaks )
const 231 QList<QgsClassificationRange>
classes;
233 for (
int i = 1; i < breaks.count(); i++ )
236 const double lowerValue = breaks.at( i - 1 );
237 const double upperValue = breaks.at( i );
242 else if ( i == breaks.count() - 1 )
245 QString label =
labelForRange( lowerValue, upperValue, pos );
259 if ( breaks.count() < 2 )
262 std::sort( breaks.begin(), breaks.end() );
264 double distBelowSymmetricValue = std::fabs( breaks[0] - symmetryPoint );
265 double distAboveSymmetricValue = std::fabs( breaks[ breaks.size() - 2 ] -
symmetryPoint ) ;
266 double absMin = std::min( distAboveSymmetricValue, distBelowSymmetricValue );
269 for (
int i = 0; i <= breaks.size() - 2; ++i )
272 if ( std::fabs( breaks.at( i ) -
symmetryPoint ) >= ( absMin - std::fabs( breaks[0] - breaks[1] ) / 100. ) )
274 breaks.removeAt( i );
281 breaks.removeAt( breaks.indexOf( symmetryPoint ) );
294 const QString lowerLabel = valueToLabel( lowerValue );
295 const QString upperLabel = valueToLabel( upperValue );
297 return labelFormat().arg( lowerLabel ).arg( upperLabel );
QgsClassificationMethod * method(const QString &id)
Returns a new instance of the method for the given id.
The class is used as a container of context for various read/write operations on other objects...
virtual QString labelForRange(double lowerValue, double upperValue, ClassPosition position=Inner) const
Returns the label for a range.
QList< QgsClassificationRange > classes(const QgsVectorLayer *layer, const QString &expression, int nclasses)
This will calculate the classes for a given layer to define the classes.
QString formatNumber(double value) const
Format the number according to label properties.
static QList< double > getDoubleValues(const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly=false, int *nullCount=nullptr, QgsFeedback *feedback=nullptr)
Fetches all double values from a specified field name or expression.
int codeComplexity() const
Code complexity as the exponent in Big O notation.
QgsClassificationRange contains the information about a classification range.
virtual void writeXml(QDomElement &element, const QgsReadWriteContext &context) const
Writes extra information about the method.
The class is not at a bound.
bool valuesRequired() const
Returns if the method requires values to calculate the classes If not, bounds are sufficient...
static const int MAX_PRECISION
QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) const
Saves the method to a DOM element and return it.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
double lowerValue() const
The class is at the upper bound.
void setSymmetricMode(bool enabled, double symmetryPoint=0, bool symmetryAstride=false)
Defines if the symmetric mode is enables and configures its parameters.
The class is at the lower bound.
int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
double symmetryPoint() const
Returns the symmetry point for symmetric mode.
int labelPrecision() const
Returns the precision for the formatting of the labels.
void setLabelFormat(const QString &format)
Defines the format of the labels for the classes, using %1 and %2 for the bounds. ...
bool labelTrimTrailingZeroes() const
Returns if the trailing 0 are trimmed in the label.
QVariant minimumValue(int index) const FINAL
Returns the minimum value for an attribute column or an invalid variant in case of error...
void setLabelPrecision(int labelPrecision)
Defines the precision for the formatting of the labels.
void copyBase(QgsClassificationMethod *c) const
Copy the parameters (shall be used in clone implementation)
static const int MIN_PRECISION
bool symmetricModeEnabled() const
Returns if the symmetric mode is enabled.
virtual void readXml(const QDomElement &element, const QgsReadWriteContext &context)
Reads extra information to apply it to the method.
QString labelFormat() const
Returns the format of the label for the classes.
QgsClassificationMethod(MethodProperties properties=NoFlag, int codeComplexity=1)
Creates a classification method.
static QgsClassificationMethodRegistry * classificationMethodRegistry()
Returns the application's classification methods registry, used in graduated renderer.
static QList< double > rangesToBreaks(const QList< QgsClassificationRange > &classes)
Transforms a list of classes to a list of breaks.
double upperValue() const
ClassPosition
Defines the class position.
static void makeBreaksSymmetric(QList< double > &breaks, double symmetryPoint, bool astride)
Remove the breaks that are above the existing opposite sign classes to keep colors symmetrically bala...
void setLabelTrimTrailingZeroes(bool trimTrailingZeroes)
Defines if the trailing 0 are trimmed in the label.
QVariant maximumValue(int index) const FINAL
Returns the maximum value for an attribute column or an invalid variant in case of error...
Represents a vector layer which manages a vector based data sets.
QgsClassificationMethod is an abstract class for implementations of classification methods...
virtual QString name() const =0
The readable and translate name of the method.
static QgsClassificationMethod * create(const QDomElement &element, const QgsReadWriteContext &context)
Reads the DOM element and return a new classification method from it.