Skip to content

Commit

Permalink
Classification methods: save/read parameters, improve negative value …
Browse files Browse the repository at this point in the history
…handling in log method
  • Loading branch information
3nids committed Dec 6, 2019
1 parent d147a8d commit 86c3202
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 33 deletions.
7 changes: 7 additions & 0 deletions python/core/auto_additions/qgsclassificationlogarithmic.py
@@ -0,0 +1,7 @@
# The following has been generated automatically from src/core/classification/qgsclassificationlogarithmic.h
# monkey patching scoped based enum
QgsClassificationLogarithmic.NegativeValueHandling.NoHandling.__doc__ = "No handling"
QgsClassificationLogarithmic.NegativeValueHandling.Discard.__doc__ = "Negative values are discarded - this will require all values"
QgsClassificationLogarithmic.NegativeValueHandling.PrependBreak.__doc__ = "Prepend an extra break to include negative values - this will require all values"
QgsClassificationLogarithmic.NegativeValueHandling.__doc__ = '\n\n' + '* ``NoHandling``: ' + QgsClassificationLogarithmic.NegativeValueHandling.NoHandling.__doc__ + '\n' + '* ``Discard``: ' + QgsClassificationLogarithmic.NegativeValueHandling.Discard.__doc__ + '\n' + '* ``PrependBreak``: ' + QgsClassificationLogarithmic.NegativeValueHandling.PrependBreak.__doc__
# --
Expand Up @@ -21,6 +21,14 @@ Implementation of a logarithmic scale method
#include "qgsclassificationlogarithmic.h"
%End
public:

enum class NegativeValueHandling
{
NoHandling,
Discard,
PrependBreak
};

QgsClassificationLogarithmic();
virtual QgsClassificationMethod *clone() const;

Expand Down
Expand Up @@ -311,7 +311,13 @@ Defines the values of the additional parameters
.. versionadded:: 3.12
%End

QVariantMap parameterValues() const;
%Docstring
Returns the values of the processing parameters.
One could use QgsProcessingParameters.parameterAsXxxx to retrieve the actual value of a parameter.

.. versionadded:: 3.12
%End

static const int MAX_PRECISION;
static const int MIN_PRECISION;
Expand Down Expand Up @@ -339,12 +345,6 @@ The paramaeter is a processing parameter which will allow its configuration in t
Python parameters are not supported.

.. versionadded:: 3.12
%End

QVariantMap parameterValues() const;
%Docstring
Returns the values of the processing parameters.
One could use QgsProcessingParameters.parameterAsXxxx to retrieve the actual value of a parameter.
%End

};
Expand Down
61 changes: 43 additions & 18 deletions src/core/classification/qgsclassificationlogarithmic.cpp
Expand Up @@ -24,7 +24,7 @@
QgsClassificationLogarithmic::QgsClassificationLogarithmic()
: QgsClassificationMethod( NoFlag, 0 )
{
QgsProcessingParameterBoolean *param = new QgsProcessingParameterBoolean( QStringLiteral( "FILTER_ZERO_NEG_VALUES" ), QObject::tr( "Filter values ≤ 0" ), false );
QgsProcessingParameterEnum *param = new QgsProcessingParameterEnum( QStringLiteral( "ZERO_NEG_VALUES_HANDLE" ), QObject::tr( "Handling of negative values" ), QStringList() << QObject::tr( "no handling (faster)" ) << QObject::tr( "discard (slower)" ) << QObject::tr( "prepend range (slower)" ), false, 0 );
addParameter( param );
}

Expand Down Expand Up @@ -53,32 +53,52 @@ QIcon QgsClassificationLogarithmic::icon() const

