classify symmetric squashed (17 commits) to rebase easily on master; 13 may 2018

This commit is contained in:
pierreloicq 2017-09-12 01:01:55 +02:00 committed by Nyall Dawson
parent 05f35f2e19
commit fe049d372c
8 changed files with 1136 additions and 59 deletions

View File

@ -225,7 +225,63 @@ Tests whether classes assigned to the renderer have gaps between the ranges.
Mode mode() const;
void setMode( Mode mode );
void updateClasses( QgsVectorLayer *vlayer, Mode mode, int nclasses );
bool useSymmetricMode();
%Docstring
get mUseSymmetricMode, which says if we want to classify symmetric around a given value
.. versionadded:: 3.2
%End
void setUseSymmetricMode( bool useSymmetricMode );
%Docstring
set mUseSymmetricMode, which says if we want to classify symmetric around a given value
.. versionadded:: 3.2
%End
double symmetryPoint();
%Docstring
get mSymmetryPoint, the pivot value for symmetric classification
.. versionadded:: 3.2
%End
void setSymmetryPoint( double symmetryPoint );
%Docstring
set the pivot point
.. versionadded:: 3.2
%End
QStringList listForCboPrettyBreaks();
%Docstring
get mListForCboPrettyBreaks, which is need to recover this list in saved configuration, or when property window in closed and reopened
.. versionadded:: 3.2
%End
void setListForCboPrettyBreaks( QStringList listForCboPrettyBreaks );
%Docstring
set mListForCboPrettyBreaks, which is need to recover this list in saved configuration, or when property window in closed and reopened
.. versionadded:: 3.2
%End
bool astride();
%Docstring
get mAstride, a bool saying if we want to have a central class astride the pivot value
.. versionadded:: 3.2
%End
void setAstride( bool astride );
%Docstring
set mAstride, a bool saying if we want to have a central class astride the pivot value
.. versionadded:: 3.2
%End
void updateClasses( QgsVectorLayer *vlayer, Mode mode, int nclasses, bool useSymmetricMode = false, double symmetryPoint = 0.0, bool astride = false );
%Docstring
Recalculate classes for a layer
@ -234,6 +290,11 @@ Recalculate classes for a layer
:param nclasses: The number of classes to calculate (approximate for some modes)
.. versionadded:: 2.6
:param useSymmetricMode: A bool indicating if we want to have classes and hence colors ramp symmetric around a value
: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] )
.. versionadded:: 3.2
%End
const QgsRendererRangeLabelFormat &labelFormat() const;
@ -266,6 +327,10 @@ Reset the label decimal places to a numberbased on the minimum class interval
const QString &attrName,
int classes,
Mode mode,
bool useSymmetricMode,
double symmetryPoint,
QStringList listForCboPrettyBreaks,
bool astride,
QgsSymbol *symbol /Transfer/,
QgsColorRamp *ramp /Transfer/,
const QgsRendererRangeLabelFormat &legendFormat = QgsRendererRangeLabelFormat() );
@ -276,6 +341,10 @@ Creates a new graduated renderer.
:param attrName: attribute to classify
:param classes: number of classes
:param mode: classification mode
:param useSymmetricMode: A bool indicating if we want to have classes and hence colors ramp symmetric around a value
:param symmetryPoint: The value around which the classes will be symmetric if useSymmetricMode is checked
: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] )
:param symbol: base symbol
:param ramp: color ramp for classes
:param legendFormat:
@ -440,6 +509,7 @@ Will return null if the functionality is disabled.
QgsSymbol *symbolForValue( double value ) const;
%Docstring
Gets the symbol which is used to represent ``value``.

View File

@ -0,0 +1,535 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/symbology/qgsgraduatedsymbolrenderer.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsRendererRange
{
%TypeHeaderCode
#include "qgsgraduatedsymbolrenderer.h"
%End
public:
QgsRendererRange();
%Docstring
Constructor for QgsRendererRange.
%End
QgsRendererRange( double lowerValue, double upperValue, QgsSymbol *symbol /Transfer/, const QString &label, bool render = true );
QgsRendererRange( const QgsRendererRange &range );
bool operator<( const QgsRendererRange &other ) const;
double lowerValue() const;
double upperValue() const;
QgsSymbol *symbol() const;
QString label() const;
void setSymbol( QgsSymbol *s /Transfer/ );
void setLabel( const QString &label );
void setLowerValue( double lowerValue );
void setUpperValue( double upperValue );
bool renderState() const;
void setRenderState( bool render );
QString dump() const;
void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props, bool firstRange = false ) const;
%Docstring
Creates a DOM element representing the range in SLD format.
:param doc: DOM document
:param element: destination DOM element
:param props: graduated renderer properties
:param firstRange: set to true if the range is the first range, where the lower value uses a <= test
rather than a < test.
%End
protected:
void swap( QgsRendererRange &other );
};
typedef QList<QgsRendererRange> QgsRangeList;
class QgsRendererRangeLabelFormat
{
%Docstring
.. versionadded:: 2.6
%End
%TypeHeaderCode
#include "qgsgraduatedsymbolrenderer.h"
%End
public:
QgsRendererRangeLabelFormat();
QgsRendererRangeLabelFormat( const QString &format, int precision = 4, bool trimTrailingZeroes = false );
bool operator==( const QgsRendererRangeLabelFormat &other ) const;
bool operator!=( const QgsRendererRangeLabelFormat &other ) const;
QString format() const;
void setFormat( const QString &format );
int precision() const;
void setPrecision( int precision );
bool trimTrailingZeroes() const;
void setTrimTrailingZeroes( bool trimTrailingZeroes );
QString labelForRange( double lower, double upper ) const /PyName=labelForLowerUpper/;
%Docstring
.. note::
labelForLowerUpper in Python bindings
%End
QString labelForRange( const QgsRendererRange &range ) const;
QString formatNumber( double value ) const;
void setFromDomElement( QDomElement &element );
void saveToDomElement( QDomElement &element );
static const int MAX_PRECISION;
static const int MIN_PRECISION;
protected:
};
class QgsGraduatedSymbolRenderer : QgsFeatureRenderer
{
%TypeHeaderCode
#include "qgsgraduatedsymbolrenderer.h"
%End
public:
QgsGraduatedSymbolRenderer( const QString &attrName = QString(), const QgsRangeList &ranges = QgsRangeList() );
~QgsGraduatedSymbolRenderer();
virtual QgsSymbol *symbolForFeature( QgsFeature &feature, QgsRenderContext &context );
virtual QgsSymbol *originalSymbolForFeature( QgsFeature &feature, QgsRenderContext &context );
virtual void startRender( QgsRenderContext &context, const QgsFields &fields );
virtual void stopRender( QgsRenderContext &context );
virtual QSet<QString> usedAttributes( const QgsRenderContext &context ) const;
virtual QString dump() const;
virtual QgsGraduatedSymbolRenderer *clone() const /Factory/;
virtual void toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap &props = QgsStringMap() ) const;
virtual QgsFeatureRenderer::Capabilities capabilities();
virtual QgsSymbolList symbols( QgsRenderContext &context );
QString classAttribute() const;
void setClassAttribute( const QString &attr );
const QgsRangeList &ranges() const;
bool updateRangeSymbol( int rangeIndex, QgsSymbol *symbol /Transfer/ );
bool updateRangeLabel( int rangeIndex, const QString &label );
bool updateRangeUpperValue( int rangeIndex, double value );
bool updateRangeLowerValue( int rangeIndex, double value );
bool updateRangeRenderState( int rangeIndex, bool render );
%Docstring
.. versionadded:: 2.5
%End
void addClass( QgsSymbol *symbol );
void addClass( const QgsRendererRange &range ) /PyName=addClassRange/;
%Docstring
.. note::
available in Python bindings as addClassRange
%End
void addClass( double lower, double upper ) /PyName=addClassLowerUpper/;
%Docstring
.. note::
available in Python bindings as addClassLowerUpper
%End
void addBreak( double breakValue, bool updateSymbols = true );
%Docstring
Add a breakpoint by splitting existing classes so that the specified
value becomes a break between two classes.
:param breakValue: position to insert break
:param updateSymbols: set to true to reapply ramp colors to the new
symbol ranges
.. versionadded:: 2.9
%End
void deleteClass( int idx );
void deleteAllClasses();
void moveClass( int from, int to );
%Docstring
Moves the category at index position from to index position to.
%End
bool rangesOverlap() const;
%Docstring
Tests whether classes assigned to the renderer have ranges which overlap.
:return: true if ranges overlap
.. versionadded:: 2.10
%End
bool rangesHaveGaps() const;
%Docstring
Tests whether classes assigned to the renderer have gaps between the ranges.
:return: true if ranges have gaps
.. versionadded:: 2.10
%End
void sortByValue( Qt::SortOrder order = Qt::AscendingOrder );
void sortByLabel( Qt::SortOrder order = Qt::AscendingOrder );
enum Mode
{
EqualInterval,
Quantile,
Jenks,
StdDev,
Pretty,
Custom
};
Mode mode() const;
void setMode( Mode mode );
bool useSymmetricMode();
%Docstring
get mUseSymmetricMode, which says if we want to classify symmetric around a given value
.. versionadded:: 3.2
%End
void setUseSymmetricMode( bool useSymmetricMode );
%Docstring
set mUseSymmetricMode, which says if we want to classify symmetric around a given value
.. versionadded:: 3.2
%End
double symmetryPoint();
%Docstring
get mSymmetryPoint, the pivot value for symmetric classification
.. versionadded:: 3.2
%End
void setSymmetryPoint( double symmetryPoint );
%Docstring
set the pivot point
.. versionadded:: 3.2
%End
QStringList listForCboPrettyBreaks();
%Docstring
get mListForCboPrettyBreaks, which is need to recover this list in saved configuration, or when property window in closed and reopened
.. versionadded:: 3.2
%End
void setListForCboPrettyBreaks( QStringList listForCboPrettyBreaks );
%Docstring
set mListForCboPrettyBreaks, which is need to recover this list in saved configuration, or when property window in closed and reopened
.. versionadded:: 3.2
%End
bool astride();
%Docstring
get mAstride, a bool saying if we want to have a central class astride the pivot value
.. versionadded:: 3.2
%End
void setAstride( bool astride );
%Docstring
set mAstride, a bool saying if we want to have a central class astride the pivot value
.. versionadded:: 3.2
%End
void updateClasses( QgsVectorLayer *vlayer, Mode mode, int nclasses, bool useSymmetricMode = false, double symmetryPoint = 0.0, bool astride = false );
%Docstring
Recalculate classes for a layer
:param vlayer: The layer being rendered (from which data values are calculated)
:param mode: The calculation mode
:param nclasses: The number of classes to calculate (approximate for some modes)
.. versionadded:: 2.6
:param useSymmetricMode: A bool indicating if we want to have classes and hence colors ramp symmetric around a value
: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] )
.. versionadded:: 3.2
%End
const QgsRendererRangeLabelFormat &labelFormat() const;
%Docstring
Return the label format used to generate default classification labels
.. versionadded:: 2.6
%End
void setLabelFormat( const QgsRendererRangeLabelFormat &labelFormat, bool updateRanges = false );
%Docstring
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.
.. versionadded:: 2.6
%End
void calculateLabelPrecision( bool updateRanges = true );
%Docstring
Reset the label decimal places to a numberbased on the minimum class interval
:param updateRanges: if true then ranges currently using the default label will be updated
.. versionadded:: 2.6
%End
static QgsGraduatedSymbolRenderer *createRenderer( QgsVectorLayer *vlayer,
const QString &attrName,
int classes,
Mode mode,
bool useSymmetricMode,
double symmetryPoint,
QStringList listForCboPrettyBreaks,
bool astride,
QgsSymbol *symbol /Transfer/,
QgsColorRamp *ramp /Transfer/,
const QgsRendererRangeLabelFormat &legendFormat = QgsRendererRangeLabelFormat() );
%Docstring
Creates a new graduated renderer.
:param vlayer: vector layer
:param attrName: attribute to classify
:param classes: number of classes
:param mode: classification mode
:param useSymmetricMode: A bool indicating if we want to have classes and hence colors ramp symmetric around a value
:param symmetryPoint: The value around which the classes will be symmetric if useSymmetricMode is checked
: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] )
:param symbol: base symbol
:param ramp: color ramp for classes
:param legendFormat:
:return: new QgsGraduatedSymbolRenderer object
%End
static QgsFeatureRenderer *create( QDomElement &element, const QgsReadWriteContext &context ) /Factory/;
%Docstring
create renderer from XML element
%End
virtual QDomElement save( QDomDocument &doc, const QgsReadWriteContext &context );
virtual QgsLegendSymbolList legendSymbolItems() const;
virtual QSet< QString > legendKeysForFeature( QgsFeature &feature, QgsRenderContext &context );
QgsSymbol *sourceSymbol();
%Docstring
Returns the renderer's source symbol, which is the base symbol used for the each classes' symbol before applying
the classes' color.
.. seealso:: :py:func:`setSourceSymbol`
.. seealso:: :py:func:`sourceColorRamp`
%End
void setSourceSymbol( QgsSymbol *sym /Transfer/ );
%Docstring
Sets the source symbol for the renderer, which is the base symbol used for the each classes' symbol before applying
the classes' color.
:param sym: source symbol, ownership is transferred to the renderer
.. seealso:: :py:func:`sourceSymbol`
.. seealso:: :py:func:`setSourceColorRamp`
%End
QgsColorRamp *sourceColorRamp();
%Docstring
Returns the source color ramp, from which each classes' color is derived.
.. seealso:: :py:func:`setSourceColorRamp`
.. seealso:: :py:func:`sourceSymbol`
%End
void setSourceColorRamp( QgsColorRamp *ramp /Transfer/ );
%Docstring
Sets the source color ramp.
:param ramp: color ramp. Ownership is transferred to the renderer
%End
void updateColorRamp( QgsColorRamp *ramp /Transfer/ = 0 );
%Docstring
Update the color ramp used. Also updates all symbols colors.
Doesn't alter current breaks.
:param ramp: color ramp. Ownership is transferred to the renderer
%End
void updateSymbols( QgsSymbol *sym );
%Docstring
Update all the symbols but leave breaks and colors. This method also sets the source
symbol for the renderer.
:param sym: source symbol to use for classes. Ownership is not transferred.
.. seealso:: :py:func:`setSourceSymbol`
%End
void setSymbolSizes( double minSize, double maxSize );
%Docstring
set varying symbol size for classes
.. note::
the classes must already be set so that symbols exist
.. versionadded:: 2.10
%End
double minSymbolSize() const;
%Docstring
return the min symbol size when graduated by size
.. versionadded:: 2.10
%End
double maxSymbolSize() const;
%Docstring
return the max symbol size when graduated by size
.. versionadded:: 2.10
%End
enum GraduatedMethod
{
GraduatedColor,
GraduatedSize
};
GraduatedMethod graduatedMethod() const;
%Docstring
return the method used for graduation (either size or color)
.. versionadded:: 2.10
%End
void setGraduatedMethod( GraduatedMethod method );
%Docstring
set the method used for graduation (either size or color)
.. versionadded:: 2.10
%End
virtual bool legendSymbolItemsCheckable() const;
virtual bool legendSymbolItemChecked( const QString &key );
virtual void checkLegendSymbolItem( const QString &key, bool state = true );
virtual void setLegendSymbolItem( const QString &key, QgsSymbol *symbol /Transfer/ );
virtual QString legendClassificationAttribute() const;
static QgsGraduatedSymbolRenderer *convertFromRenderer( const QgsFeatureRenderer *renderer ) /Factory/;
%Docstring
creates a QgsGraduatedSymbolRenderer from an existing renderer.
:return: a new renderer if the conversion was possible, otherwise 0.
.. versionadded:: 2.6
%End
void setDataDefinedSizeLegend( QgsDataDefinedSizeLegend *settings /Transfer/ );
%Docstring
Configures appearance of legend when renderer is configured to use data-defined size for marker symbols.
This allows configuring for which values (symbol sizes) should be shown in the legend, whether to display
different symbol sizes collapsed in one legend node or separated across multiple legend nodes etc.
When renderer does not use data-defined size or does not use marker symbols, these settings will be ignored.
Takes ownership of the passed settings objects. Null pointer is a valid input that disables data-defined
size legend.
.. versionadded:: 3.0
%End
QgsDataDefinedSizeLegend *dataDefinedSizeLegend() const;
%Docstring
Returns configuration of appearance of legend when using data-defined size for marker symbols.
Will return null if the functionality is disabled.
.. versionadded:: 3.0
%End
protected:
QgsSymbol *symbolForValue( double value );
%Docstring
attribute index (derived from attribute name in startRender)
%End
QString legendKeyForValue( double value ) const;
%Docstring
Returns the matching legend key for a value.
%End
private:
QgsGraduatedSymbolRenderer( const QgsGraduatedSymbolRenderer & );
QgsGraduatedSymbolRenderer &operator=( const QgsGraduatedSymbolRenderer & );
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/symbology/qgsgraduatedsymbolrenderer.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -0,0 +1,100 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/symbology/qgsgraduatedsymbolrendererwidget.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsGraduatedSymbolRendererWidget : QgsRendererWidget
{
%TypeHeaderCode
#include "qgsgraduatedsymbolrendererwidget.h"
%End
public:
static QgsRendererWidget *create( QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer ) /Factory/;
QgsGraduatedSymbolRendererWidget( QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer );
~QgsGraduatedSymbolRendererWidget();
virtual QgsFeatureRenderer *renderer();
public slots:
void changeGraduatedSymbol();
void graduatedColumnChanged( const QString &field );
void classifyGraduated();
void reapplyColorRamp();
void reapplySizes();
void rangesDoubleClicked( const QModelIndex &idx );
void rangesClicked( const QModelIndex &idx );
void changeCurrentValue( QStandardItem *item );
void addClass();
%Docstring
Adds a class manually to the classification
%End
void deleteClasses();
%Docstring
Removes currently selected classes
%End
void deleteAllClasses();
%Docstring
Removes all classes from the classification
%End
void toggleBoundariesLink( bool linked );
%Docstring
Toggle the link between classes boundaries
%End
void labelFormatChanged();
void showSymbolLevels();
void rowsMoved();
void modelDataChanged();
void refreshRanges( bool reset = false );
protected:
void updateUiFromRenderer( bool updateCount = true );
void connectUpdateHandlers();
void disconnectUpdateHandlers();
bool rowsOrdered();
void updateGraduatedSymbolIcon();
QList<int> selectedClasses();
%Docstring
return a list of indexes for the classes under selection
%End
QgsRangeList selectedRanges();
void changeRangeSymbol( int rangeIdx );
void changeRange( int rangeIdx );
void changeSelectedSymbols();
virtual QList<QgsSymbol *> selectedSymbols();
QgsSymbol *findSymbolForRange( double lowerBound, double upperBound, const QgsRangeList &ranges ) const;
virtual void refreshSymbolView();
virtual void keyPressEvent( QKeyEvent *event );
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/symbology/qgsgraduatedsymbolrendererwidget.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -288,7 +288,8 @@ QgsGraduatedSymbolRenderer::QgsGraduatedSymbolRenderer( const QString &attrName,
{
mRanges << range;
}
mUseSymmetricMode = false;
mAstride = false;
}
QgsGraduatedSymbolRenderer::~QgsGraduatedSymbolRenderer()
@ -484,6 +485,11 @@ 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 );
if ( mSourceSymbol )
r->setSourceSymbol( mSourceSymbol->clone() );
if ( mSourceColorRamp )
@ -525,29 +531,83 @@ QgsSymbolList QgsGraduatedSymbolRenderer::symbols( QgsRenderContext &context ) c
return lst;
}
static QList<double> _calcEqualIntervalBreaks( double minimum, double maximum, int classes )
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 balanced around symmetryPoint
// if astride is true, remove the symmetryPoint break so that
// the 2 classes form only one
// Equal interval algorithm
//
// Returns breaks based on dividing the range ('minimum' to 'maximum')
// into 'classes' parts.
double step = ( maximum - minimum ) / classes;
QList<double> breaks;
double value = minimum;
breaks.reserve( classes );
for ( int i = 0; i < classes; i++ )
if ( breaks.size() > 1 ) //to avoid crash when only 1 class
{
value += step;
breaks.append( value );
std::sort( breaks.begin(), breaks.end() );
// breaks contain the maximum of the distrib but not the minimum
double distBelowSymmetricValue = std::abs( breaks[0] - symmetryPoint );
double distAboveSymmetricValue = std::abs( breaks[ breaks.size() - 2 ] - symmetryPoint ) ;
double absMin = std::min( std::abs( distAboveSymmetricValue ), std::abs( distBelowSymmetricValue ) );
// make symmetric
for ( int i = 0; i <= breaks.size() - 2; ++i )
{
if ( std::abs( breaks.at( i ) - symmetryPoint ) > absMin )
{
breaks.removeAt( i );
--i;
}
}
// remove symmetry point
if ( true == astride ) // && breaks.indexOf( symmetryPoint ) != -1) // if symmetryPoint is found
{
breaks.removeAt( breaks.indexOf( symmetryPoint ) );
}
}
}
// floating point arithmetics is not precise:
// set the last break to be exactly maximum so we do not miss it
breaks[classes - 1] = maximum;
static QList<double> _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 ( false == 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 ( true == useSymmetricMode ) // symmetric mode
{
double distBelowSymmetricValue = std::abs( minimum - symmetryPoint );
double distAboveSymmetricValue = std::abs( maximum - symmetryPoint ) ;
if ( true == astride )
{
( 0 == classes % 2 ) ? ++classes : classes; // we want odd number of classes
}
else
{
( 1 == classes % 2 ) ? ++classes : classes; // we want even number of classes
}
double step = 2 * std::min( distBelowSymmetricValue, distAboveSymmetricValue ) / classes;
double value;
breaks.reserve( classes );
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;
}
@ -593,7 +653,7 @@ static QList<double> _calcQuantileBreaks( QList<double> values, int classes )
return breaks;
}
static QList<double> _calcStdDevBreaks( QList<double> values, int classes, QList<double> &labels )
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
@ -629,13 +689,17 @@ static QList<double> _calcStdDevBreaks( QList<double> values, int classes, QList
}
stdDev = std::sqrt( stdDev / n );
QList<double> breaks = QgsSymbolLayerUtils::prettyBreaks( ( minimum - mean ) / stdDev, ( maximum - mean ) / stdDev, classes );
for ( int i = 0; i < breaks.count(); i++ )
if ( false == useSymmetricMode )
symmetryPoint = mean; // otherwise symmetryPoint = symmetryPoint
QList<double> breaks = QgsSymbolLayerUtils::prettyBreaks( ( minimum - symmetryPoint ) / stdDev, ( maximum - symmetryPoint ) / stdDev, classes );
_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 ) + mean;
breaks[i] = ( breaks[i] * stdDev ) + symmetryPoint;
}
return breaks;
} // _calcStdDevBreaks
@ -769,12 +833,25 @@ static QList<double> _calcJenksBreaks( QList<double> values, int classes,
return breaks.toList();
} //_calcJenksBreaks
static QStringList _breaksAsStrings( QList<double> breaks ) // get QStringList from QList<double> without maxi break (min is not in)
{
QStringList breaksAsTrings;
for ( int i = 0; i < breaks.count() - 1; i++ )
{
breaksAsTrings << QString::number( breaks.at( i ), 'f', 2 );
}
return breaksAsTrings;
}
QgsGraduatedSymbolRenderer *QgsGraduatedSymbolRenderer::createRenderer(
QgsVectorLayer *vlayer,
const QString &attrName,
int classes,
Mode mode,
bool useSymmetricMode,
double symmetryPoint,
QStringList listForCboPrettyBreaks,
bool astride,
QgsSymbol *symbol,
QgsColorRamp *ramp,
const QgsRendererRangeLabelFormat &labelFormat
@ -785,17 +862,25 @@ QgsGraduatedSymbolRenderer *QgsGraduatedSymbolRenderer::createRenderer(
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 );
r->updateClasses( vlayer, mode, classes, useSymmetricMode, symmetryPoint, astride );
return r;
}
void QgsGraduatedSymbolRenderer::updateClasses( QgsVectorLayer *vlayer, Mode mode, int nclasses )
void QgsGraduatedSymbolRenderer::updateClasses( QgsVectorLayer *vlayer, Mode mode, int nclasses,
bool useSymmetricMode, double symmetryPoint, bool astride )
{
if ( mAttrName.isEmpty() )
return;
setMode( mode );
setSymmetryPoint( symmetryPoint );
setUseSymmetricMode( useSymmetricMode );
setAstride( astride );
// Custom classes are not recalculated
if ( mode == Custom )
return;
@ -831,13 +916,18 @@ void QgsGraduatedSymbolRenderer::updateClasses( QgsVectorLayer *vlayer, Mode mod
QgsDebugMsg( QString( "min %1 // max %2" ).arg( minimum ).arg( maximum ) );
QList<double> breaks;
QList<double> labels;
if ( mode == EqualInterval )
{
breaks = _calcEqualIntervalBreaks( minimum, maximum, nclasses );
breaks = _calcEqualIntervalBreaks( minimum, maximum, nclasses, mUseSymmetricMode, symmetryPoint, astride );
}
else if ( mode == Pretty )
{
breaks = QgsSymbolLayerUtils::prettyBreaks( minimum, maximum, nclasses );
setListForCboPrettyBreaks( _breaksAsStrings( breaks ) );
if ( true == useSymmetricMode )
_makeBreaksSymmetric( breaks, symmetryPoint, astride );
}
else if ( mode == Quantile || mode == Jenks || mode == StdDev )
{
@ -846,20 +936,13 @@ void QgsGraduatedSymbolRenderer::updateClasses( QgsVectorLayer *vlayer, Mode mod
{
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 );
}
breaks = _calcStdDevBreaks( values, nclasses, labels, mUseSymmetricMode, symmetryPoint, astride );
}
else
{
@ -871,7 +954,6 @@ void QgsGraduatedSymbolRenderer::updateClasses( QgsVectorLayer *vlayer, Mode mod
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 )
{
@ -904,6 +986,7 @@ void QgsGraduatedSymbolRenderer::updateClasses( QgsVectorLayer *vlayer, Mode mod
updateColorRamp( nullptr );
}
QgsFeatureRenderer *QgsGraduatedSymbolRenderer::create( QDomElement &element, const QgsReadWriteContext &context )
{
QDomElement symbolsElem = element.firstChildElement( QStringLiteral( "symbols" ) );
@ -989,6 +1072,21 @@ QgsFeatureRenderer *QgsGraduatedSymbolRenderer::create( QDomElement &element, co
r->setMode( Pretty );
}
// symmetric mode
QDomElement symmetricModeElem = element.firstChildElement( QStringLiteral( "symmetricMode" ) );
if ( !symmetricModeElem.isNull() )
{
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 );
}
QDomElement rotationElem = element.firstChildElement( QStringLiteral( "rotation" ) );
if ( !rotationElem.isNull() && !rotationElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
{
@ -1001,7 +1099,6 @@ QgsFeatureRenderer *QgsGraduatedSymbolRenderer::create( QDomElement &element, co
convertSymbolRotation( r->mSourceSymbol.get(), rotationElem.attribute( QStringLiteral( "field" ) ) );
}
}
QDomElement sizeScaleElem = element.firstChildElement( QStringLiteral( "sizescale" ) );
if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
{
@ -1032,7 +1129,6 @@ QgsFeatureRenderer *QgsGraduatedSymbolRenderer::create( QDomElement &element, co
{
r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) );
}
// TODO: symbol levels
return r;
}
@ -1108,6 +1204,25 @@ QDomElement QgsGraduatedSymbolRenderer::save( QDomDocument &doc, const QgsReadWr
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( QStringLiteral( "/" ) );
}
breaks.append( mListForCboPrettyBreaks.at( mListForCboPrettyBreaks.size() - 1 ) );
symmetricModeElem.setAttribute( QStringLiteral( "valueForCboPrettyBreaks" ), breaks );
}
rendererElem.appendChild( symmetricModeElem );
QDomElement rotationElem = doc.createElement( QStringLiteral( "rotation" ) );
rendererElem.appendChild( rotationElem );

View File

@ -222,14 +222,66 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer : public QgsFeatureRenderer
Mode mode() const { return mMode; }
void setMode( Mode mode ) { mMode = mode; }
/**
* get mUseSymmetricMode, which says if we want to classify symmetric around a given value
* \since QGIS 3.2
*/
bool useSymmetricMode() { return mUseSymmetricMode; }
/**
* set mUseSymmetricMode, which says if we want to classify symmetric around a given value
* \since QGIS 3.2
*/
void setUseSymmetricMode( bool useSymmetricMode ) { mUseSymmetricMode = useSymmetricMode; }
/**
* get mSymmetryPoint, the pivot value for symmetric classification
* \since QGIS 3.2
*/
double symmetryPoint() { return mSymmetryPoint; }
/**
* set the pivot point
* \since QGIS 3.2
*/
void setSymmetryPoint( double symmetryPoint ) { mSymmetryPoint = symmetryPoint; }
/**
* get mListForCboPrettyBreaks, which is need to recover this list in saved configuration, or when property window in closed and reopened
* \since QGIS 3.2
*/
QStringList listForCboPrettyBreaks() { return mListForCboPrettyBreaks; }
/**
* set mListForCboPrettyBreaks, which is need to recover this list in saved configuration, or when property window in closed and reopened
* \since QGIS 3.2
*/
void setListForCboPrettyBreaks( QStringList listForCboPrettyBreaks ) { mListForCboPrettyBreaks = listForCboPrettyBreaks; }
/**
* get mAstride, a bool saying if we want to have a central class astride the pivot value
* \since QGIS 3.2
*/
bool astride() { return mAstride; }
/**
* set mAstride, a bool saying if we want to have a central class astride the pivot value
* \since QGIS 3.2
*/
void setAstride( bool astride ) { mAstride = astride; }
/**
* Recalculate classes for a layer
* \param vlayer The layer being rendered (from which data values are calculated)
* \param mode The calculation mode
* \param nclasses The number of classes to calculate (approximate for some modes)
* \since QGIS 2.6
* \param useSymmetricMode A bool indicating if we want to have classes and hence colors ramp symmetric around a value
* \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 3.2
*/
void updateClasses( QgsVectorLayer *vlayer, Mode mode, int nclasses );
void updateClasses( QgsVectorLayer *vlayer, Mode mode, int nclasses, bool useSymmetricMode = false, double symmetryPoint = 0.0, bool astride = false );
/**
* Returns the label format used to generate default classification labels
@ -258,6 +310,10 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer : public QgsFeatureRenderer
* \param attrName attribute to classify
* \param classes number of classes
* \param mode classification mode
* \param useSymmetricMode A bool indicating if we want to have classes and hence colors ramp symmetric around a value
* \param symmetryPoint The value around which the classes will be symmetric if useSymmetricMode is checked
* \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] )
* \param symbol base symbol
* \param ramp color ramp for classes
* \param legendFormat
@ -267,6 +323,10 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer : public QgsFeatureRenderer
const QString &attrName,
int classes,
Mode mode,
bool useSymmetricMode,
double symmetryPoint,
QStringList listForCboPrettyBreaks,
bool astride,
QgsSymbol *symbol SIP_TRANSFER,
QgsColorRamp *ramp SIP_TRANSFER,
const QgsRendererRangeLabelFormat &legendFormat = QgsRendererRangeLabelFormat() );
@ -396,6 +456,10 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer : public QgsFeatureRenderer
QString mAttrName;
QgsRangeList mRanges;
Mode mMode = Custom;
bool mUseSymmetricMode;
double mSymmetryPoint;
QStringList mListForCboPrettyBreaks;
bool mAstride;
std::unique_ptr<QgsSymbol> mSourceSymbol;
std::unique_ptr<QgsColorRamp> mSourceColorRamp;
QgsRendererRangeLabelFormat mLabelFormat;
@ -403,6 +467,7 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer : public QgsFeatureRenderer
std::unique_ptr<QgsExpression> mExpression;
GraduatedMethod mGraduatedMethod = GraduatedColor;
//! attribute index (derived from attribute name in startRender)
int mAttrNum = -1;
bool mCounting = false;

View File

@ -4068,6 +4068,24 @@ QList<double> QgsSymbolLayerUtils::prettyBreaks( double minimum, double maximum,
breaks[breaks.count() - 1] = maximum;
}
// because sometimes when number of classes is big,
// break supposed to be at zero is something like -2.22045e-16
if ( minimum < 0.0 && maximum > 0.0 ) //then there should be a zero somewhere
{
QList<double> breaksMinusZero; // compute difference "each break - 0"
for ( int i = 0; i < breaks.count(); i++ )
{
breaksMinusZero.append( breaks[i] - 0.0 );
}
int posOfMin = 0;
for ( int i = 1; i < breaks.count(); i++ ) // find position of minimal difference
{
if ( std::abs( breaksMinusZero[i] ) < std::abs( breaksMinusZero[i - 1] ) )
posOfMin = i;
}
breaks[posOfMin] = 0.0;
}
return breaks;
}

View File

@ -435,10 +435,7 @@ QgsExpressionContext QgsGraduatedSymbolRendererWidget::createExpressionContext()
QgsGraduatedSymbolRendererWidget::QgsGraduatedSymbolRendererWidget( QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer )
: QgsRendererWidget( layer, style )
{
// try to recognize the previous renderer
// (null renderer means "no previous renderer")
if ( renderer )
@ -513,7 +510,6 @@ QgsGraduatedSymbolRendererWidget::QgsGraduatedSymbolRendererWidget( QgsVectorLay
connect( btnDeleteAllClasses, &QAbstractButton::clicked, this, &QgsGraduatedSymbolRendererWidget::deleteAllClasses );
connect( btnGraduatedAdd, &QAbstractButton::clicked, this, &QgsGraduatedSymbolRendererWidget::addClass );
connect( cbxLinkBoundaries, &QAbstractButton::toggled, this, &QgsGraduatedSymbolRendererWidget::toggleBoundariesLink );
connect( mSizeUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsGraduatedSymbolRendererWidget::mSizeUnitWidget_changed );
connectUpdateHandlers();
@ -563,7 +559,6 @@ QgsFeatureRenderer *QgsGraduatedSymbolRendererWidget::renderer()
}
// Connect/disconnect event handlers which trigger updating renderer
void QgsGraduatedSymbolRendererWidget::connectUpdateHandlers()
{
connect( spinGraduatedClasses, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsGraduatedSymbolRendererWidget::classifyGraduated );
@ -577,10 +572,14 @@ void QgsGraduatedSymbolRendererWidget::connectUpdateHandlers()
connect( mModel, &QgsGraduatedSymbolRendererModel::rowsMoved, this, &QgsGraduatedSymbolRendererWidget::rowsMoved );
connect( mModel, &QAbstractItemModel::dataChanged, this, &QgsGraduatedSymbolRendererWidget::modelDataChanged );
connect( cbxClassifySymmetric, &QAbstractButton::toggled, this, &QgsGraduatedSymbolRendererWidget::classifyGraduated );
connect( cbxAstride, &QAbstractButton::toggled, this, &QgsGraduatedSymbolRendererWidget::classifyGraduated );
connect( cboSymmetryPointForPretty, static_cast<void ( QComboBox::* )( int )>( &QComboBox::activated ), this, &QgsGraduatedSymbolRendererWidget::classifyGraduated );
connect( spinSymmetryPointForOtherMethods, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsGraduatedSymbolRendererWidget::classifyGraduated );
}
// Connect/disconnect event handlers which trigger updating renderer
void QgsGraduatedSymbolRendererWidget::disconnectUpdateHandlers()
{
disconnect( spinGraduatedClasses, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsGraduatedSymbolRendererWidget::classifyGraduated );
@ -594,17 +593,74 @@ void QgsGraduatedSymbolRendererWidget::disconnectUpdateHandlers()
disconnect( mModel, &QgsGraduatedSymbolRendererModel::rowsMoved, this, &QgsGraduatedSymbolRendererWidget::rowsMoved );
disconnect( mModel, &QAbstractItemModel::dataChanged, this, &QgsGraduatedSymbolRendererWidget::modelDataChanged );
disconnect( cbxClassifySymmetric, &QAbstractButton::toggled, this, &QgsGraduatedSymbolRendererWidget::classifyGraduated );
disconnect( cbxAstride, &QAbstractButton::toggled, this, &QgsGraduatedSymbolRendererWidget::classifyGraduated );
disconnect( cboSymmetryPointForPretty, static_cast<void ( QComboBox::* )( int )>( &QComboBox::activated ), this, &QgsGraduatedSymbolRendererWidget::classifyGraduated );
disconnect( spinSymmetryPointForOtherMethods, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsGraduatedSymbolRendererWidget::classifyGraduated );
}
void QgsGraduatedSymbolRendererWidget::updateUiFromRenderer( bool updateCount )
{
disconnectUpdateHandlers();
updateGraduatedSymbolIcon();
spinSymmetryPointForOtherMethods->setShowClearButton( false );
// update UI from the graduated renderer (update combo boxes, view)
if ( mRenderer->mode() < cboGraduatedMode->count() )
{
cboGraduatedMode->setCurrentIndex( mRenderer->mode() );
}
// symmetric classification
if ( cboGraduatedMode->currentIndex() == 0 || cboGraduatedMode->currentIndex() == 3 ) // EqualInterval or StdDev
{
cbxClassifySymmetric->setVisible( true );
cbxAstride->setVisible( true );
cboSymmetryPointForPretty->setVisible( false );
spinSymmetryPointForOtherMethods->setVisible( true );
spinSymmetryPointForOtherMethods->setValue( mRenderer->symmetryPoint() );
}
else if ( cboGraduatedMode->currentIndex() == 4 ) // Pretty
{
cbxClassifySymmetric->setVisible( true );
cbxAstride->setVisible( true );
spinSymmetryPointForOtherMethods->setVisible( false );
cboSymmetryPointForPretty->setVisible( true );
cboSymmetryPointForPretty->clear();
cboSymmetryPointForPretty->addItems( mRenderer->listForCboPrettyBreaks() );
// replace the combobox on the good old value
cboSymmetryPointForPretty->setCurrentText( QString::number( mRenderer->symmetryPoint(), 'f', 2 ) );
}
else // quantile or Jenks
{
cbxClassifySymmetric->setVisible( false );
cbxAstride->setVisible( false );
cboSymmetryPointForPretty->setVisible( false );
spinSymmetryPointForOtherMethods->setVisible( false );
spinSymmetryPointForOtherMethods->setValue( mRenderer->symmetryPoint() );
}
if ( true == mRenderer->useSymmetricMode() )
{
cbxClassifySymmetric->setChecked( true );
spinSymmetryPointForOtherMethods->setEnabled( true );
cbxAstride->setEnabled( true );
cboSymmetryPointForPretty->setEnabled( true );
}
else
{
cbxClassifySymmetric->setChecked( false );
spinSymmetryPointForOtherMethods->setEnabled( false );
cbxAstride->setEnabled( false );
cboSymmetryPointForPretty->setEnabled( false );
}
if ( true == mRenderer->astride() )
cbxAstride->setChecked( true );
else
cbxAstride->setChecked( false );
// Only update class count if different - otherwise typing value gets very messy
int nclasses = mRenderer->ranges().count();
@ -796,7 +852,6 @@ void QgsGraduatedSymbolRendererWidget::applyChangeToSymbol()
void QgsGraduatedSymbolRendererWidget::classifyGraduated()
{
QString attrName = mExpressionWidget->currentField();
int nclasses = spinGraduatedClasses->value();
std::unique_ptr<QgsColorRamp> ramp( btnColorRamp->colorRamp() );
@ -807,16 +862,53 @@ void QgsGraduatedSymbolRendererWidget::classifyGraduated()
}
QgsGraduatedSymbolRenderer::Mode mode;
if ( cboGraduatedMode->currentIndex() == 0 )
bool useSymmetricMode = false;
bool astride = false;
double symmetryPoint = 0.0;
int attrNum = mLayer->fields().lookupField( attrName );
double minimum = mLayer->minimumValue( attrNum ).toDouble();
double maximum = mLayer->maximumValue( attrNum ).toDouble();
spinSymmetryPointForOtherMethods->setMinimum( minimum );
spinSymmetryPointForOtherMethods->setMaximum( maximum );
if ( cboGraduatedMode->currentIndex() == 0 ) // EqualInterval
{
mode = QgsGraduatedSymbolRenderer::EqualInterval;
else if ( cboGraduatedMode->currentIndex() == 2 )
if ( cbxClassifySymmetric->isChecked() )
{
useSymmetricMode = true;
symmetryPoint = spinSymmetryPointForOtherMethods->value();
cbxAstride->isChecked() ? astride = true : astride = false;
}
}
else if ( cboGraduatedMode->currentIndex() == 2 ) // Jenks
{
mode = QgsGraduatedSymbolRenderer::Jenks;
else if ( cboGraduatedMode->currentIndex() == 3 )
}
else if ( cboGraduatedMode->currentIndex() == 3 ) // StdDev
{
mode = QgsGraduatedSymbolRenderer::StdDev;
else if ( cboGraduatedMode->currentIndex() == 4 )
if ( cbxClassifySymmetric->isChecked() )
{
useSymmetricMode = true;
symmetryPoint = spinSymmetryPointForOtherMethods->value();
cbxAstride->isChecked() ? astride = true : astride = false;
}
}
else if ( cboGraduatedMode->currentIndex() == 4 ) // Pretty
{
mode = QgsGraduatedSymbolRenderer::Pretty;
if ( cbxClassifySymmetric->isChecked() )
{
useSymmetricMode = true;
cbxAstride->isChecked() ? astride = true : astride = false;
symmetryPoint = cboSymmetryPointForPretty->currentText().toDouble(); //selected number
}
}
else // default should be quantile for now
mode = QgsGraduatedSymbolRenderer::Quantile;
{
mode = QgsGraduatedSymbolRenderer::Quantile; // Quantile
}
// Jenks is n^2 complexity, warn for big dataset (more than 50k records)
// and give the user the chance to cancel
@ -825,11 +917,12 @@ void QgsGraduatedSymbolRendererWidget::classifyGraduated()
if ( QMessageBox::Cancel == QMessageBox::question( this, tr( "Apply Classification" ), tr( "Natural break classification (Jenks) is O(n2) complexity, your classification may take a long time.\nPress cancel to abort breaks calculation or OK to continue." ), QMessageBox::Cancel, QMessageBox::Ok ) )
return;
}
// create and set new renderer
mRenderer->setClassAttribute( attrName );
mRenderer->setMode( mode );
mRenderer->setUseSymmetricMode( useSymmetricMode );
mRenderer->setSymmetryPoint( symmetryPoint );
mRenderer->setAstride( astride );
if ( methodComboBox->currentIndex() == 0 )
{
@ -846,7 +939,8 @@ void QgsGraduatedSymbolRendererWidget::classifyGraduated()
}
QApplication::setOverrideCursor( Qt::WaitCursor );
mRenderer->updateClasses( mLayer, mode, nclasses );
mRenderer->updateClasses( mLayer, mode, nclasses, useSymmetricMode, symmetryPoint, astride );
if ( methodComboBox->currentIndex() == 1 )
mRenderer->setSymbolSizes( minSizeSpinBox->value(), maxSizeSpinBox->value() );

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>442</width>
<width>952</width>
<height>554</height>
</rect>
</property>
@ -206,7 +206,7 @@ Negative rounds to powers of 10</string>
<property name="value">
<double>1.000000000000000</double>
</property>
<property name="showClearButton">
<property name="showClearButton" stdset="0">
<bool>false</bool>
</property>
</widget>
@ -238,7 +238,7 @@ Negative rounds to powers of 10</string>
<property name="value">
<double>10.000000000000000</double>
</property>
<property name="showClearButton">
<property name="showClearButton" stdset="0">
<bool>false</bool>
</property>
</widget>
@ -316,6 +316,9 @@ Negative rounds to powers of 10</string>
</item>
<item>
<widget class="QComboBox" name="cboGraduatedMode">
<property name="editable">
<bool>false</bool>
</property>
<item>
<property name="text">
<string>Equal Interval</string>
@ -343,6 +346,9 @@ Negative rounds to powers of 10</string>
</item>
</widget>
</item>
<item>
<widget class="QWidget" name="widget" native="true"/>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
@ -387,6 +393,80 @@ Negative rounds to powers of 10</string>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="cbxClassifySymmetric">
<property name="enabled">
<bool>true</bool>
</property>
<property name="visible">
<bool>true</bool>
</property>
<property name="text">
<string>Symmetric around:</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="tristate">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QgsDoubleSpinBox" name="spinSymmetryPointForOtherMethods">
<property name="specialValueText">
<string/>
</property>
<property name="showClearButton" stdset="0">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cboSymmetryPointForPretty"/>
</item>
<item>
<widget class="QCheckBox" name="cbxAstride">
<property name="text">
<string>with a class astride that value</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>