QList<double> QgsClassificationLogarithmic::calculateBreaks( double &minimum, double &maximum, const QList<double> &values, int nclasses )
{
// not possible if only negative values
if ( maximum <= 0 )
return QList<double>();

QgsProcessingContext context;
bool filterZeroNeg = QgsProcessingParameters::parameterAsBool( parameterDefinition( QStringLiteral( "FILTER_ZERO_NEG_VALUES" ) ), parameterValues(), context );
const QgsProcessingParameterDefinition *def = parameterDefinition( QStringLiteral( "ZERO_NEG_VALUES_HANDLE" ) );
NegativeValueHandling nvh = static_cast< NegativeValueHandling >( QgsProcessingParameters::parameterAsEnum( def, parameterValues(), context ) );

if ( filterZeroNeg && minimum <= 0 )
double positiveMinimum = std::numeric_limits<double>::max();
if ( nvh != NegativeValueHandling::NoHandling && minimum <= 0 )
{
Q_ASSERT( values.count() );
minimum = std::numeric_limits<double>::max();
for ( int i = 0; i < values.count(); i++ )
if ( maximum > 0 )
{
for ( int i = 0; i < values.count(); i++ )
{
if ( values.at( i ) > 0 )
positiveMinimum = std::min( positiveMinimum, values.at( i ) );
}
}
if ( positiveMinimum == std::numeric_limits<double>::max() )
{
if ( values.at( i ) > 0 )
minimum = std::min( minimum, values.at( i ) );
// there is no usable values
if ( nvh == NegativeValueHandling::PrependBreak )
return QList<double>( {0} );
else
return QList<double>();
}
if ( minimum == std::numeric_limits<double>::max() )
return QList<double>();
}

QList<double> breaks;

if ( positiveMinimum != std::numeric_limits<double>::max() )
{
if ( nvh == NegativeValueHandling::PrependBreak )
breaks << std::floor( std::log10( positiveMinimum ) );
else if ( nvh == NegativeValueHandling::Discard )
minimum = positiveMinimum; // the minimum gets updated
}
else
{
positiveMinimum = minimum;
}

// get the min/max in log10 scale
double log_min = std::floor( std::log10( minimum ) );
double log_min = std::floor( std::log10( positiveMinimum ) );
double log_max = std::ceil( std::log10( maximum ) );

// calculate pretty breaks
QList<double> breaks = QgsSymbolLayerUtils::prettyBreaks( log_min, log_max, nclasses );
breaks.append( QgsSymbolLayerUtils::prettyBreaks( log_min, log_max, nclasses ) );

// create the value
for ( int i = 0; i < breaks.count(); i++ )
Expand All @@ -89,8 +109,10 @@ QList<double> QgsClassificationLogarithmic::calculateBreaks( double &minimum, do

QString QgsClassificationLogarithmic::valueToLabel( double value ) const
{
QString label = QString( QStringLiteral( "10^%1" ) ).arg( std::log10( value ) );
return label;
if ( value <= 0 )
return QString( QStringLiteral( "%1" ) ).arg( value );
else
return QString( QStringLiteral( "10^%1" ) ).arg( std::log10( value ) );
}

QString QgsClassificationLogarithmic::labelForRange( double lowerValue, double upperValue, QgsClassificationMethod::ClassPosition position ) const
Expand All @@ -115,5 +137,8 @@ QString QgsClassificationLogarithmic::labelForRange( double lowerValue, double u
bool QgsClassificationLogarithmic::valuesRequired() const
{
QgsProcessingContext context;
return QgsProcessingParameters::parameterAsBool( parameterDefinition( QStringLiteral( "FILTER_ZERO_NEG_VALUES" ) ), parameterValues(), context );
const QgsProcessingParameterDefinition *def = parameterDefinition( QStringLiteral( "ZERO_NEG_VALUES_HANDLE" ) );
NegativeValueHandling nvh = static_cast< NegativeValueHandling >( QgsProcessingParameters::parameterAsEnum( def, parameterValues(), context ) );

return nvh != NegativeValueHandling::NoHandling;
}
8 changes: 8 additions & 0 deletions src/core/classification/qgsclassificationlogarithmic.h
Expand Up @@ -28,6 +28,14 @@
class CORE_EXPORT QgsClassificationLogarithmic : public QgsClassificationMethod
{
public:

enum class NegativeValueHandling : int
{
NoHandling = 0, //!< No handling
Discard, //!< Negative values are discarded - this will require all values
PrependBreak //!< Prepend an extra break to include negative values - this will require all values
};

QgsClassificationLogarithmic();
QgsClassificationMethod *clone() const override;
QString name() const override;
Expand Down
15 changes: 14 additions & 1 deletion src/core/classification/qgsclassificationmethod.cpp
Expand Up @@ -22,6 +22,7 @@
#include "qgsgraduatedsymbolrenderer.h"
#include "qgsapplication.h"
#include "qgsclassificationmethodregistry.h"
#include "qgsxmlutils.h"

const int QgsClassificationMethod::MAX_PRECISION = 15;
const int QgsClassificationMethod::MIN_PRECISION = -6;
Expand Down Expand Up @@ -49,6 +50,7 @@ void QgsClassificationMethod::copyBase( QgsClassificationMethod *c ) const
c->setLabelFormat( mLabelFormat );
c->setLabelPrecision( mLabelPrecision );
c->setLabelTrimTrailingZeroes( mLabelTrimTrailingZeroes );
c->setParameterValues( mParameterValues );
}

QgsClassificationMethod *QgsClassificationMethod::create( const QDomElement &element, const QgsReadWriteContext &context )
Expand Down Expand Up @@ -78,6 +80,11 @@ QgsClassificationMethod *QgsClassificationMethod::create( const QDomElement &ele
method->setLabelTrimTrailingZeroes( trimTrailingZeroes );
}

// parameters (processing parameters)
QDomElement parametersElem = element.firstChildElement( QStringLiteral( "parameters" ) );
const QVariantMap parameterValues = QgsXmlUtils::readVariant( parametersElem.firstChildElement() ).toMap();
method->setParameterValues( parameterValues );

// Read specific properties from the implementation
QDomElement extraElem = element.firstChildElement( QStringLiteral( "extraInformation" ) );
if ( !extraElem.isNull() )
Expand Down Expand Up @@ -106,6 +113,11 @@ QDomElement QgsClassificationMethod::save( QDomDocument &doc, const QgsReadWrite
labelFormatElem.setAttribute( QStringLiteral( "trimtrailingzeroes" ), labelTrimTrailingZeroes() ? 1 : 0 );
methodElem.appendChild( labelFormatElem );

// parameters (processing parameters)
QDomElement parametersElem = doc.createElement( QStringLiteral( "parameters" ) );
parametersElem.appendChild( QgsXmlUtils::writeVariant( mParameterValues, doc ) );
methodElem.appendChild( parametersElem );

// extra information
QDomElement extraElem = doc.createElement( QStringLiteral( "extraInformation" ) );
writeXml( extraElem, context );
Expand Down Expand Up @@ -173,13 +185,14 @@ const QgsProcessingParameterDefinition *QgsClassificationMethod::parameterDefini
if ( def->name() == parameterName )
return def;
}
QgsMessageLog::logMessage( QStringLiteral( "No parameter defintion found for %1 in %2 method." ).arg( parameterName ).arg( name() ) );
return nullptr;
}

void QgsClassificationMethod::setParameterValues( const QVariantMap &values )
{
mParameterValues = values;
for ( auto it = mParameterValues.begin(); it != mParameterValues.end(); ++it )
for ( auto it = mParameterValues.constBegin(); it != mParameterValues.constEnd(); ++it )
{
if ( !parameterDefinition( it.key() ) )
{
Expand Down
13 changes: 6 additions & 7 deletions src/core/classification/qgsclassificationmethod.h
Expand Up @@ -289,7 +289,12 @@ class CORE_EXPORT QgsClassificationMethod SIP_ABSTRACT
*/
void setParameterValues( const QVariantMap &values );


/**
* Returns the values of the processing parameters.
* One could use QgsProcessingParameters::parameterAsXxxx to retrieve the actual value of a parameter.
* \since QGIS 3.12
*/
QVariantMap parameterValues() const {return mParameterValues;}

static const int MAX_PRECISION;
static const int MIN_PRECISION;
Expand All @@ -311,12 +316,6 @@ class CORE_EXPORT QgsClassificationMethod SIP_ABSTRACT
*/
void addParameter( QgsProcessingParameterDefinition *definition SIP_TRANSFER );

/**
* Returns the values of the processing parameters.
* One could use QgsProcessingParameters::parameterAsXxxx to retrieve the actual value of a parameter.
*/
QVariantMap parameterValues() const {return mParameterValues;}

private:

/**
Expand Down
13 changes: 12 additions & 1 deletion src/gui/symbology/qgsgraduatedsymbolrendererwidget.cpp
Expand Up @@ -705,6 +705,14 @@ void QgsGraduatedSymbolRendererWidget::updateUiFromRenderer( bool updateCount )
txtLegendFormat->setText( method->labelFormat() );
spinPrecision->setValue( method->labelPrecision() );
cbxTrimTrailingZeroes->setChecked( method->labelTrimTrailingZeroes() );

QgsProcessingContext context;
for ( const auto &ppww : qgis::as_const( mParameterWidgetWrappers ) )
{
const QgsProcessingParameterDefinition *def = ppww->parameterDefinition();
QVariant value = method->parameterValues().value( def->name(), def->defaultValue() );
ppww->setParameterValue( value, context );
}
}

// Only update class count if different - otherwise typing value gets very messy
Expand Down Expand Up @@ -827,14 +835,17 @@ void QgsGraduatedSymbolRendererWidget::updateMethodParameters()
QgsClassificationMethod *method = QgsApplication::classificationMethodRegistry()->method( methodId );
Q_ASSERT( method );

// todo need more?
// need more context?
QgsProcessingContext context;

for ( const QgsProcessingParameterDefinition *def : method->parameterDefinitions() )
{
QgsAbstractProcessingParameterWidgetWrapper *ppww = QgsGui::processingGuiRegistry()->createParameterWidgetWrapper( def, QgsProcessingGui::Standard );
mParametersLayout->addRow( ppww->createWrappedLabel(), ppww->createWrappedWidget( context ) );

QVariant value = method->parameterValues().value( def->name(), def->defaultValue() );
ppww->setParameterValue( value, context );

connect( ppww, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, &QgsGraduatedSymbolRendererWidget::classifyGraduated );

mParameterWidgetWrappers.push_back( std::unique_ptr<QgsAbstractProcessingParameterWidgetWrapper>( ppww ) );
Expand Down

0 comments on commit 86c3202

Please sign in to comment.